From acdd08c96649b9162f27be19d9a85f3f0bb8b3db Mon Sep 17 00:00:00 2001 From: MBmasher Date: Sun, 8 Aug 2021 23:56:03 +1000 Subject: [PATCH 001/161] Add Flashlight skill --- .../Difficulty/OsuDifficultyAttributes.cs | 1 + .../Difficulty/OsuDifficultyCalculator.cs | 5 +- .../Difficulty/OsuPerformanceCalculator.cs | 51 ++++++++++---- .../Difficulty/Skills/Flashlight.cs | 67 +++++++++++++++++++ .../Difficulty/Skills/OsuStrainSkill.cs | 2 + 5 files changed, 111 insertions(+), 15 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 141138c125..1e870dac68 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public double AimStrain { get; set; } public double SpeedStrain { get; set; } + public double FlashlightStrain { get; set; } public double ApproachRate { get; set; } public double OverallDifficulty { get; set; } public int HitCircleCount { get; set; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index e47f82fb39..b0dd4dc9b0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -34,6 +34,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; + double flashlightRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier; double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2; HitWindows hitWindows = new OsuHitWindows(); @@ -56,6 +57,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty Mods = mods, AimStrain = aimRating, SpeedStrain = speedRating, + FlashlightStrain = flashlightRating, ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5, OverallDifficulty = (80 - hitWindowGreat) / 6, MaxCombo = maxCombo, @@ -82,7 +84,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) => new Skill[] { new Aim(mods), - new Speed(mods) + new Speed(mods), + new Flashlight(mods) }; protected override Mod[] DifficultyAdjustmentMods => new Mod[] diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index e6ab978dfb..d409eae9af 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -52,11 +52,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimValue = computeAimValue(); double speedValue = computeSpeedValue(); double accuracyValue = computeAccuracyValue(); + double flashlightValue = computeFlashlightValue(); double totalValue = Math.Pow( Math.Pow(aimValue, 1.1) + Math.Pow(speedValue, 1.1) + - Math.Pow(accuracyValue, 1.1), 1.0 / 1.1 + Math.Pow(accuracyValue, 1.1) + + Math.Pow(flashlightValue, 1.1), 1.0 / 1.1 ) * multiplier; if (categoryRatings != null) @@ -64,6 +66,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty categoryRatings.Add("Aim", aimValue); categoryRatings.Add("Speed", speedValue); categoryRatings.Add("Accuracy", accuracyValue); + categoryRatings.Add("Flashlight", flashlightValue); categoryRatings.Add("OD", Attributes.OverallDifficulty); categoryRatings.Add("AR", Attributes.ApproachRate); categoryRatings.Add("Max Combo", Attributes.MaxCombo); @@ -109,19 +112,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(h => h is OsuModHidden)) aimValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate); - double flashlightBonus = 1.0; - - if (mods.Any(h => h is OsuModFlashlight)) - { - // Apply object-based bonus for flashlight. - flashlightBonus = 1.0 + 0.35 * Math.Min(1.0, totalHits / 200.0) + - (totalHits > 200 - ? 0.3 * Math.Min(1.0, (totalHits - 200) / 300.0) + - (totalHits > 500 ? (totalHits - 500) / 1200.0 : 0.0) - : 0.0); - } - - aimValue *= Math.Max(flashlightBonus, approachRateBonus); + aimValue *= approachRateBonus; // Scale the aim value with accuracy _slightly_ aimValue *= 0.5 + accuracy / 2.0; @@ -197,6 +188,38 @@ namespace osu.Game.Rulesets.Osu.Difficulty return accuracyValue; } + private double computeFlashlightValue() + { + double flashlightValue = 0.0; + + if (mods.Any(h => h is OsuModFlashlight)) { + flashlightValue = Math.Pow(Attributes.FlashlightStrain, 2.0) * 25.0; + + // Add an additional bonus for HDFL. + if (mods.Any(h => h is OsuModHidden)) + flashlightValue *= 1.2; + + // Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses. + if (countMiss > 0) + flashlightValue *= 0.97 * Math.Pow(1 - Math.Pow((double)countMiss / totalHits, 0.775), Math.Pow(countMiss, .875)); + + // Combo scaling + if (Attributes.MaxCombo > 0) + flashlightValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); + + // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. + flashlightValue *= 0.5 + 0.15 * Math.Min(1.0, totalHits / 200.0) + + (totalHits > 200 ? 0.35 * Math.Min(1.0, (totalHits - 200) / 600.0) : 0.0); + + // Scale the aim value with accuracy _slightly_ + flashlightValue *= 0.5 + accuracy / 2.0; + // It is important to also consider accuracy difficulty when doing that + flashlightValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500; + } + + return flashlightValue; + } + private int totalHits => countGreat + countOk + countMeh + countMiss; private int totalSuccessfulHits => countGreat + countOk + countMeh; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs new file mode 100644 index 0000000000..b48e6e30c0 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.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 osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; +using osu.Game.Rulesets.Osu.Objects; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Difficulty.Skills +{ + /// + /// Represents the skill required to memorise and hit every object in a map with the Flashlight mod enabled. + /// + public class Flashlight : OsuStrainSkill + { + public Flashlight(Mod[] mods) + : base(mods) + { + } + + protected override double SkillMultiplier => 0.065; + protected override double StrainDecayBase => 0.15; + protected override double DecayWeight => 1.0; + + protected override double StrainValueOf(DifficultyHitObject current) + { + if (current.BaseObject is Spinner) + return 0; + + var osuCurrent = (OsuDifficultyHitObject)current; + var osuHitObject = (OsuHitObject)(osuCurrent.BaseObject); + + double scalingFactor = 52.0 / osuHitObject.Radius; + double smallDistNerf = 1.0; + + double result = 0.0; + + if (Previous.Count > 0) + { + double cumulativeStrainTime = 0.0; + + for (int i = 0; i < Previous.Count; i++) { + var osuPrevious = (OsuDifficultyHitObject)Previous[i]; + var osuPreviousHitObject = (OsuHitObject)(osuPrevious.BaseObject); + + if (!(osuPrevious.BaseObject is Spinner)) { + double JumpDistance = (osuHitObject.StackedPosition - osuPreviousHitObject.EndPosition).Length; + + cumulativeStrainTime += osuPrevious.StrainTime; + + // We want to nerf objects that can be easily seen within the Flashlight circle radius. + if (i == 0 && JumpDistance < 50.0) { + smallDistNerf = JumpDistance / 50.0; + } + + result += Math.Pow(0.8, i) * scalingFactor * JumpDistance / cumulativeStrainTime; + } + } + } + + return Math.Pow(smallDistNerf * result, 2.5); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index e47edc37cc..f74298cdca 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -28,6 +28,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// protected virtual double DifficultyMultiplier => 1.06; + protected override int HistoryLength => 10; // Look back for 10 notes is added for the sake of flashlight calculations. + protected OsuStrainSkill(Mod[] mods) : base(mods) { From 6b1a4a53d44d980c28b510996269fe9f3742f270 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Mon, 9 Aug 2021 08:31:28 +1000 Subject: [PATCH 002/161] Cleanup of code --- .../Difficulty/OsuPerformanceCalculator.cs | 6 +++--- .../Difficulty/Skills/Flashlight.cs | 12 +++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index d409eae9af..3634374f50 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty Math.Pow( Math.Pow(aimValue, 1.1) + Math.Pow(speedValue, 1.1) + - Math.Pow(accuracyValue, 1.1) + + Math.Pow(accuracyValue, 1.1) + Math.Pow(flashlightValue, 1.1), 1.0 / 1.1 ) * multiplier; @@ -194,7 +194,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(h => h is OsuModFlashlight)) { flashlightValue = Math.Pow(Attributes.FlashlightStrain, 2.0) * 25.0; - + // Add an additional bonus for HDFL. if (mods.Any(h => h is OsuModHidden)) flashlightValue *= 1.2; @@ -205,7 +205,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Combo scaling if (Attributes.MaxCombo > 0) - flashlightValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); + flashlightValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. flashlightValue *= 0.5 + 0.15 * Math.Min(1.0, totalHits / 200.0) + diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index b48e6e30c0..fd771ab768 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -2,12 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; -using osuTK; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { @@ -45,18 +43,18 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills for (int i = 0; i < Previous.Count; i++) { var osuPrevious = (OsuDifficultyHitObject)Previous[i]; var osuPreviousHitObject = (OsuHitObject)(osuPrevious.BaseObject); - + if (!(osuPrevious.BaseObject is Spinner)) { - double JumpDistance = (osuHitObject.StackedPosition - osuPreviousHitObject.EndPosition).Length; + double jumpDistance = (osuHitObject.StackedPosition - osuPreviousHitObject.EndPosition).Length; cumulativeStrainTime += osuPrevious.StrainTime; // We want to nerf objects that can be easily seen within the Flashlight circle radius. - if (i == 0 && JumpDistance < 50.0) { - smallDistNerf = JumpDistance / 50.0; + if (i == 0 && jumpDistance < 50.0) { + smallDistNerf = jumpDistance / 50.0; } - result += Math.Pow(0.8, i) * scalingFactor * JumpDistance / cumulativeStrainTime; + result += Math.Pow(0.8, i) * scalingFactor * jumpDistance / cumulativeStrainTime; } } } From f4ceb170642f802a2420b7e39d9b6887292ad270 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Tue, 10 Aug 2021 16:06:20 +1000 Subject: [PATCH 003/161] Cleanup of code --- .../Difficulty/OsuPerformanceCalculator.cs | 3 ++- osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 3634374f50..267e332372 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -192,7 +192,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty { double flashlightValue = 0.0; - if (mods.Any(h => h is OsuModFlashlight)) { + if (mods.Any(h => h is OsuModFlashlight)) + { flashlightValue = Math.Pow(Attributes.FlashlightStrain, 2.0) * 25.0; // Add an additional bonus for HDFL. diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index fd771ab768..b8a96b3310 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -40,19 +40,20 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { double cumulativeStrainTime = 0.0; - for (int i = 0; i < Previous.Count; i++) { + for (int i = 0; i < Previous.Count; i++) + { var osuPrevious = (OsuDifficultyHitObject)Previous[i]; var osuPreviousHitObject = (OsuHitObject)(osuPrevious.BaseObject); - if (!(osuPrevious.BaseObject is Spinner)) { + if (!(osuPrevious.BaseObject is Spinner)) + { double jumpDistance = (osuHitObject.StackedPosition - osuPreviousHitObject.EndPosition).Length; cumulativeStrainTime += osuPrevious.StrainTime; // We want to nerf objects that can be easily seen within the Flashlight circle radius. - if (i == 0 && jumpDistance < 50.0) { + if (i == 0 && jumpDistance < 50.0) smallDistNerf = jumpDistance / 50.0; - } result += Math.Pow(0.8, i) * scalingFactor * jumpDistance / cumulativeStrainTime; } From cee69eaad0c50c35031e74c59b99db52793e926c Mon Sep 17 00:00:00 2001 From: MBmasher Date: Wed, 11 Aug 2021 06:14:38 +1000 Subject: [PATCH 004/161] Add a nerf to FL for TD plays --- .../Difficulty/OsuPerformanceCalculator.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 267e332372..2d4e4cf551 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -194,7 +194,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(h => h is OsuModFlashlight)) { - flashlightValue = Math.Pow(Attributes.FlashlightStrain, 2.0) * 25.0; + double rawFlashlight = Attributes.FlashlightStrain; + + if (mods.Any(m => m is OsuModTouchDevice)) + rawFlashlight = Math.Pow(rawFlashlight, 0.8); + + flashlightValue = Math.Pow(rawFlashlight, 2.0) * 25.0; // Add an additional bonus for HDFL. if (mods.Any(h => h is OsuModHidden)) From b1d25346a2e646200c759f1763f6b1da7367bfa9 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Wed, 11 Aug 2021 13:30:40 +1000 Subject: [PATCH 005/161] Move HistoryLength override from OsuStrainSkill to Flashlight --- osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs | 1 + osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index b8a96b3310..dc60ab4041 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -22,6 +22,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double SkillMultiplier => 0.065; protected override double StrainDecayBase => 0.15; protected override double DecayWeight => 1.0; + protected override int HistoryLength => 10; // Look back for 10 notes is added for the sake of flashlight calculations. protected override double StrainValueOf(DifficultyHitObject current) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index f74298cdca..e47edc37cc 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -28,8 +28,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// protected virtual double DifficultyMultiplier => 1.06; - protected override int HistoryLength => 10; // Look back for 10 notes is added for the sake of flashlight calculations. - protected OsuStrainSkill(Mod[] mods) : base(mods) { From 1cadcb43d958d3e00e4941eff674b321b392db43 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Wed, 11 Aug 2021 15:54:30 +1000 Subject: [PATCH 006/161] Apply nerf to Flashlight skill on high star maps --- 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 dc60ab4041..d225486cc8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { } - protected override double SkillMultiplier => 0.065; + protected override double SkillMultiplier => 0.13; protected override double StrainDecayBase => 0.15; protected override double DecayWeight => 1.0; protected override int HistoryLength => 10; // Look back for 10 notes is added for the sake of flashlight calculations. @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills } } - return Math.Pow(smallDistNerf * result, 2.5); + return Math.Pow(smallDistNerf * result, 2.0); } } } From 27918583e1143a2b8e717d9824998c0a28848ec4 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Wed, 11 Aug 2021 15:55:13 +1000 Subject: [PATCH 007/161] Increase the multiplier when hidden is applied on the Flashlight skill --- 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 2d4e4cf551..2ca5145c6a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -203,7 +203,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // Add an additional bonus for HDFL. if (mods.Any(h => h is OsuModHidden)) - flashlightValue *= 1.2; + flashlightValue *= 1.3; // Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses. if (countMiss > 0) From b06226e7385cbae56dce1729594003f5a5502cd4 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Thu, 12 Aug 2021 09:54:25 +1000 Subject: [PATCH 008/161] Change comments --- .../Difficulty/OsuPerformanceCalculator.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 2ca5145c6a..2c8ee93819 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); // Custom multipliers for NoFail and SpunOut. - 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.12; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. if (mods.Any(m => m is OsuModNoFail)) multiplier *= Math.Max(0.90, 1.0 - 0.02 * countMiss); @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimValue = Math.Pow(5.0 * Math.Max(1.0, rawAim / 0.0675) - 4.0, 3.0) / 100000.0; - // Longer maps are worth more + // Longer maps are worth more. double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (countMiss > 0) aimValue *= 0.97 * Math.Pow(1 - Math.Pow((double)countMiss / totalHits, 0.775), countMiss); - // Combo scaling + // Combo scaling. if (Attributes.MaxCombo > 0) aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); @@ -114,9 +114,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty aimValue *= approachRateBonus; - // Scale the aim value with accuracy _slightly_ + // Scale the aim value with accuracy _slightly_. aimValue *= 0.5 + accuracy / 2.0; - // It is important to also consider accuracy difficulty when doing that + // It is important to also consider accuracy difficulty when doing that. aimValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500; return aimValue; @@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { double speedValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.SpeedStrain / 0.0675) - 4.0, 3.0) / 100000.0; - // Longer maps are worth more + // Longer maps are worth more. double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); speedValue *= lengthBonus; @@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (countMiss > 0) speedValue *= 0.97 * Math.Pow(1 - Math.Pow((double)countMiss / totalHits, 0.775), Math.Pow(countMiss, .875)); - // Combo scaling + // Combo scaling. if (Attributes.MaxCombo > 0) speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); @@ -150,7 +150,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModHidden)) speedValue *= 1.0 + 0.04 * (12.0 - Attributes.ApproachRate); - // Scale the speed value with accuracy and OD + // Scale the speed value with accuracy and OD. speedValue *= (0.95 + Math.Pow(Attributes.OverallDifficulty, 2) / 750) * Math.Pow(accuracy, (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); @@ -160,7 +160,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeAccuracyValue() { - // This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window + // This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window. double betterAccuracyPercentage; int amountHitObjectsWithAccuracy = Attributes.HitCircleCount; @@ -169,15 +169,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty else betterAccuracyPercentage = 0; - // It is possible to reach a negative accuracy with this formula. Cap it at zero - zero points + // It is possible to reach a negative accuracy with this formula. Cap it at zero - zero points. if (betterAccuracyPercentage < 0) betterAccuracyPercentage = 0; // Lots of arbitrary values from testing. - // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution + // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution. double accuracyValue = Math.Pow(1.52163, Attributes.OverallDifficulty) * Math.Pow(betterAccuracyPercentage, 24) * 2.83; - // Bonus for many hitcircles - it's harder to keep good accuracy up for longer + // Bonus for many hitcircles - it's harder to keep good accuracy up for longer. accuracyValue *= Math.Min(1.15, Math.Pow(amountHitObjectsWithAccuracy / 1000.0, 0.3)); if (mods.Any(m => m is OsuModHidden)) @@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (countMiss > 0) flashlightValue *= 0.97 * Math.Pow(1 - Math.Pow((double)countMiss / totalHits, 0.775), Math.Pow(countMiss, .875)); - // Combo scaling + // Combo scaling. if (Attributes.MaxCombo > 0) flashlightValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); @@ -217,9 +217,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty flashlightValue *= 0.5 + 0.15 * Math.Min(1.0, totalHits / 200.0) + (totalHits > 200 ? 0.35 * Math.Min(1.0, (totalHits - 200) / 600.0) : 0.0); - // Scale the aim value with accuracy _slightly_ + // Scale the flashlight value with accuracy _slightly_. flashlightValue *= 0.5 + accuracy / 2.0; - // It is important to also consider accuracy difficulty when doing that + // It is important to also consider accuracy difficulty when doing that. flashlightValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500; } From eaa0d383158facbf8b779b17010ba9c8b0fcd00b Mon Sep 17 00:00:00 2001 From: MBmasher Date: Thu, 12 Aug 2021 10:00:24 +1000 Subject: [PATCH 009/161] Add a buff to short maps for Flashlight skill --- 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 2c8ee93819..ad7376a044 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -214,8 +214,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty flashlightValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. - flashlightValue *= 0.5 + 0.15 * Math.Min(1.0, totalHits / 200.0) + - (totalHits > 200 ? 0.35 * Math.Min(1.0, (totalHits - 200) / 600.0) : 0.0); + flashlightValue *= 0.7 + 0.1 * Math.Min(1.0, totalHits / 200.0) + + (totalHits > 200 ? 0.2 * Math.Min(1.0, (totalHits - 200) / 200.0) : 0.0); // Scale the flashlight value with accuracy _slightly_. flashlightValue *= 0.5 + accuracy / 2.0; From 7188a3268fbdfc24fb66b8aa6783ca151833c72d Mon Sep 17 00:00:00 2001 From: MBmasher Date: Tue, 24 Aug 2021 14:01:54 +1000 Subject: [PATCH 010/161] Apply a nerf to stacks for Flashlight skill --- 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 d225486cc8..f048142b56 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { } - protected override double SkillMultiplier => 0.13; + protected override double SkillMultiplier => 0.15; protected override double StrainDecayBase => 0.15; protected override double DecayWeight => 1.0; protected override int HistoryLength => 10; // Look back for 10 notes is added for the sake of flashlight calculations. @@ -53,10 +53,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills cumulativeStrainTime += osuPrevious.StrainTime; // We want to nerf objects that can be easily seen within the Flashlight circle radius. - if (i == 0 && jumpDistance < 50.0) - smallDistNerf = jumpDistance / 50.0; + if (i == 0) + smallDistNerf = Math.Min(1.0, jumpDistance / 50.0); - result += Math.Pow(0.8, i) * scalingFactor * jumpDistance / cumulativeStrainTime; + // We also want to nerf stacks so that only the first object of the stack is accounted for. + double stackNerf = Math.Min(1.0, osuPrevious.JumpDistance * scalingFactor / 50.0); + + result += Math.Pow(0.8, i) * stackNerf * scalingFactor * jumpDistance / cumulativeStrainTime; } } } From c91feb29684c3a80b9af50be9ba63a53f3754b91 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Wed, 25 Aug 2021 11:18:21 +1000 Subject: [PATCH 011/161] Fix multiplying instead of dividing by scalingFactor --- 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 f048142b56..f6760235b4 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -54,10 +54,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills // We want to nerf objects that can be easily seen within the Flashlight circle radius. if (i == 0) - smallDistNerf = Math.Min(1.0, jumpDistance / 50.0); + smallDistNerf = Math.Min(1.0, jumpDistance / 75.0); // We also want to nerf stacks so that only the first object of the stack is accounted for. - double stackNerf = Math.Min(1.0, osuPrevious.JumpDistance * scalingFactor / 50.0); + double stackNerf = Math.Min(1.0, (osuPrevious.JumpDistance / scalingFactor) / 25.0); result += Math.Pow(0.8, i) * stackNerf * scalingFactor * jumpDistance / cumulativeStrainTime; } From 738ce0f6894953445cd9287ff00fbdde8a0454c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Sep 2021 19:34:57 +0900 Subject: [PATCH 012/161] Fix repeat arrows being hidden beneath head circles in legacy skins Aims to make minimal changes to `DrawableSlider` itself. I'm not super happy about the slider ball being moved above the head circle, but it *is* what people are used to so no one except for me is going to complain. Supersedes and closes https://github.com/ppy/osu/pull/14561. --- .../Objects/Drawables/DrawableSlider.cs | 11 ++++- .../Objects/Drawables/DrawableSliderHead.cs | 2 +- .../Objects/Drawables/DrawableSliderRepeat.cs | 2 +- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 40 +++++++---------- .../Skinning/Legacy/LegacyReverseArrow.cs | 44 +++++++++++++++++++ .../Legacy/LegacySliderHeadHitCircle.cs | 30 +++++++++++++ .../Legacy/OsuLegacySkinTransformer.cs | 8 +++- 7 files changed, 110 insertions(+), 27 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 0bec33bf77..0e1d1043e3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -32,6 +32,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public SliderBall Ball { get; private set; } public SkinnableDrawable Body { get; private set; } + /// + /// 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. + /// + public Container OverlayElementContainer { get; private set; } + public override bool DisplayResult => !HitObject.OnlyJudgeNestedObjects; [CanBeNull] @@ -65,6 +71,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables tailContainer = new Container { RelativeSizeAxes = Axes.Both }, tickContainer = new Container { RelativeSizeAxes = Axes.Both }, repeatContainer = new Container { RelativeSizeAxes = Axes.Both }, + headContainer = new Container { RelativeSizeAxes = Axes.Both }, + OverlayElementContainer = new Container { RelativeSizeAxes = Axes.Both, }, Ball = new SliderBall(this) { GetInitialHitAction = () => HeadCircle.HitAction, @@ -72,7 +80,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables AlwaysPresent = true, Alpha = 0 }, - headContainer = new Container { RelativeSizeAxes = Axes.Both }, slidingSample = new PausableSkinnableSound { Looping = true } }; @@ -179,6 +186,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables tailContainer.Clear(false); repeatContainer.Clear(false); tickContainer.Clear(false); + + OverlayElementContainer.Clear(); } protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index 01c0d988ee..2b026e6840 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables [CanBeNull] public Slider Slider => DrawableSlider?.HitObject; - protected DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; + public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; public override bool DisplayResult => HitObject?.JudgeAsNormalHitCircle ?? base.DisplayResult; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 4a2a18ffd6..673211ac6c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables [CanBeNull] public Slider Slider => DrawableSlider?.HitObject; - protected DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; + public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; private double animDuration; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 7a210324d7..3afd814174 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); } - private Container circleSprites; private Drawable hitCircleSprite; - private Drawable hitCircleOverlay; + + protected Drawable HitCircleOverlay { get; private set; } private SkinnableSpriteText hitCircleText; @@ -70,28 +70,19 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy // expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin). Texture overlayTexture = getTextureWithFallback("overlay"); - InternalChildren = new Drawable[] + InternalChildren = new[] { - circleSprites = new Container + hitCircleSprite = new KiaiFlashingSprite { + Texture = baseTexture, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + HitCircleOverlay = new KiaiFlashingSprite + { + Texture = overlayTexture, Anchor = Anchor.Centre, Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Children = new[] - { - hitCircleSprite = new KiaiFlashingSprite - { - Texture = baseTexture, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - hitCircleOverlay = new KiaiFlashingSprite - { - Texture = overlayTexture, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - } }, }; @@ -111,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy bool overlayAboveNumber = skin.GetConfig(OsuSkinConfiguration.HitCircleOverlayAboveNumber)?.Value ?? true; if (overlayAboveNumber) - AddInternal(hitCircleOverlay.CreateProxy()); + ChangeInternalChildDepth(HitCircleOverlay, float.MinValue); accentColour.BindTo(drawableObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); @@ -153,8 +144,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (state) { case ArmedState.Hit: - circleSprites.FadeOut(legacy_fade_duration, Easing.Out); - circleSprites.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); + hitCircleSprite.FadeOut(legacy_fade_duration, Easing.Out); + hitCircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); + + HitCircleOverlay.FadeOut(legacy_fade_duration, Easing.Out); + HitCircleOverlay.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); if (hasNumber) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs new file mode 100644 index 0000000000..b6956693b6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.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.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Osu.Skinning.Legacy +{ + public class LegacyReverseArrow : CompositeDrawable + { + private ISkin skin { get; set; } + + [Resolved(canBeNull: true)] + private DrawableHitObject drawableHitObject { get; set; } + + public LegacyReverseArrow(ISkin skin) + { + this.skin = skin; + } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + string lookupName = new OsuSkinComponent(OsuSkinComponents.ReverseArrow).LookupName; + + InternalChild = skin.GetAnimation(lookupName, true, true) ?? Drawable.Empty(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // see logic in LegacySliderHeadHitCircle. + (drawableHitObject as DrawableSliderRepeat)?.DrawableSlider + .OverlayElementContainer.Add(CreateProxy()); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs new file mode 100644 index 0000000000..83ebdafa50 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.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 osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Skinning.Legacy +{ + public class LegacySliderHeadHitCircle : LegacyMainCirclePiece + { + [Resolved(canBeNull: true)] + private DrawableHitObject drawableHitObject { get; set; } + + public LegacySliderHeadHitCircle() + : base("sliderstartcircle") + { + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // see logic in LegacyReverseArrow. + (drawableHitObject as DrawableSliderHead)?.DrawableSlider + .OverlayElementContainer.Add(HitCircleOverlay.CreateProxy().With(d => d.Depth = float.MinValue)); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 41b0a88f11..8df8001d42 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -67,7 +67,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy case OsuSkinComponents.SliderHeadHitCircle: if (hasHitCircle.Value) - return new LegacyMainCirclePiece("sliderstartcircle"); + return new LegacySliderHeadHitCircle(); + + return null; + + case OsuSkinComponents.ReverseArrow: + if (hasHitCircle.Value) + return new LegacyReverseArrow(this); return null; From bf0150bab4670d05e3112e24db50d29ac1c814ce Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Thu, 9 Sep 2021 16:21:51 -0400 Subject: [PATCH 013/161] Clear UR bar display on keyboard input --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 89f61785e8..5998c1b494 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -10,7 +10,9 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Bindings; using osu.Game.Graphics; +using osu.Game.Input.Bindings; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; @@ -18,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { - public class BarHitErrorMeter : HitErrorMeter + public class BarHitErrorMeter : HitErrorMeter, IKeyBindingHandler { private const int arrow_move_duration = 400; @@ -279,5 +281,22 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration).Expire(); } } + + public bool OnPressed(GlobalAction action) + { + switch (action) + { + case GlobalAction.SeekReplayBackward: + case GlobalAction.SeekReplayForward: + judgementsContainer.Clear(true); + return false; + } + + return false; + } + + public void OnReleased(GlobalAction action) + { + } } } From bde092f816c3e9570d54e7484baca3877ef0a7d1 Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Thu, 9 Sep 2021 20:08:16 -0400 Subject: [PATCH 014/161] Clear UR bar display on seek with mouse --- .../Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 12 +++++++++++- osu.Game/Screens/Play/SongProgress.cs | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 5998c1b494..2854fabbae 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.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; +using osu.Framework.Testing; using osu.Game.Graphics; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Judgements; @@ -143,6 +144,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters arrow.Alpha = 0; arrow.Delay(200).FadeInFromZero(600); + + var progressBar = Parent.ChildrenOfType().FirstOrDefault(); + if (progressBar != null) + progressBar.Bar.OnSeek += _ => handleSeek(); } private void createColourBars(OsuColour colours) @@ -282,13 +287,18 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } + private void handleSeek() + { + judgementsContainer.Clear(true); + } + public bool OnPressed(GlobalAction action) { switch (action) { case GlobalAction.SeekReplayBackward: case GlobalAction.SeekReplayForward: - judgementsContainer.Clear(true); + handleSeek(); return false; } diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index b27a9c5f5d..dff2dcc86b 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -35,6 +35,8 @@ namespace osu.Game.Screens.Play private readonly SongProgressGraph graph; private readonly SongProgressInfo info; + public SongProgressBar Bar => bar; + public Action RequestSeek; /// From 0dc31a476f9ccf0eafdf7c1f16fe96da287977bb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 13 Sep 2021 16:39:05 +0900 Subject: [PATCH 015/161] Invert condition to reduce nesting --- .../Difficulty/OsuPerformanceCalculator.cs | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index ad7376a044..f9a3423eab 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -190,38 +190,36 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeFlashlightValue() { - double flashlightValue = 0.0; + if (!mods.Any(h => h is OsuModFlashlight)) + return 0.0; - if (mods.Any(h => h is OsuModFlashlight)) - { - double rawFlashlight = Attributes.FlashlightStrain; + double rawFlashlight = Attributes.FlashlightStrain; - if (mods.Any(m => m is OsuModTouchDevice)) - rawFlashlight = Math.Pow(rawFlashlight, 0.8); + if (mods.Any(m => m is OsuModTouchDevice)) + rawFlashlight = Math.Pow(rawFlashlight, 0.8); - flashlightValue = Math.Pow(rawFlashlight, 2.0) * 25.0; + double flashlightValue = Math.Pow(rawFlashlight, 2.0) * 25.0; - // Add an additional bonus for HDFL. - if (mods.Any(h => h is OsuModHidden)) - flashlightValue *= 1.3; + // Add an additional bonus for HDFL. + if (mods.Any(h => h is OsuModHidden)) + flashlightValue *= 1.3; - // Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses. - if (countMiss > 0) - flashlightValue *= 0.97 * Math.Pow(1 - Math.Pow((double)countMiss / totalHits, 0.775), Math.Pow(countMiss, .875)); + // Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses. + if (countMiss > 0) + flashlightValue *= 0.97 * Math.Pow(1 - Math.Pow((double)countMiss / totalHits, 0.775), Math.Pow(countMiss, .875)); - // Combo scaling. - if (Attributes.MaxCombo > 0) - flashlightValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); + // Combo scaling. + if (Attributes.MaxCombo > 0) + flashlightValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0); - // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. - flashlightValue *= 0.7 + 0.1 * Math.Min(1.0, totalHits / 200.0) + - (totalHits > 200 ? 0.2 * Math.Min(1.0, (totalHits - 200) / 200.0) : 0.0); + // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. + flashlightValue *= 0.7 + 0.1 * Math.Min(1.0, totalHits / 200.0) + + (totalHits > 200 ? 0.2 * Math.Min(1.0, (totalHits - 200) / 200.0) : 0.0); - // Scale the flashlight value with accuracy _slightly_. - flashlightValue *= 0.5 + accuracy / 2.0; - // It is important to also consider accuracy difficulty when doing that. - flashlightValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500; - } + // Scale the flashlight value with accuracy _slightly_. + flashlightValue *= 0.5 + accuracy / 2.0; + // It is important to also consider accuracy difficulty when doing that. + flashlightValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500; return flashlightValue; } From aa71e3f3d4e6206798a563c3e4af1291e6626323 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Sep 2021 18:32:48 +0900 Subject: [PATCH 016/161] Update nested game tests in line with framework changes --- .../TestSceneOsuGame.cs | 6 ++---- .../osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs | 6 ++---- .../TestSceneOsuGame.cs | 6 ++---- .../osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs | 6 ++---- osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs | 6 ++---- osu.Game/Tests/Visual/OsuGameTestScene.cs | 5 +---- 6 files changed, 11 insertions(+), 24 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 9c512a01ea..536fdfc6df 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 @@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.EmptyFreeform.Tests [BackgroundDependencyLoader] private void load(GameHost host, OsuGameBase gameBase) { - OsuGame game = new OsuGame(); - game.SetHost(host); - Children = new Drawable[] { new Box @@ -25,8 +22,9 @@ namespace osu.Game.Rulesets.EmptyFreeform.Tests RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - game }; + + AddGame(new OsuGame()); } } } 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 270d906b01..3cdf44e6f1 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 @@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.Pippidon.Tests [BackgroundDependencyLoader] private void load(GameHost host, OsuGameBase gameBase) { - OsuGame game = new OsuGame(); - game.SetHost(host); - Children = new Drawable[] { new Box @@ -25,8 +22,9 @@ namespace osu.Game.Rulesets.Pippidon.Tests RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - game }; + + AddGame(new OsuGame()); } } } 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 aed6abb6bf..4d3f5086d9 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 @@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.EmptyScrolling.Tests [BackgroundDependencyLoader] private void load(GameHost host, OsuGameBase gameBase) { - OsuGame game = new OsuGame(); - game.SetHost(host); - Children = new Drawable[] { new Box @@ -25,8 +22,9 @@ namespace osu.Game.Rulesets.EmptyScrolling.Tests RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - game }; + + AddGame(new OsuGame()); } } } 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 270d906b01..3cdf44e6f1 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 @@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.Pippidon.Tests [BackgroundDependencyLoader] private void load(GameHost host, OsuGameBase gameBase) { - OsuGame game = new OsuGame(); - game.SetHost(host); - Children = new Drawable[] { new Box @@ -25,8 +22,9 @@ namespace osu.Game.Rulesets.Pippidon.Tests RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - game }; + + AddGame(new OsuGame()); } } } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index b8232837b5..e38b1353d9 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -97,9 +97,6 @@ namespace osu.Game.Tests.Visual.Navigation { AddStep("create game", () => { - game = new OsuGame(); - game.SetHost(host); - Children = new Drawable[] { new Box @@ -107,8 +104,9 @@ namespace osu.Game.Tests.Visual.Navigation RelativeSizeAxes = Axes.Both, Colour = Color4.Black, }, - game }; + + AddGame(game = new OsuGame()); }); AddUntilStep("wait for load", () => game.IsLoaded); diff --git a/osu.Game/Tests/Visual/OsuGameTestScene.cs b/osu.Game/Tests/Visual/OsuGameTestScene.cs index f38aaa9358..b56c8a15af 100644 --- a/osu.Game/Tests/Visual/OsuGameTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGameTestScene.cs @@ -81,10 +81,7 @@ namespace osu.Game.Tests.Visual protected void CreateGame() { - Game = new TestOsuGame(LocalStorage, API); - Game.SetHost(host); - - Add(Game); + AddGame(Game = new TestOsuGame(LocalStorage, API)); } protected void PushAndConfirm(Func newScreen) From 24ae530a8087d35119a9b4533571cf4e6dbf9112 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Sep 2021 18:32:58 +0900 Subject: [PATCH 017/161] Add test coverage of double dispose of `OsuGame` --- osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index cc64d37116..0d1719c1d2 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -400,6 +400,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Hold escape", () => InputManager.PressKey(Key.Escape)); AddUntilStep("Wait for intro", () => Game.ScreenStack.CurrentScreen is IntroTriangles); AddUntilStep("Wait for game exit", () => Game.ScreenStack.CurrentScreen == null); + AddStep("test dispose doesn't crash", () => Game.Dispose()); } private void pushEscape() => From d999c29d3ac873f6991cf19030d9e74dc8bc0b49 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Sep 2021 19:38:43 +0900 Subject: [PATCH 018/161] Remove unused `GameHost` DI in `OsuGameTestScene` --- osu.Game/Tests/Visual/OsuGameTestScene.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuGameTestScene.cs b/osu.Game/Tests/Visual/OsuGameTestScene.cs index b56c8a15af..881c4bab02 100644 --- a/osu.Game/Tests/Visual/OsuGameTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGameTestScene.cs @@ -30,8 +30,6 @@ namespace osu.Game.Tests.Visual /// public abstract class OsuGameTestScene : OsuManualInputManagerTestScene { - private GameHost host; - protected TestOsuGame Game; protected override bool UseFreshStoragePerRun => true; @@ -39,10 +37,8 @@ namespace osu.Game.Tests.Visual protected override bool CreateNestedActionContainer => false; [BackgroundDependencyLoader] - private void load(GameHost host) + private void load() { - this.host = host; - Child = new Box { RelativeSizeAxes = Axes.Both, @@ -55,7 +51,7 @@ namespace osu.Game.Tests.Visual { AddStep("Create new game instance", () => { - if (Game != null) + if (Game?.Parent != null) { Remove(Game); Game.Dispose(); From e8d4e2e6da97c2a7b7dc41f78705bc6ad8a72894 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Sep 2021 19:38:53 +0900 Subject: [PATCH 019/161] Fix tests being blocked by notification overlay popup --- .../Navigation/TestSceneScreenNavigation.cs | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 0d1719c1d2..2c416ee758 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -77,7 +77,13 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("press enter", () => InputManager.Key(Key.Enter)); - AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null); + AddUntilStep("wait for player", () => + { + // dismiss any notifications that may appear (ie. muted notification). + clickMouseInCentre(); + return (player = Game.ScreenStack.CurrentScreen as Player) != null; + }); + AddAssert("retry count is 0", () => player.RestartCount == 0); AddStep("attempt to retry", () => player.ChildrenOfType().First().Action()); @@ -104,7 +110,14 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("set mods", () => Game.SelectedMods.Value = new Mod[] { new OsuModNoFail(), new OsuModDoubleTime { SpeedChange = { Value = 2 } } }); AddStep("press enter", () => InputManager.Key(Key.Enter)); - AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null); + + AddUntilStep("wait for player", () => + { + // dismiss any notifications that may appear (ie. muted notification). + clickMouseInCentre(); + return (player = Game.ScreenStack.CurrentScreen as Player) != null; + }); + AddUntilStep("wait for track playing", () => beatmap().Track.IsRunning); AddStep("seek to near end", () => player.ChildrenOfType().First().Seek(beatmap().Beatmap.HitObjects[^1].StartTime - 1000)); AddUntilStep("wait for pass", () => (results = Game.ScreenStack.CurrentScreen as ResultsScreen) != null && results.IsLoaded); @@ -131,7 +144,13 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("press enter", () => InputManager.Key(Key.Enter)); - AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null); + AddUntilStep("wait for player", () => + { + // dismiss any notifications that may appear (ie. muted notification). + clickMouseInCentre(); + return (player = Game.ScreenStack.CurrentScreen as Player) != null; + }); + AddUntilStep("wait for fail", () => player.HasFailed); AddUntilStep("wait for track stop", () => !Game.MusicController.IsPlaying); @@ -403,6 +422,12 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("test dispose doesn't crash", () => Game.Dispose()); } + private void clickMouseInCentre() + { + InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre); + InputManager.Click(MouseButton.Left); + } + private void pushEscape() => AddStep("Press escape", () => InputManager.Key(Key.Escape)); From 1a60ce164e31c5cf3706e25d4b7e42aa70f359da Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Tue, 24 Aug 2021 00:15:16 +0200 Subject: [PATCH 020/161] Add `ParticleJet` --- .../Visual/Gameplay/TestSceneParticleJet.cs | 61 +++++++ osu.Game/Graphics/Particles/ParticleJet.cs | 49 +++++ osu.Game/Graphics/Particles/ParticleSpewer.cs | 172 ++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs create mode 100644 osu.Game/Graphics/Particles/ParticleJet.cs create mode 100644 osu.Game/Graphics/Particles/ParticleSpewer.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs new file mode 100644 index 0000000000..6438ba0b22 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Graphics.Particles; +using osu.Game.Skinning; + +namespace osu.Game.Tests.Visual.Gameplay +{ + [TestFixture] + public class TestSceneParticleJet : OsuTestScene + { + private ParticleJet jet; + + [Resolved] + private SkinManager skinManager { get; set; } + + public TestSceneParticleJet() + { + AddStep("create", () => + { + Child = jet = createJet(); + }); + + AddToggleStep("toggle spawning", value => jet.Active = value); + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create jet", () => Child = jet = createJet()); + } + + [Test] + public void TestPresence() + { + AddStep("start jet", () => jet.Active = true); + AddAssert("is present", () => jet.IsPresent); + + AddWaitStep("wait for some particles", 3); + AddStep("stop jet", () => jet.Active = false); + + AddWaitStep("wait for clean screen", 5); + AddAssert("is not present", () => !jet.IsPresent); + } + + private ParticleJet createJet() + { + return new ParticleJet(skinManager.DefaultLegacySkin.GetTexture("star2"), 180) + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativePositionAxes = Axes.Y, + Y = -0.1f, + }; + } + } +} diff --git a/osu.Game/Graphics/Particles/ParticleJet.cs b/osu.Game/Graphics/Particles/ParticleJet.cs new file mode 100644 index 0000000000..039dd36ddc --- /dev/null +++ b/osu.Game/Graphics/Particles/ParticleJet.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.Textures; +using osu.Framework.Utils; +using osuTK; + +namespace osu.Game.Graphics.Particles +{ + public class ParticleJet : ParticleSpewer + { + private const int particles_per_second = 80; + private const double particle_lifetime = 500; + private const float angular_velocity = 3f; + private const int angle_spread = 10; + private const float velocity_min = 1.3f; + private const float velocity_max = 1.5f; + + private readonly int angle; + + protected override float ParticleGravity => 0.25f; + + public ParticleJet(Texture texture, int angle) + : base(texture, particles_per_second, particle_lifetime) + { + this.angle = angle; + } + + protected override FallingParticle SpawnParticle() + { + var directionRads = MathUtils.DegreesToRadians( + RNG.NextSingle(angle - angle_spread / 2, angle + angle_spread / 2) + ); + var direction = new Vector2(MathF.Sin(directionRads), MathF.Cos(directionRads)); + + return new FallingParticle + { + StartTime = (float)Time.Current, + Position = OriginPosition, + Duration = RNG.NextSingle((float)particle_lifetime * 0.8f, (float)particle_lifetime), + Velocity = direction * new Vector2(RNG.NextSingle(velocity_min, velocity_max)), + AngularVelocity = RNG.NextSingle(-angular_velocity, angular_velocity), + StartScale = 1f, + EndScale = 2f, + }; + } + } +} diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/Particles/ParticleSpewer.cs new file mode 100644 index 0000000000..7196727ca1 --- /dev/null +++ b/osu.Game/Graphics/Particles/ParticleSpewer.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. + +using System; +using osu.Framework.Graphics; +using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osuTK; + +namespace osu.Game.Graphics.Particles +{ + public abstract class ParticleSpewer : Sprite + { + private readonly FallingParticle[] particles; + private int currentIndex; + private double lastParticleAdded; + + private readonly double cooldown; + private readonly double maxLifetime; + + /// + /// Determines whether particles are being spawned. + /// + public bool Active { get; set; } + + public bool HasActiveParticles => Active || (lastParticleAdded + maxLifetime) > Time.Current; + public override bool IsPresent => base.IsPresent && HasActiveParticles; + + protected virtual float ParticleGravity => 0.5f; + + protected ParticleSpewer(Texture texture, int perSecond, double maxLifetime) + { + Texture = texture; + Blending = BlendingParameters.Additive; + + particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxLifetime / 1000)]; + + cooldown = 1000f / perSecond; + this.maxLifetime = maxLifetime; + } + + protected override void Update() + { + base.Update(); + + if (Active && Time.Current > lastParticleAdded + cooldown) + { + addParticle(SpawnParticle()); + } + + Invalidate(Invalidation.DrawNode); + } + + /// + /// Called each time a new particle should be spawned. + /// + protected abstract FallingParticle SpawnParticle(); + + private void addParticle(FallingParticle fallingParticle) + { + particles[currentIndex] = fallingParticle; + + currentIndex = (currentIndex + 1) % particles.Length; + lastParticleAdded = Time.Current; + } + + protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this); + + private class ParticleSpewerDrawNode : SpriteDrawNode + { + private readonly FallingParticle[] particles; + + protected new ParticleSpewer Source => (ParticleSpewer)base.Source; + + private float currentTime; + private float gravity; + + public ParticleSpewerDrawNode(Sprite source) + : base(source) + { + particles = new FallingParticle[Source.particles.Length]; + } + + public override void ApplyState() + { + base.ApplyState(); + + Source.particles.CopyTo(particles, 0); + + currentTime = (float)Source.Time.Current; + gravity = Source.ParticleGravity; + } + + protected override void Blit(Action vertexAction) + { + foreach (var p in particles) + { + // ignore particles that weren't initialized. + if (p.StartTime <= 0) continue; + + var timeSinceStart = currentTime - p.StartTime; + + var alpha = p.AlphaAtTime(timeSinceStart); + if (alpha <= 0) continue; + + var scale = p.ScaleAtTime(timeSinceStart); + var pos = p.PositionAtTime(timeSinceStart, gravity); + var angle = p.AngleAtTime(timeSinceStart); + + var rect = new RectangleF( + pos.X - Texture.DisplayWidth * scale / 2, + pos.Y - Texture.DisplayHeight * scale / 2, + Texture.DisplayWidth * scale, + Texture.DisplayHeight * scale); + + var quad = new Quad( + transformPosition(rect.TopLeft, rect.Centre, angle), + transformPosition(rect.TopRight, rect.Centre, angle), + transformPosition(rect.BottomLeft, rect.Centre, angle), + 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); + } + } + + private Vector2 transformPosition(Vector2 pos, Vector2 centre, float angle) + { + // rotate point around centre. + float cos = MathF.Cos(angle); + float sin = MathF.Sin(angle); + + float x = centre.X + (pos.X - centre.X) * cos + (pos.Y - centre.Y) * sin; + float y = centre.Y + (pos.Y - centre.Y) * cos - (pos.X - centre.X) * sin; + + // convert to screen space. + return Vector2Extensions.Transform(new Vector2(x, y), DrawInfo.Matrix); + } + } + + protected struct FallingParticle + { + public float StartTime; + public Vector2 Position; + public Vector2 Velocity; + public float Duration; + public float AngularVelocity; + public float StartScale; + public float EndScale; + + public float AlphaAtTime(float timeSinceStart) => 1 - progressAtTime(timeSinceStart); + + public float ScaleAtTime(float timeSinceStart) => StartScale + (EndScale - StartScale) * progressAtTime(timeSinceStart); + + public float AngleAtTime(float timeSinceStart) => AngularVelocity / 1000 * timeSinceStart; + + public Vector2 PositionAtTime(float timeSinceStart, float gravity) + { + var progress = progressAtTime(timeSinceStart); + var grav = new Vector2(0, -gravity) * progress; + + return Position + (Velocity - grav) * timeSinceStart; + } + + private float progressAtTime(float timeSinceStart) => Math.Clamp(timeSinceStart / Duration, 0, 1); + } + } +} From 714cf33aac1b94ce27d6411b4f0efdc3cab92c8b Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 29 Aug 2021 21:41:47 +0200 Subject: [PATCH 021/161] Change `ParticleSpewer` to use screen space --- osu.Game/Graphics/Particles/ParticleJet.cs | 19 ++++--- osu.Game/Graphics/Particles/ParticleSpewer.cs | 51 +++++++++++++------ 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/osu.Game/Graphics/Particles/ParticleJet.cs b/osu.Game/Graphics/Particles/ParticleJet.cs index 039dd36ddc..eb7a49abc3 100644 --- a/osu.Game/Graphics/Particles/ParticleJet.cs +++ b/osu.Game/Graphics/Particles/ParticleJet.cs @@ -29,21 +29,20 @@ namespace osu.Game.Graphics.Particles protected override FallingParticle SpawnParticle() { + var p = base.SpawnParticle(); + var directionRads = MathUtils.DegreesToRadians( RNG.NextSingle(angle - angle_spread / 2, angle + angle_spread / 2) ); var direction = new Vector2(MathF.Sin(directionRads), MathF.Cos(directionRads)); - return new FallingParticle - { - StartTime = (float)Time.Current, - Position = OriginPosition, - Duration = RNG.NextSingle((float)particle_lifetime * 0.8f, (float)particle_lifetime), - Velocity = direction * new Vector2(RNG.NextSingle(velocity_min, velocity_max)), - AngularVelocity = RNG.NextSingle(-angular_velocity, angular_velocity), - StartScale = 1f, - EndScale = 2f, - }; + p.Duration = RNG.NextSingle((float)particle_lifetime * 0.8f, (float)particle_lifetime); + p.Velocity = direction * new Vector2(RNG.NextSingle(velocity_min, velocity_max)); + p.AngularVelocity = RNG.NextSingle(-angular_velocity, angular_velocity); + p.StartScale = 1f; + p.EndScale = 2f; + + return p; } } } diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/Particles/ParticleSpewer.cs index 7196727ca1..f2c358bd96 100644 --- a/osu.Game/Graphics/Particles/ParticleSpewer.cs +++ b/osu.Game/Graphics/Particles/ParticleSpewer.cs @@ -45,6 +45,10 @@ namespace osu.Game.Graphics.Particles { base.Update(); + // reset cooldown if the clock was rewound. + // this can happen when seeking in replays. + if (lastParticleAdded > Time.Current) lastParticleAdded = 0; + if (Active && Time.Current > lastParticleAdded + cooldown) { addParticle(SpawnParticle()); @@ -56,7 +60,14 @@ namespace osu.Game.Graphics.Particles /// /// Called each time a new particle should be spawned. /// - protected abstract FallingParticle SpawnParticle(); + protected virtual FallingParticle SpawnParticle() + { + return new FallingParticle + { + StartTime = (float)Time.Current, + StartPosition = ToScreenSpace(OriginPosition), + }; + } private void addParticle(FallingParticle fallingParticle) { @@ -68,6 +79,8 @@ namespace osu.Game.Graphics.Particles protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this); + # region DrawNode + private class ParticleSpewerDrawNode : SpriteDrawNode { private readonly FallingParticle[] particles; @@ -102,6 +115,10 @@ namespace osu.Game.Graphics.Particles var timeSinceStart = currentTime - p.StartTime; + // ignore particles from the future. + // these can appear when seeking in replays. + if (timeSinceStart < 0) continue; + var alpha = p.AlphaAtTime(timeSinceStart); if (alpha <= 0) continue; @@ -109,17 +126,21 @@ namespace osu.Game.Graphics.Particles var pos = p.PositionAtTime(timeSinceStart, gravity); var angle = p.AngleAtTime(timeSinceStart); + var matrixScale = DrawInfo.Matrix.ExtractScale(); + var width = Texture.DisplayWidth * scale * matrixScale.X; + var height = Texture.DisplayHeight * scale * matrixScale.Y; + var rect = new RectangleF( - pos.X - Texture.DisplayWidth * scale / 2, - pos.Y - Texture.DisplayHeight * scale / 2, - Texture.DisplayWidth * scale, - Texture.DisplayHeight * scale); + pos.X - width / 2, + pos.Y - height / 2, + width, + height); var quad = new Quad( - transformPosition(rect.TopLeft, rect.Centre, angle), - transformPosition(rect.TopRight, rect.Centre, angle), - transformPosition(rect.BottomLeft, rect.Centre, angle), - transformPosition(rect.BottomRight, rect.Centre, angle) + rotatePosition(rect.TopLeft, rect.Centre, angle), + rotatePosition(rect.TopRight, rect.Centre, angle), + rotatePosition(rect.BottomLeft, rect.Centre, angle), + rotatePosition(rect.BottomRight, rect.Centre, angle) ); DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), null, vertexAction, @@ -128,24 +149,24 @@ namespace osu.Game.Graphics.Particles } } - private Vector2 transformPosition(Vector2 pos, Vector2 centre, float angle) + private Vector2 rotatePosition(Vector2 pos, Vector2 centre, float angle) { - // rotate point around centre. float cos = MathF.Cos(angle); float sin = MathF.Sin(angle); float x = centre.X + (pos.X - centre.X) * cos + (pos.Y - centre.Y) * sin; float y = centre.Y + (pos.Y - centre.Y) * cos - (pos.X - centre.X) * sin; - // convert to screen space. - return Vector2Extensions.Transform(new Vector2(x, y), DrawInfo.Matrix); + return new Vector2(x, y); } } + #endregion + protected struct FallingParticle { public float StartTime; - public Vector2 Position; + public Vector2 StartPosition; public Vector2 Velocity; public float Duration; public float AngularVelocity; @@ -163,7 +184,7 @@ namespace osu.Game.Graphics.Particles var progress = progressAtTime(timeSinceStart); var grav = new Vector2(0, -gravity) * progress; - return Position + (Velocity - grav) * timeSinceStart; + return StartPosition + (Velocity - grav) * timeSinceStart; } private float progressAtTime(float timeSinceStart) => Math.Clamp(timeSinceStart / Duration, 0, 1); From 4c753420d3859df95a3eed7751df08b0f83a6747 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sat, 4 Sep 2021 16:47:12 +0200 Subject: [PATCH 022/161] Fix `ParticleSpewer` gravity calculation --- osu.Game/Graphics/Particles/ParticleJet.cs | 6 +++--- osu.Game/Graphics/Particles/ParticleSpewer.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/Particles/ParticleJet.cs b/osu.Game/Graphics/Particles/ParticleJet.cs index eb7a49abc3..6bdde44a2c 100644 --- a/osu.Game/Graphics/Particles/ParticleJet.cs +++ b/osu.Game/Graphics/Particles/ParticleJet.cs @@ -14,12 +14,12 @@ namespace osu.Game.Graphics.Particles private const double particle_lifetime = 500; private const float angular_velocity = 3f; private const int angle_spread = 10; - private const float velocity_min = 1.3f; - private const float velocity_max = 1.5f; + private const float velocity_min = 1300f; + private const float velocity_max = 1500f; private readonly int angle; - protected override float ParticleGravity => 0.25f; + protected override float ParticleGravity => 750f; public ParticleJet(Texture texture, int angle) : base(texture, particles_per_second, particle_lifetime) diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/Particles/ParticleSpewer.cs index f2c358bd96..52e089fcca 100644 --- a/osu.Game/Graphics/Particles/ParticleSpewer.cs +++ b/osu.Game/Graphics/Particles/ParticleSpewer.cs @@ -28,7 +28,7 @@ namespace osu.Game.Graphics.Particles public bool HasActiveParticles => Active || (lastParticleAdded + maxLifetime) > Time.Current; public override bool IsPresent => base.IsPresent && HasActiveParticles; - protected virtual float ParticleGravity => 0.5f; + protected virtual float ParticleGravity => 0; protected ParticleSpewer(Texture texture, int perSecond, double maxLifetime) { @@ -182,9 +182,9 @@ namespace osu.Game.Graphics.Particles public Vector2 PositionAtTime(float timeSinceStart, float gravity) { var progress = progressAtTime(timeSinceStart); - var grav = new Vector2(0, -gravity) * progress; + var currentGravity = new Vector2(0, gravity * Duration / 1000 * progress); - return StartPosition + (Velocity - grav) * timeSinceStart; + return StartPosition + (Velocity + currentGravity) * timeSinceStart / 1000; } private float progressAtTime(float timeSinceStart) => Math.Clamp(timeSinceStart / Duration, 0, 1); From 328c9a5dd038d9882ebd11d8f0ba068b16826252 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sat, 4 Sep 2021 20:50:30 +0200 Subject: [PATCH 023/161] Change `ParticleSpewer.Active` to a Bindable --- osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs | 6 +++--- osu.Game/Graphics/Particles/ParticleSpewer.cs | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs index 6438ba0b22..e570abcf88 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Gameplay Child = jet = createJet(); }); - AddToggleStep("toggle spawning", value => jet.Active = value); + AddToggleStep("toggle spawning", value => jet.Active.Value = value); } [SetUpSteps] @@ -37,11 +37,11 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestPresence() { - AddStep("start jet", () => jet.Active = true); + AddStep("start jet", () => jet.Active.Value = true); AddAssert("is present", () => jet.IsPresent); AddWaitStep("wait for some particles", 3); - AddStep("stop jet", () => jet.Active = false); + AddStep("stop jet", () => jet.Active.Value = false); AddWaitStep("wait for clean screen", 5); AddAssert("is not present", () => !jet.IsPresent); diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/Particles/ParticleSpewer.cs index 52e089fcca..bc25206311 100644 --- a/osu.Game/Graphics/Particles/ParticleSpewer.cs +++ b/osu.Game/Graphics/Particles/ParticleSpewer.cs @@ -2,6 +2,7 @@ // 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.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; @@ -23,9 +24,9 @@ namespace osu.Game.Graphics.Particles /// /// Determines whether particles are being spawned. /// - public bool Active { get; set; } + public readonly BindableBool Active = new BindableBool(); - public bool HasActiveParticles => Active || (lastParticleAdded + maxLifetime) > Time.Current; + public bool HasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current; public override bool IsPresent => base.IsPresent && HasActiveParticles; protected virtual float ParticleGravity => 0; @@ -49,7 +50,7 @@ namespace osu.Game.Graphics.Particles // this can happen when seeking in replays. if (lastParticleAdded > Time.Current) lastParticleAdded = 0; - if (Active && Time.Current > lastParticleAdded + cooldown) + if (Active.Value && Time.Current > lastParticleAdded + cooldown) { addParticle(SpawnParticle()); } From ee4006f3d73389eddfcc382de288bb041d4f1989 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sat, 4 Sep 2021 21:49:05 +0200 Subject: [PATCH 024/161] Add legacy cursor star particles --- .../Skinning/Legacy/LegacyCursor.cs | 5 + .../Legacy/LegacyCursorStarParticles.cs | 185 ++++++++++++++++++ osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 1 + 3 files changed, 191 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs index b2ffc171be..cd7954a8d6 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs @@ -31,6 +31,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy InternalChildren = new[] { + new LegacyCursorStarParticles + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, ExpandTarget = new NonPlayfieldSprite { Texture = skin.GetTexture("cursor"), diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs new file mode 100644 index 0000000000..f10d9a0fa9 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs @@ -0,0 +1,185 @@ +// 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.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Framework.Input.Bindings; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Particles; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Screens.Play; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Skinning.Legacy +{ + public class LegacyCursorStarParticles : BeatSyncedContainer, IKeyBindingHandler + { + private StarParticleSpewer breakSpewer; + private StarParticleSpewer kiaiSpewer; + + [Resolved(canBeNull: true)] + private Player player { get; set; } + + [Resolved(canBeNull: true)] + private OsuPlayfield osuPlayfield { get; set; } + + [BackgroundDependencyLoader] + private void load(ISkinSource skin, OsuColour colour) + { + var texture = skin.GetTexture("star2"); + + InternalChildren = new[] + { + breakSpewer = new StarParticleSpewer(texture, 20) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = colour.PinkLighter, + Direction = SpewDirection.None, + Active = + { + Value = true, + } + }, + kiaiSpewer = new StarParticleSpewer(texture, 60) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = colour.PinkLighter, + Direction = SpewDirection.None, + Active = + { + Value = false, + } + }, + }; + + if (player != null) + { + breakSpewer.Active.BindTarget = player.IsBreakTime; + } + } + + protected override void Update() + { + if (osuPlayfield == null) return; + + // find active kiai slider or spinner. + var kiaiHitObject = osuPlayfield.HitObjectContainer.AliveObjects.FirstOrDefault(h => + h.HitObject.Kiai && + ( + (h is DrawableSlider slider && slider.Tracking.Value) || + (h is DrawableSpinner spinner && spinner.RotationTracker.Tracking) + ) + ); + + kiaiSpewer.Active.Value = kiaiHitObject != null; + } + + public bool OnPressed(OsuAction action) + { + handleInput(action, true); + return false; + } + + public void OnReleased(OsuAction action) + { + handleInput(action, false); + } + + private bool leftPressed; + private bool rightPressed; + + private void handleInput(OsuAction action, bool pressed) + { + switch (action) + { + case OsuAction.LeftButton: + leftPressed = pressed; + break; + + case OsuAction.RightButton: + rightPressed = pressed; + break; + } + + if (leftPressed && rightPressed) + breakSpewer.Direction = SpewDirection.Both; + else if (leftPressed) + breakSpewer.Direction = SpewDirection.Left; + else if (rightPressed) + breakSpewer.Direction = SpewDirection.Right; + else + breakSpewer.Direction = SpewDirection.None; + } + + private class StarParticleSpewer : ParticleSpewer + { + private const int particle_lifetime_min = 300; + private const int particle_lifetime_max = 1000; + + public SpewDirection Direction { get; set; } + + protected override float ParticleGravity => 460; + + public StarParticleSpewer(Texture texture, int perSecond) + : base(texture, perSecond, particle_lifetime_max) + { + } + + protected override FallingParticle SpawnParticle() + { + var p = base.SpawnParticle(); + + p.Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max); + p.AngularVelocity = RNG.NextSingle(-3f, 3f); + p.StartScale = RNG.NextSingle(0.5f, 1f); + p.EndScale = RNG.NextSingle(2f); + + switch (Direction) + { + case SpewDirection.None: + p.Velocity = Vector2.Zero; + break; + + case SpewDirection.Left: + p.Velocity = new Vector2( + RNG.NextSingle(-460f, 0) * 2, + RNG.NextSingle(-40f, 40f) * 2 + ); + break; + + case SpewDirection.Right: + p.Velocity = new Vector2( + RNG.NextSingle(0, 460f) * 2, + RNG.NextSingle(-40f, 40f) * 2 + ); + break; + + case SpewDirection.Both: + p.Velocity = new Vector2( + RNG.NextSingle(-460f, 460f) * 2, + RNG.NextSingle(-160f, 160f) * 2 + ); + break; + } + + return p; + } + } + + private enum SpewDirection + { + None, + Left, + Right, + Both, + } + } +} diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index c1c2ea2299..2233a547b9 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -24,6 +24,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.UI { + [Cached] public class OsuPlayfield : Playfield { private readonly PlayfieldBorder playfieldBorder; From 5b1b36436f0ec4ccf95f9dbdf45c28f5a87c3fbc Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 5 Sep 2021 01:01:49 +0200 Subject: [PATCH 025/161] Add cursor velocity to star particles --- .../Legacy/LegacyCursorStarParticles.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs index f10d9a0fa9..52d4eedf42 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs @@ -131,6 +131,44 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy public StarParticleSpewer(Texture texture, int perSecond) : base(texture, perSecond, particle_lifetime_max) { + Active.BindValueChanged(_ => resetVelocityCalculation()); + } + + private Vector2 screenPosition => ToScreenSpace(OriginPosition); + + private Vector2 screenVelocity; + + private const double velocity_calculation_delay = 15; + private double lastVelocityCalculation; + private Vector2 positionDifference; + private Vector2? lastPosition; + + protected override void Update() + { + base.Update(); + + if (lastPosition != null) + { + positionDifference += (screenPosition - lastPosition.Value); + lastVelocityCalculation += Clock.ElapsedFrameTime; + } + + lastPosition = screenPosition; + + if (lastVelocityCalculation > velocity_calculation_delay) + { + screenVelocity = positionDifference / (float)lastVelocityCalculation; + + positionDifference = Vector2.Zero; + lastVelocityCalculation = 0; + } + } + + private void resetVelocityCalculation() + { + positionDifference = Vector2.Zero; + lastVelocityCalculation = 0; + lastPosition = null; } protected override FallingParticle SpawnParticle() @@ -170,6 +208,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy break; } + p.Velocity += screenVelocity * 50; + return p; } } From db662f8c5c9ae2b7b35a0da4317e1e9ee94ab9dd Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 5 Sep 2021 16:08:22 +0200 Subject: [PATCH 026/161] Add `ParticleParent` option to `ParticleSpewer` --- .../Legacy/LegacyCursorStarParticles.cs | 31 ++++++++++++------- osu.Game/Graphics/Particles/ParticleJet.cs | 1 + osu.Game/Graphics/Particles/ParticleSpewer.cs | 17 +++++++--- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs index 52d4eedf42..58fe4f9b7c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Direction = SpewDirection.None, Active = { - Value = true, + Value = false, } }, kiaiSpewer = new StarParticleSpewer(texture, 60) @@ -64,6 +64,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { breakSpewer.Active.BindTarget = player.IsBreakTime; } + + if (osuPlayfield != null) + { + breakSpewer.ParticleParent = osuPlayfield; + kiaiSpewer.ParticleParent = osuPlayfield; + } } protected override void Update() @@ -126,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy public SpewDirection Direction { get; set; } - protected override float ParticleGravity => 460; + protected override float ParticleGravity => 240; public StarParticleSpewer(Texture texture, int perSecond) : base(texture, perSecond, particle_lifetime_max) @@ -134,7 +140,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Active.BindValueChanged(_ => resetVelocityCalculation()); } - private Vector2 screenPosition => ToScreenSpace(OriginPosition); + private Vector2 positionInParent => ToSpaceOfOtherDrawable(OriginPosition, ParticleParent); private Vector2 screenVelocity; @@ -149,11 +155,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (lastPosition != null) { - positionDifference += (screenPosition - lastPosition.Value); + positionDifference += (positionInParent - lastPosition.Value); lastVelocityCalculation += Clock.ElapsedFrameTime; } - lastPosition = screenPosition; + lastPosition = positionInParent; if (lastVelocityCalculation > velocity_calculation_delay) { @@ -175,6 +181,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { var p = base.SpawnParticle(); + p.StartPosition = positionInParent; p.Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max); p.AngularVelocity = RNG.NextSingle(-3f, 3f); p.StartScale = RNG.NextSingle(0.5f, 1f); @@ -188,27 +195,27 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy case SpewDirection.Left: p.Velocity = new Vector2( - RNG.NextSingle(-460f, 0) * 2, - RNG.NextSingle(-40f, 40f) * 2 + RNG.NextSingle(-460f, 0), + RNG.NextSingle(-40f, 40f) ); break; case SpewDirection.Right: p.Velocity = new Vector2( - RNG.NextSingle(0, 460f) * 2, - RNG.NextSingle(-40f, 40f) * 2 + RNG.NextSingle(0, 460f), + RNG.NextSingle(-40f, 40f) ); break; case SpewDirection.Both: p.Velocity = new Vector2( - RNG.NextSingle(-460f, 460f) * 2, - RNG.NextSingle(-160f, 160f) * 2 + RNG.NextSingle(-460f, 460f), + RNG.NextSingle(-160f, 160f) ); break; } - p.Velocity += screenVelocity * 50; + p.Velocity += screenVelocity * 40; return p; } diff --git a/osu.Game/Graphics/Particles/ParticleJet.cs b/osu.Game/Graphics/Particles/ParticleJet.cs index 6bdde44a2c..763f8d0a9e 100644 --- a/osu.Game/Graphics/Particles/ParticleJet.cs +++ b/osu.Game/Graphics/Particles/ParticleJet.cs @@ -36,6 +36,7 @@ namespace osu.Game.Graphics.Particles ); var direction = new Vector2(MathF.Sin(directionRads), MathF.Cos(directionRads)); + p.StartPosition = OriginPosition; p.Duration = RNG.NextSingle((float)particle_lifetime * 0.8f, (float)particle_lifetime); p.Velocity = direction * new Vector2(RNG.NextSingle(velocity_min, velocity_max)); p.AngularVelocity = RNG.NextSingle(-angular_velocity, angular_velocity); diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/Particles/ParticleSpewer.cs index bc25206311..2251d9590d 100644 --- a/osu.Game/Graphics/Particles/ParticleSpewer.cs +++ b/osu.Game/Graphics/Particles/ParticleSpewer.cs @@ -26,6 +26,12 @@ namespace osu.Game.Graphics.Particles /// public readonly BindableBool Active = new BindableBool(); + /// + /// whose DrawInfo will be used to draw each particle. + /// Defaults to the itself. + /// + public IDrawable ParticleParent; + public bool HasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current; public override bool IsPresent => base.IsPresent && HasActiveParticles; @@ -35,6 +41,7 @@ namespace osu.Game.Graphics.Particles { Texture = texture; Blending = BlendingParameters.Additive; + ParticleParent = this; particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxLifetime / 1000)]; @@ -66,7 +73,6 @@ namespace osu.Game.Graphics.Particles return new FallingParticle { StartTime = (float)Time.Current, - StartPosition = ToScreenSpace(OriginPosition), }; } @@ -90,6 +96,7 @@ namespace osu.Game.Graphics.Particles private float currentTime; private float gravity; + private Matrix3 particleDrawMatrix; public ParticleSpewerDrawNode(Sprite source) : base(source) @@ -105,6 +112,7 @@ namespace osu.Game.Graphics.Particles currentTime = (float)Source.Time.Current; gravity = Source.ParticleGravity; + particleDrawMatrix = Source.ParticleParent.DrawInfo.Matrix; } protected override void Blit(Action vertexAction) @@ -127,9 +135,8 @@ namespace osu.Game.Graphics.Particles var pos = p.PositionAtTime(timeSinceStart, gravity); var angle = p.AngleAtTime(timeSinceStart); - var matrixScale = DrawInfo.Matrix.ExtractScale(); - var width = Texture.DisplayWidth * scale * matrixScale.X; - var height = Texture.DisplayHeight * scale * matrixScale.Y; + var width = Texture.DisplayWidth * scale; + var height = Texture.DisplayHeight * scale; var rect = new RectangleF( pos.X - width / 2, @@ -158,7 +165,7 @@ namespace osu.Game.Graphics.Particles float x = centre.X + (pos.X - centre.X) * cos + (pos.Y - centre.Y) * sin; float y = centre.Y + (pos.Y - centre.Y) * cos - (pos.X - centre.X) * sin; - return new Vector2(x, y); + return Vector2Extensions.Transform(new Vector2(x, y), particleDrawMatrix); } } From 6d68da8ff00229bfcbccd68f7b6d73c80c4da70d Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 5 Sep 2021 16:25:24 +0200 Subject: [PATCH 027/161] Remove `StartScale` from `ParticleSpewer` particles --- .../Skinning/Legacy/LegacyCursorStarParticles.cs | 1 - osu.Game/Graphics/Particles/ParticleJet.cs | 1 - osu.Game/Graphics/Particles/ParticleSpewer.cs | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs index 58fe4f9b7c..d6c4d9f92a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs @@ -184,7 +184,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy p.StartPosition = positionInParent; p.Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max); p.AngularVelocity = RNG.NextSingle(-3f, 3f); - p.StartScale = RNG.NextSingle(0.5f, 1f); p.EndScale = RNG.NextSingle(2f); switch (Direction) diff --git a/osu.Game/Graphics/Particles/ParticleJet.cs b/osu.Game/Graphics/Particles/ParticleJet.cs index 763f8d0a9e..2d70a7f697 100644 --- a/osu.Game/Graphics/Particles/ParticleJet.cs +++ b/osu.Game/Graphics/Particles/ParticleJet.cs @@ -40,7 +40,6 @@ namespace osu.Game.Graphics.Particles p.Duration = RNG.NextSingle((float)particle_lifetime * 0.8f, (float)particle_lifetime); p.Velocity = direction * new Vector2(RNG.NextSingle(velocity_min, velocity_max)); p.AngularVelocity = RNG.NextSingle(-angular_velocity, angular_velocity); - p.StartScale = 1f; p.EndScale = 2f; return p; diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/Particles/ParticleSpewer.cs index 2251d9590d..f9fb30abdc 100644 --- a/osu.Game/Graphics/Particles/ParticleSpewer.cs +++ b/osu.Game/Graphics/Particles/ParticleSpewer.cs @@ -178,12 +178,11 @@ namespace osu.Game.Graphics.Particles public Vector2 Velocity; public float Duration; public float AngularVelocity; - public float StartScale; public float EndScale; public float AlphaAtTime(float timeSinceStart) => 1 - progressAtTime(timeSinceStart); - public float ScaleAtTime(float timeSinceStart) => StartScale + (EndScale - StartScale) * progressAtTime(timeSinceStart); + public float ScaleAtTime(float timeSinceStart) => 1 + (EndScale - 1) * progressAtTime(timeSinceStart); public float AngleAtTime(float timeSinceStart) => AngularVelocity / 1000 * timeSinceStart; From c2f7b01ca400b8286365877c3f363f247897c857 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 5 Sep 2021 17:08:00 +0200 Subject: [PATCH 028/161] Change particle `AngularVelocity` into `StartAngle` and `EndAngle` --- .../Skinning/Legacy/LegacyCursorStarParticles.cs | 3 ++- osu.Game/Graphics/Particles/ParticleJet.cs | 4 ++-- osu.Game/Graphics/Particles/ParticleSpewer.cs | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs index d6c4d9f92a..9c901a7de5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs @@ -183,7 +183,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy p.StartPosition = positionInParent; p.Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max); - p.AngularVelocity = RNG.NextSingle(-3f, 3f); + p.StartAngle = (float)(RNG.NextDouble() * 4 - 2); + p.EndAngle = RNG.NextSingle(-2f, 2f); p.EndScale = RNG.NextSingle(2f); switch (Direction) diff --git a/osu.Game/Graphics/Particles/ParticleJet.cs b/osu.Game/Graphics/Particles/ParticleJet.cs index 2d70a7f697..a76aa6b75f 100644 --- a/osu.Game/Graphics/Particles/ParticleJet.cs +++ b/osu.Game/Graphics/Particles/ParticleJet.cs @@ -12,7 +12,6 @@ namespace osu.Game.Graphics.Particles { private const int particles_per_second = 80; private const double particle_lifetime = 500; - private const float angular_velocity = 3f; private const int angle_spread = 10; private const float velocity_min = 1300f; private const float velocity_max = 1500f; @@ -39,7 +38,8 @@ namespace osu.Game.Graphics.Particles p.StartPosition = OriginPosition; p.Duration = RNG.NextSingle((float)particle_lifetime * 0.8f, (float)particle_lifetime); p.Velocity = direction * new Vector2(RNG.NextSingle(velocity_min, velocity_max)); - p.AngularVelocity = RNG.NextSingle(-angular_velocity, angular_velocity); + p.StartAngle = RNG.NextSingle(-2f, 2f); + p.EndAngle = RNG.NextSingle(-2f, 2f); p.EndScale = 2f; return p; diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/Particles/ParticleSpewer.cs index f9fb30abdc..3d2225d382 100644 --- a/osu.Game/Graphics/Particles/ParticleSpewer.cs +++ b/osu.Game/Graphics/Particles/ParticleSpewer.cs @@ -177,14 +177,15 @@ namespace osu.Game.Graphics.Particles public Vector2 StartPosition; public Vector2 Velocity; public float Duration; - public float AngularVelocity; + public float StartAngle; + public float EndAngle; public float EndScale; public float AlphaAtTime(float timeSinceStart) => 1 - progressAtTime(timeSinceStart); public float ScaleAtTime(float timeSinceStart) => 1 + (EndScale - 1) * progressAtTime(timeSinceStart); - public float AngleAtTime(float timeSinceStart) => AngularVelocity / 1000 * timeSinceStart; + public float AngleAtTime(float timeSinceStart) => StartAngle + (EndAngle - StartAngle) * progressAtTime(timeSinceStart); public Vector2 PositionAtTime(float timeSinceStart, float gravity) { From 99eff4f41f5e5d126fc165fed86309e98ed05cfd Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Thu, 9 Sep 2021 23:18:19 +0200 Subject: [PATCH 029/161] Move cursor particles under `OsuCursorContainer` --- .../Skinning/Legacy/LegacyCursor.cs | 5 -- .../Legacy/LegacyCursorStarParticles.cs | 71 ++++++++++--------- .../UI/Cursor/OsuCursorContainer.cs | 11 ++- osu.Game/Graphics/Particles/ParticleSpewer.cs | 27 ++----- 4 files changed, 53 insertions(+), 61 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs index cd7954a8d6..b2ffc171be 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs @@ -31,11 +31,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy InternalChildren = new[] { - new LegacyCursorStarParticles - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, ExpandTarget = new NonPlayfieldSprite { Texture = skin.GetTexture("cursor"), diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs index 9c901a7de5..89ffa4ca15 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs @@ -4,11 +4,13 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; +using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Particles; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; @@ -18,7 +20,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyCursorStarParticles : BeatSyncedContainer, IKeyBindingHandler + public class LegacyCursorStarParticles : CompositeDrawable, IKeyBindingHandler { private StarParticleSpewer breakSpewer; private StarParticleSpewer kiaiSpewer; @@ -64,12 +66,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { breakSpewer.Active.BindTarget = player.IsBreakTime; } - - if (osuPlayfield != null) - { - breakSpewer.ParticleParent = osuPlayfield; - kiaiSpewer.ParticleParent = osuPlayfield; - } } protected override void Update() @@ -116,7 +112,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } if (leftPressed && rightPressed) - breakSpewer.Direction = SpewDirection.Both; + breakSpewer.Direction = SpewDirection.Omni; else if (leftPressed) breakSpewer.Direction = SpewDirection.Left; else if (rightPressed) @@ -125,13 +121,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy breakSpewer.Direction = SpewDirection.None; } - private class StarParticleSpewer : ParticleSpewer + private class StarParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition { private const int particle_lifetime_min = 300; private const int particle_lifetime_max = 1000; public SpewDirection Direction { get; set; } + protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue; protected override float ParticleGravity => 240; public StarParticleSpewer(Texture texture, int perSecond) @@ -140,48 +137,52 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Active.BindValueChanged(_ => resetVelocityCalculation()); } - private Vector2 positionInParent => ToSpaceOfOtherDrawable(OriginPosition, ParticleParent); + private Vector2? cursorScreenPosition; + private Vector2 cursorVelocity; - private Vector2 screenVelocity; + private const double max_velocity_frame_length = 15; + private double velocityFrameLength; + private Vector2 totalPosDifference; - private const double velocity_calculation_delay = 15; - private double lastVelocityCalculation; - private Vector2 positionDifference; - private Vector2? lastPosition; - - protected override void Update() + protected override bool OnMouseMove(MouseMoveEvent e) { - base.Update(); - - if (lastPosition != null) + if (cursorScreenPosition == null) { - positionDifference += (positionInParent - lastPosition.Value); - lastVelocityCalculation += Clock.ElapsedFrameTime; + cursorScreenPosition = e.ScreenSpaceMousePosition; + return base.OnMouseMove(e); } - lastPosition = positionInParent; + // calculate cursor velocity. + totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value; + cursorScreenPosition = e.ScreenSpaceMousePosition; - if (lastVelocityCalculation > velocity_calculation_delay) + velocityFrameLength += Clock.ElapsedFrameTime; + + if (velocityFrameLength > max_velocity_frame_length) { - screenVelocity = positionDifference / (float)lastVelocityCalculation; + cursorVelocity = totalPosDifference / (float)velocityFrameLength; - positionDifference = Vector2.Zero; - lastVelocityCalculation = 0; + totalPosDifference = Vector2.Zero; + velocityFrameLength = 0; } + + return base.OnMouseMove(e); } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + private void resetVelocityCalculation() { - positionDifference = Vector2.Zero; - lastVelocityCalculation = 0; - lastPosition = null; + cursorScreenPosition = null; + totalPosDifference = Vector2.Zero; + velocityFrameLength = 0; } protected override FallingParticle SpawnParticle() { var p = base.SpawnParticle(); - p.StartPosition = positionInParent; + p.StartPosition = ToLocalSpace(cursorScreenPosition ?? Vector2.Zero); p.Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max); p.StartAngle = (float)(RNG.NextDouble() * 4 - 2); p.EndAngle = RNG.NextSingle(-2f, 2f); @@ -207,7 +208,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy ); break; - case SpewDirection.Both: + case SpewDirection.Omni: p.Velocity = new Vector2( RNG.NextSingle(-460f, 460f), RNG.NextSingle(-160f, 160f) @@ -215,7 +216,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy break; } - p.Velocity += screenVelocity * 40; + p.Velocity += cursorVelocity * 40; return p; } @@ -226,7 +227,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy None, Left, Right, - Both, + Omni, } } } diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 5812e8cf75..fbb7bfd7b1 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -11,6 +11,7 @@ using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Configuration; +using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osu.Game.Skinning; @@ -42,7 +43,15 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor InternalChild = fadeContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = cursorTrail = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling) + Children = new[] + { + cursorTrail = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling), + new LegacyCursorStarParticles() + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + } }; } diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/Particles/ParticleSpewer.cs index 3d2225d382..f0c9dff239 100644 --- a/osu.Game/Graphics/Particles/ParticleSpewer.cs +++ b/osu.Game/Graphics/Particles/ParticleSpewer.cs @@ -26,22 +26,16 @@ namespace osu.Game.Graphics.Particles /// public readonly BindableBool Active = new BindableBool(); - /// - /// whose DrawInfo will be used to draw each particle. - /// Defaults to the itself. - /// - public IDrawable ParticleParent; - public bool HasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current; public override bool IsPresent => base.IsPresent && HasActiveParticles; + protected virtual bool CanSpawnParticles => true; protected virtual float ParticleGravity => 0; protected ParticleSpewer(Texture texture, int perSecond, double maxLifetime) { Texture = texture; Blending = BlendingParameters.Additive; - ParticleParent = this; particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxLifetime / 1000)]; @@ -57,9 +51,12 @@ namespace osu.Game.Graphics.Particles // this can happen when seeking in replays. if (lastParticleAdded > Time.Current) lastParticleAdded = 0; - if (Active.Value && Time.Current > lastParticleAdded + cooldown) + if (Active.Value && CanSpawnParticles && Time.Current > lastParticleAdded + cooldown) { - addParticle(SpawnParticle()); + particles[currentIndex] = SpawnParticle(); + + currentIndex = (currentIndex + 1) % particles.Length; + lastParticleAdded = Time.Current; } Invalidate(Invalidation.DrawNode); @@ -76,14 +73,6 @@ namespace osu.Game.Graphics.Particles }; } - private void addParticle(FallingParticle fallingParticle) - { - particles[currentIndex] = fallingParticle; - - currentIndex = (currentIndex + 1) % particles.Length; - lastParticleAdded = Time.Current; - } - protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this); # region DrawNode @@ -96,7 +85,6 @@ namespace osu.Game.Graphics.Particles private float currentTime; private float gravity; - private Matrix3 particleDrawMatrix; public ParticleSpewerDrawNode(Sprite source) : base(source) @@ -112,7 +100,6 @@ namespace osu.Game.Graphics.Particles currentTime = (float)Source.Time.Current; gravity = Source.ParticleGravity; - particleDrawMatrix = Source.ParticleParent.DrawInfo.Matrix; } protected override void Blit(Action vertexAction) @@ -165,7 +152,7 @@ namespace osu.Game.Graphics.Particles float x = centre.X + (pos.X - centre.X) * cos + (pos.Y - centre.Y) * sin; float y = centre.Y + (pos.Y - centre.Y) * cos - (pos.X - centre.X) * sin; - return Vector2Extensions.Transform(new Vector2(x, y), particleDrawMatrix); + return Vector2Extensions.Transform(new Vector2(x, y), DrawInfo.Matrix); } } From cfcb46034c51bc4a95186f4e304e8b84294706fa Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Fri, 10 Sep 2021 00:02:37 +0200 Subject: [PATCH 030/161] Remove `ParticleJet` --- .../Visual/Gameplay/TestSceneParticleJet.cs | 61 ------------ .../Gameplay/TestSceneParticleSpewer.cs | 94 +++++++++++++++++++ osu.Game/Graphics/Particles/ParticleJet.cs | 48 ---------- 3 files changed, 94 insertions(+), 109 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs delete mode 100644 osu.Game/Graphics/Particles/ParticleJet.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs deleted file mode 100644 index e570abcf88..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleJet.cs +++ /dev/null @@ -1,61 +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.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Testing; -using osu.Game.Graphics.Particles; -using osu.Game.Skinning; - -namespace osu.Game.Tests.Visual.Gameplay -{ - [TestFixture] - public class TestSceneParticleJet : OsuTestScene - { - private ParticleJet jet; - - [Resolved] - private SkinManager skinManager { get; set; } - - public TestSceneParticleJet() - { - AddStep("create", () => - { - Child = jet = createJet(); - }); - - AddToggleStep("toggle spawning", value => jet.Active.Value = value); - } - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("create jet", () => Child = jet = createJet()); - } - - [Test] - public void TestPresence() - { - AddStep("start jet", () => jet.Active.Value = true); - AddAssert("is present", () => jet.IsPresent); - - AddWaitStep("wait for some particles", 3); - AddStep("stop jet", () => jet.Active.Value = false); - - AddWaitStep("wait for clean screen", 5); - AddAssert("is not present", () => !jet.IsPresent); - } - - private ParticleJet createJet() - { - return new ParticleJet(skinManager.DefaultLegacySkin.GetTexture("star2"), 180) - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativePositionAxes = Axes.Y, - Y = -0.1f, - }; - } - } -} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs new file mode 100644 index 0000000000..3a59374c98 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.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 System; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Graphics.Particles; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + [TestFixture] + public class TestSceneParticleSpewer : OsuTestScene + { + private TestParticleSpewer spewer; + + [Resolved] + private SkinManager skinManager { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + Child = spewer = createSpewer(); + + AddToggleStep("toggle spawning", value => spewer.Active.Value = value); + AddSliderStep("particle gravity", 0f, 250f, 0f, value => spewer.Gravity = value); + AddSliderStep("particle velocity", 0f, 500f, 250f, value => spewer.MaxVelocity = value); + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create jet", () => Child = spewer = createSpewer()); + } + + [Test] + public void TestPresence() + { + AddStep("start jet", () => spewer.Active.Value = true); + AddAssert("is present", () => spewer.IsPresent); + + AddWaitStep("wait for some particles", 3); + AddStep("stop jet", () => spewer.Active.Value = false); + + AddWaitStep("wait for clean screen", 8); + AddAssert("is not present", () => !spewer.IsPresent); + } + + private TestParticleSpewer createSpewer() + { + return new TestParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2")) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + private class TestParticleSpewer : ParticleSpewer + { + private const int lifetime = 1500; + private const int rate = 250; + + public float Gravity = 0; + public float MaxVelocity = 250; + + protected override float ParticleGravity => Gravity; + + public TestParticleSpewer(Texture texture) + : base(texture, rate, lifetime) + { + } + + protected override FallingParticle SpawnParticle() + { + var p = base.SpawnParticle(); + p.Velocity = new Vector2( + RNG.NextSingle(-MaxVelocity, MaxVelocity), + RNG.NextSingle(-MaxVelocity, MaxVelocity) + ); + p.Duration = RNG.NextSingle(lifetime); + p.StartAngle = RNG.NextSingle(MathF.PI * 2); + p.EndAngle = RNG.NextSingle(MathF.PI * 2); + p.EndScale = RNG.NextSingle(0.5f, 1.5f); + + return p; + } + } + } +} diff --git a/osu.Game/Graphics/Particles/ParticleJet.cs b/osu.Game/Graphics/Particles/ParticleJet.cs deleted file mode 100644 index a76aa6b75f..0000000000 --- a/osu.Game/Graphics/Particles/ParticleJet.cs +++ /dev/null @@ -1,48 +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.Textures; -using osu.Framework.Utils; -using osuTK; - -namespace osu.Game.Graphics.Particles -{ - public class ParticleJet : ParticleSpewer - { - private const int particles_per_second = 80; - private const double particle_lifetime = 500; - private const int angle_spread = 10; - private const float velocity_min = 1300f; - private const float velocity_max = 1500f; - - private readonly int angle; - - protected override float ParticleGravity => 750f; - - public ParticleJet(Texture texture, int angle) - : base(texture, particles_per_second, particle_lifetime) - { - this.angle = angle; - } - - protected override FallingParticle SpawnParticle() - { - var p = base.SpawnParticle(); - - var directionRads = MathUtils.DegreesToRadians( - RNG.NextSingle(angle - angle_spread / 2, angle + angle_spread / 2) - ); - var direction = new Vector2(MathF.Sin(directionRads), MathF.Cos(directionRads)); - - p.StartPosition = OriginPosition; - p.Duration = RNG.NextSingle((float)particle_lifetime * 0.8f, (float)particle_lifetime); - p.Velocity = direction * new Vector2(RNG.NextSingle(velocity_min, velocity_max)); - p.StartAngle = RNG.NextSingle(-2f, 2f); - p.EndAngle = RNG.NextSingle(-2f, 2f); - p.EndScale = 2f; - - return p; - } - } -} From 8862d3fa1ea67d42c54dda8710206f036aed6436 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Fri, 10 Sep 2021 00:29:05 +0200 Subject: [PATCH 031/161] Add `OsuSkinComponents.CursorParticles` --- osu.Game.Rulesets.Osu/OsuSkinComponents.cs | 1 + .../Skinning/Legacy/OsuLegacySkinTransformer.cs | 3 +++ osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 7 +------ 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs index 46e501758b..484d1c6753 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs @@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Osu FollowPoint, Cursor, CursorTrail, + CursorParticles, SliderScorePoint, ReverseArrow, HitCircleText, diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 41b0a88f11..0887e4d1d3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -89,6 +89,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return null; + case OsuSkinComponents.CursorParticles: + return new LegacyCursorStarParticles(); + case OsuSkinComponents.HitCircleText: if (!this.HasFont(LegacyFont.HitCircle)) return null; diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index fbb7bfd7b1..463b1f4eaf 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -11,7 +11,6 @@ using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Configuration; -using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osu.Game.Skinning; @@ -46,11 +45,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor Children = new[] { cursorTrail = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling), - new LegacyCursorStarParticles() - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, + new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorParticles), confineMode: ConfineMode.NoScaling), } }; } From 911282234e9a0944caec1af51c6c544e28927edf Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Fri, 10 Sep 2021 00:30:58 +0200 Subject: [PATCH 032/161] Rename legacy cursor particle classes --- ...orStarParticles.cs => LegacyCursorParticles.cs} | 14 +++++++------- .../Skinning/Legacy/OsuLegacySkinTransformer.cs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) rename osu.Game.Rulesets.Osu/Skinning/Legacy/{LegacyCursorStarParticles.cs => LegacyCursorParticles.cs} (93%) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs similarity index 93% rename from osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 89ffa4ca15..876af29e88 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorStarParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -20,10 +20,10 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyCursorStarParticles : CompositeDrawable, IKeyBindingHandler + public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler { - private StarParticleSpewer breakSpewer; - private StarParticleSpewer kiaiSpewer; + private LegacyCursorParticleSpewer breakSpewer; + private LegacyCursorParticleSpewer kiaiSpewer; [Resolved(canBeNull: true)] private Player player { get; set; } @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy InternalChildren = new[] { - breakSpewer = new StarParticleSpewer(texture, 20) + breakSpewer = new LegacyCursorParticleSpewer(texture, 20) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Value = false, } }, - kiaiSpewer = new StarParticleSpewer(texture, 60) + kiaiSpewer = new LegacyCursorParticleSpewer(texture, 60) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy breakSpewer.Direction = SpewDirection.None; } - private class StarParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition + private class LegacyCursorParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition { private const int particle_lifetime_min = 300; private const int particle_lifetime_max = 1000; @@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue; protected override float ParticleGravity => 240; - public StarParticleSpewer(Texture texture, int perSecond) + public LegacyCursorParticleSpewer(Texture texture, int perSecond) : base(texture, perSecond, particle_lifetime_max) { Active.BindValueChanged(_ => resetVelocityCalculation()); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 0887e4d1d3..20c432b298 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return null; case OsuSkinComponents.CursorParticles: - return new LegacyCursorStarParticles(); + return new LegacyCursorParticles(); case OsuSkinComponents.HitCircleText: if (!this.HasFont(LegacyFont.HitCircle)) From a688e69859262529d668ad6db5758d58d29aa8f6 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sat, 11 Sep 2021 01:55:16 +0200 Subject: [PATCH 033/161] Scale down cursor particles --- .../Skinning/Legacy/LegacyCursorParticles.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 876af29e88..f8b5ab97df 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -35,6 +35,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private void load(ISkinSource skin, OsuColour colour) { var texture = skin.GetTexture("star2"); + if (texture == null) + return; + + texture.ScaleAdjust = 3.2f; InternalChildren = new[] { From 82d16ab394e747a333b47a9ac725d8152b94ce07 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 12 Sep 2021 23:45:50 +0200 Subject: [PATCH 034/161] Fix `LegacyCursorParticles` texture null reference --- .../Skinning/Legacy/OsuLegacySkinTransformer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 20c432b298..02a67ea44f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -90,7 +90,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return null; case OsuSkinComponents.CursorParticles: - return new LegacyCursorParticles(); + if (GetTexture("star2") != null) + return new LegacyCursorParticles(); + + return null; case OsuSkinComponents.HitCircleText: if (!this.HasFont(LegacyFont.HitCircle)) From 16f98357e621260b5a7e9107055e391e2c453a62 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 12 Sep 2021 23:53:41 +0200 Subject: [PATCH 035/161] Add cursor particles tests --- .../TestSceneCursorParticles.cs | 174 ++++++++++++++++++ .../Skinning/Legacy/LegacyCursorParticles.cs | 8 +- 2 files changed, 179 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs new file mode 100644 index 0000000000..11b1f5b2af --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs @@ -0,0 +1,174 @@ +// 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.Testing; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Skinning.Legacy; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Skinning; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneCursorParticles : TestSceneOsuPlayer + { + protected override bool Autoplay => autoplay; + protected override bool HasCustomSteps => true; + + private bool autoplay; + private IBeatmap currentBeatmap; + + [Resolved] + private SkinManager skinManager { get; set; } + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => currentBeatmap ?? base.CreateBeatmap(ruleset); + + [Test] + public void TestLegacyBreakParticles() + { + LegacyCursorParticles cursorParticles = null; + + createLegacyTest(false, () => new Beatmap + { + Breaks = + { + new BreakPeriod(8500, 10000), + }, + HitObjects = + { + new HitCircle + { + StartTime = 8000, + Position = OsuPlayfield.BASE_SIZE / 2, + }, + new HitCircle + { + StartTime = 11000, + Position = OsuPlayfield.BASE_SIZE / 2, + }, + } + }); + + AddUntilStep("fetch cursor particles", () => + { + cursorParticles = this.ChildrenOfType().SingleOrDefault(); + return cursorParticles != null; + }); + + AddStep("move mouse to centre", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre)); + + AddAssert("particles are being spawned", () => cursorParticles.Active); + + AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left)); + AddWaitStep("wait a bit", 5); + AddStep("press right mouse button", () => InputManager.PressButton(MouseButton.Right)); + AddWaitStep("wait a bit", 5); + AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); + AddWaitStep("wait a bit", 5); + AddStep("release right mouse button", () => InputManager.ReleaseButton(MouseButton.Right)); + + AddUntilStep("wait for beatmap start", () => !Player.IsBreakTime.Value); + AddAssert("particle spawning stopped", () => !cursorParticles.Active); + + AddUntilStep("wait for break", () => Player.IsBreakTime.Value); + AddAssert("particles are being spawned", () => cursorParticles.Active); + + AddUntilStep("wait for break end", () => !Player.IsBreakTime.Value); + AddAssert("particle spawning stopped", () => !cursorParticles.Active); + } + + [Test] + public void TestLegacyKiaiParticles() + { + LegacyCursorParticles cursorParticles = null; + DrawableSpinner spinner = null; + DrawableSlider slider = null; + + createLegacyTest(true, () => + { + var controlPointInfo = new ControlPointInfo(); + controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + + return new Beatmap + { + ControlPointInfo = controlPointInfo, + HitObjects = + { + new Spinner + { + StartTime = 0, + Duration = 1000, + Position = OsuPlayfield.BASE_SIZE / 2, + }, + new Slider + { + StartTime = 2500, + RepeatCount = 0, + Position = OsuPlayfield.BASE_SIZE / 2, + Path = new SliderPath(new[] + { + new PathControlPoint(Vector2.Zero), + new PathControlPoint(new Vector2(100, 0)), + }) + }, + new HitCircle + { + StartTime = 4500, + Position = OsuPlayfield.BASE_SIZE / 2, + }, + }, + }; + } + ); + + AddUntilStep("fetch cursor particles", () => + { + cursorParticles = this.ChildrenOfType().SingleOrDefault(); + return cursorParticles != null; + }); + + AddUntilStep("wait for spinner tracking", () => + { + spinner = this.ChildrenOfType().SingleOrDefault(); + return spinner?.RotationTracker.Tracking == true; + }); + AddAssert("particles are being spawned", () => cursorParticles.Active); + + AddUntilStep("spinner tracking stopped", () => !spinner.RotationTracker.Tracking); + AddAssert("particle spawning stopped", () => !cursorParticles.Active); + + AddUntilStep("wait for slider tracking", () => + { + slider = this.ChildrenOfType().SingleOrDefault(); + return slider?.Tracking.Value == true; + }); + AddAssert("particles are being spawned", () => cursorParticles.Active); + + AddUntilStep("slider tracking stopped", () => !slider.Tracking.Value); + AddAssert("particle spawning stopped", () => !cursorParticles.Active); + } + + private void createLegacyTest(bool autoplay, Func beatmap) => CreateTest(() => + { + AddStep("set beatmap", () => + { + this.autoplay = autoplay; + currentBeatmap = beatmap(); + }); + AddStep("setup default legacy skin", () => + { + skinManager.CurrentSkinInfo.Value = skinManager.DefaultLegacySkin.SkinInfo; + }); + }); + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index f8b5ab97df..2080b1a3ce 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -22,6 +22,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler { + public bool Active => breakSpewer?.Active.Value == true || kiaiSpewer?.Active.Value == true; + private LegacyCursorParticleSpewer breakSpewer; private LegacyCursorParticleSpewer kiaiSpewer; @@ -32,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private OsuPlayfield osuPlayfield { get; set; } [BackgroundDependencyLoader] - private void load(ISkinSource skin, OsuColour colour) + private void load(ISkinSource skin, OsuColour colours) { var texture = skin.GetTexture("star2"); if (texture == null) @@ -46,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Colour = colour.PinkLighter, + Colour = colours.PinkLighter, Direction = SpewDirection.None, Active = { @@ -57,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Colour = colour.PinkLighter, + Colour = colours.PinkLighter, Direction = SpewDirection.None, Active = { From 7327603fc834de3cbb32b29e5a511d1df8061107 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Mon, 13 Sep 2021 00:05:49 +0200 Subject: [PATCH 036/161] Fix outdated test step description --- osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index 3a59374c98..e58bbb737e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -35,17 +35,17 @@ namespace osu.Game.Tests.Visual.Gameplay [SetUpSteps] public void SetUpSteps() { - AddStep("create jet", () => Child = spewer = createSpewer()); + AddStep("create spewer", () => Child = spewer = createSpewer()); } [Test] public void TestPresence() { - AddStep("start jet", () => spewer.Active.Value = true); + AddStep("start spewer", () => spewer.Active.Value = true); AddAssert("is present", () => spewer.IsPresent); AddWaitStep("wait for some particles", 3); - AddStep("stop jet", () => spewer.Active.Value = false); + AddStep("stop spewer", () => spewer.Active.Value = false); AddWaitStep("wait for clean screen", 8); AddAssert("is not present", () => !spewer.IsPresent); From 224244801f35ed2b031c9be907cd891181b5da97 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Mon, 13 Sep 2021 00:35:13 +0200 Subject: [PATCH 037/161] Remove Particles namespace --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs | 1 - osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs | 2 +- osu.Game/Graphics/{Particles => }/ParticleSpewer.cs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) rename osu.Game/Graphics/{Particles => }/ParticleSpewer.cs (99%) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 2080b1a3ce..95c2a6b930 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -11,7 +11,6 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Graphics; -using osu.Game.Graphics.Particles; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; using osu.Game.Screens.Play; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index e58bbb737e..fe14869e9a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Framework.Utils; -using osu.Game.Graphics.Particles; +using osu.Game.Graphics; using osu.Game.Skinning; using osuTK; diff --git a/osu.Game/Graphics/Particles/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs similarity index 99% rename from osu.Game/Graphics/Particles/ParticleSpewer.cs rename to osu.Game/Graphics/ParticleSpewer.cs index f0c9dff239..544b2bd2ed 100644 --- a/osu.Game/Graphics/Particles/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osuTK; -namespace osu.Game.Graphics.Particles +namespace osu.Game.Graphics { public abstract class ParticleSpewer : Sprite { From b009772206a4ffeebb2b7d36dad890ec655c2ff6 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Mon, 13 Sep 2021 00:45:36 +0200 Subject: [PATCH 038/161] Fix code inspect failure --- osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index fe14869e9a..e6b5763f2c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual.Gameplay private const int lifetime = 1500; private const int rate = 250; - public float Gravity = 0; + public float Gravity; public float MaxVelocity = 250; protected override float ParticleGravity => Gravity; From 9fd616c578107ab375fa102ab313a6d5f40a34cf Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Tue, 14 Sep 2021 00:16:42 +0200 Subject: [PATCH 039/161] Tiny refactor --- .../Skinning/Legacy/LegacyCursorParticles.cs | 4 ++-- osu.Game/Graphics/ParticleSpewer.cs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 95c2a6b930..8dc486285b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -149,6 +149,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private double velocityFrameLength; private Vector2 totalPosDifference; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + protected override bool OnMouseMove(MouseMoveEvent e) { if (cursorScreenPosition == null) @@ -174,8 +176,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return base.OnMouseMove(e); } - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - private void resetVelocityCalculation() { cursorScreenPosition = null; diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 544b2bd2ed..8b82dfb7c6 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -132,10 +132,10 @@ namespace osu.Game.Graphics height); var quad = new Quad( - rotatePosition(rect.TopLeft, rect.Centre, angle), - rotatePosition(rect.TopRight, rect.Centre, angle), - rotatePosition(rect.BottomLeft, rect.Centre, angle), - rotatePosition(rect.BottomRight, rect.Centre, angle) + transformPosition(rect.TopLeft, rect.Centre, angle), + transformPosition(rect.TopRight, rect.Centre, angle), + transformPosition(rect.BottomLeft, rect.Centre, angle), + transformPosition(rect.BottomRight, rect.Centre, angle) ); DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), null, vertexAction, @@ -144,7 +144,7 @@ namespace osu.Game.Graphics } } - private Vector2 rotatePosition(Vector2 pos, Vector2 centre, float angle) + private Vector2 transformPosition(Vector2 pos, Vector2 centre, float angle) { float cos = MathF.Cos(angle); float sin = MathF.Sin(angle); From c4886be7e1132ed189dbc400db3930cb3c218b11 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Tue, 14 Sep 2021 00:36:01 +0200 Subject: [PATCH 040/161] Add `StarBreakAdditive` config support --- .../Skinning/Legacy/LegacyCursorParticles.cs | 7 +++++-- osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 8dc486285b..a2ee9afff1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets.Osu.UI; using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { @@ -36,6 +37,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private void load(ISkinSource skin, OsuColour colours) { var texture = skin.GetTexture("star2"); + var starBreakAdditive = skin.GetConfig(OsuSkinColour.StarBreakAdditive)?.Value ?? new Color4(255, 182, 193, 255); + if (texture == null) return; @@ -47,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Colour = colours.PinkLighter, + Colour = starBreakAdditive, Direction = SpewDirection.None, Active = { @@ -58,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Colour = colours.PinkLighter, + Colour = starBreakAdditive, Direction = SpewDirection.None, Active = { diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs b/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs index f7ba8b9fc4..24f9217a5f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs @@ -9,5 +9,6 @@ namespace osu.Game.Rulesets.Osu.Skinning SliderBorder, SliderBall, SpinnerBackground, + StarBreakAdditive, } } From d13ff12a3e4cb0218f1aa1560b9439354aea0353 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Tue, 14 Sep 2021 00:36:52 +0200 Subject: [PATCH 041/161] Remove hardcoded particle scale --- .../Skinning/Legacy/LegacyCursorParticles.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index a2ee9afff1..ccccd1810c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -39,11 +39,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy var texture = skin.GetTexture("star2"); var starBreakAdditive = skin.GetConfig(OsuSkinColour.StarBreakAdditive)?.Value ?? new Color4(255, 182, 193, 255); - if (texture == null) - return; - - texture.ScaleAdjust = 3.2f; - InternalChildren = new[] { breakSpewer = new LegacyCursorParticleSpewer(texture, 20) From 178a3d1132801dbe0d0e6725def89622cc48932d Mon Sep 17 00:00:00 2001 From: MBmasher Date: Tue, 14 Sep 2021 10:23:11 +1000 Subject: [PATCH 042/161] Remove redundant check --- .../Difficulty/Skills/Flashlight.cs | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index f6760235b4..abd900a80d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -34,33 +34,29 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills double scalingFactor = 52.0 / osuHitObject.Radius; double smallDistNerf = 1.0; + double cumulativeStrainTime = 0.0; double result = 0.0; - if (Previous.Count > 0) + for (int i = 0; i < Previous.Count; i++) { - double cumulativeStrainTime = 0.0; + var osuPrevious = (OsuDifficultyHitObject)Previous[i]; + var osuPreviousHitObject = (OsuHitObject)(osuPrevious.BaseObject); - for (int i = 0; i < Previous.Count; i++) + if (!(osuPrevious.BaseObject is Spinner)) { - var osuPrevious = (OsuDifficultyHitObject)Previous[i]; - var osuPreviousHitObject = (OsuHitObject)(osuPrevious.BaseObject); + double jumpDistance = (osuHitObject.StackedPosition - osuPreviousHitObject.EndPosition).Length; - if (!(osuPrevious.BaseObject is Spinner)) - { - double jumpDistance = (osuHitObject.StackedPosition - osuPreviousHitObject.EndPosition).Length; + cumulativeStrainTime += osuPrevious.StrainTime; - cumulativeStrainTime += osuPrevious.StrainTime; + // We want to nerf objects that can be easily seen within the Flashlight circle radius. + if (i == 0) + smallDistNerf = Math.Min(1.0, jumpDistance / 75.0); - // We want to nerf objects that can be easily seen within the Flashlight circle radius. - if (i == 0) - smallDistNerf = Math.Min(1.0, jumpDistance / 75.0); + // We also want to nerf stacks so that only the first object of the stack is accounted for. + double stackNerf = Math.Min(1.0, (osuPrevious.JumpDistance / scalingFactor) / 25.0); - // We also want to nerf stacks so that only the first object of the stack is accounted for. - double stackNerf = Math.Min(1.0, (osuPrevious.JumpDistance / scalingFactor) / 25.0); - - result += Math.Pow(0.8, i) * stackNerf * scalingFactor * jumpDistance / cumulativeStrainTime; - } + result += Math.Pow(0.8, i) * stackNerf * scalingFactor * jumpDistance / cumulativeStrainTime; } } From c4fbae136a8c4e53785227a30cd9d92323d06376 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Tue, 14 Sep 2021 10:34:21 +1000 Subject: [PATCH 043/161] Rename FlashlightStrain to FlashlightRating --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 1e870dac68..ac77a93239 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public double AimStrain { get; set; } public double SpeedStrain { get; set; } - public double FlashlightStrain { get; set; } + public double FlashlightRating { get; set; } public double ApproachRate { get; set; } public double OverallDifficulty { get; set; } public int HitCircleCount { get; set; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index b0dd4dc9b0..28b2174071 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty Mods = mods, AimStrain = aimRating, SpeedStrain = speedRating, - FlashlightStrain = flashlightRating, + FlashlightRating = flashlightRating, ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5, OverallDifficulty = (80 - hitWindowGreat) / 6, MaxCombo = maxCombo, diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index f9a3423eab..bf4d92652c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -193,7 +193,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (!mods.Any(h => h is OsuModFlashlight)) return 0.0; - double rawFlashlight = Attributes.FlashlightStrain; + double rawFlashlight = Attributes.FlashlightRating; if (mods.Any(m => m is OsuModTouchDevice)) rawFlashlight = Math.Pow(rawFlashlight, 0.8); From 67750e6e1a1e0b99091c0f893fd129972df6d4a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 14 Sep 2021 15:08:43 +0900 Subject: [PATCH 044/161] Fix subsequent navigation tests failing due to escape key not being released --- osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 2c416ee758..aeb800f58a 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -418,6 +418,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Hold escape", () => InputManager.PressKey(Key.Escape)); AddUntilStep("Wait for intro", () => Game.ScreenStack.CurrentScreen is IntroTriangles); + AddStep("Release escape", () => InputManager.ReleaseKey(Key.Escape)); AddUntilStep("Wait for game exit", () => Game.ScreenStack.CurrentScreen == null); AddStep("test dispose doesn't crash", () => Game.Dispose()); } From 63aa3ddcba2ba2d1681c67e1d510ce245a079ef8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 Sep 2021 17:45:23 +0900 Subject: [PATCH 045/161] Add animation support for mania notes --- .../Legacy/LegacyHoldNoteHeadPiece.cs | 8 +++--- .../Legacy/LegacyHoldNoteTailPiece.cs | 10 +++---- .../Skinning/Legacy/LegacyNotePiece.cs | 26 +++++++++++++------ osu.Game/Skinning/LegacySkinExtensions.cs | 3 +++ 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs index 21e5bdd5d6..1e75533442 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs @@ -1,18 +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.Framework.Graphics.Textures; +using osu.Framework.Graphics; using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyHoldNoteHeadPiece : LegacyNotePiece { - protected override Texture GetTexture(ISkinSource skin) + protected override Drawable GetAnimation(ISkinSource skin) { // TODO: Should fallback to the head from default legacy skin instead of note. - return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage) - ?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage); + return GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage) + ?? GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage); } } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs index 232b47ae27..e6d4291d79 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; -using osu.Framework.Graphics.Textures; +using osu.Framework.Graphics; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; @@ -18,12 +18,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy : new ValueChangedEvent(ScrollingDirection.Up, ScrollingDirection.Up)); } - protected override Texture GetTexture(ISkinSource skin) + protected override Drawable GetAnimation(ISkinSource skin) { // TODO: Should fallback to the head from default legacy skin instead of note. - return GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteTailImage) - ?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage) - ?? GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage); + return GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteTailImage) + ?? GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage) + ?? GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage); } } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs index 31279796ce..e8ff1c23f3 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.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 JetBrains.Annotations; 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.OpenGL.Textures; using osu.Framework.Graphics.Sprites; @@ -19,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy private readonly IBindable direction = new Bindable(); private Container directionContainer; - private Sprite noteSprite; + private Drawable noteAnimation; private float? minimumColumnWidth; @@ -39,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = noteSprite = new Sprite { Texture = GetTexture(skin) } + Child = noteAnimation = GetAnimation(skin) }; direction.BindTo(scrollingInfo.Direction); @@ -50,12 +52,18 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { base.Update(); - if (noteSprite.Texture != null) + Texture texture = null; + + if (noteAnimation is Sprite sprite) + texture = sprite.Texture; + else if (noteAnimation is TextureAnimation textureAnimation) + texture = textureAnimation.CurrentFrame; + + if (texture != null) { // The height is scaled to the minimum column width, if provided. float minimumWidth = minimumColumnWidth ?? DrawWidth; - - noteSprite.Scale = Vector2.Divide(new Vector2(DrawWidth, minimumWidth), noteSprite.Texture.DisplayWidth); + noteAnimation.Scale = Vector2.Divide(new Vector2(DrawWidth, minimumWidth), texture.DisplayWidth); } } @@ -73,9 +81,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } } - protected virtual Texture GetTexture(ISkinSource skin) => GetTextureFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage); + [CanBeNull] + protected virtual Drawable GetAnimation(ISkinSource skin) => GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage); - protected Texture GetTextureFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup) + [CanBeNull] + protected Drawable GetAnimationFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup) { string suffix = string.Empty; @@ -93,7 +103,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy string noteImage = GetColumnSkinConfig(skin, lookup)?.Value ?? $"mania-note{FallbackColumnIndex}{suffix}"; - return skin.GetTexture(noteImage, WrapMode.ClampToEdge, WrapMode.ClampToEdge); + return skin.GetAnimation(noteImage, WrapMode.ClampToEdge, WrapMode.ClampToEdge, true, true); } } } diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index ec25268be4..fd1f905868 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -17,10 +18,12 @@ namespace osu.Game.Skinning { public static class LegacySkinExtensions { + [CanBeNull] public static Drawable GetAnimation(this ISkin source, string componentName, bool animatable, bool looping, bool applyConfigFrameRate = false, string animationSeparator = "-", bool startAtCurrentTime = true, double? frameLength = null) => source.GetAnimation(componentName, default, default, animatable, looping, applyConfigFrameRate, animationSeparator, startAtCurrentTime, frameLength); + [CanBeNull] public static Drawable GetAnimation(this ISkin source, string componentName, WrapMode wrapModeS, WrapMode wrapModeT, bool animatable, bool looping, bool applyConfigFrameRate = false, string animationSeparator = "-", bool startAtCurrentTime = true, double? frameLength = null) From c009e1473ddf319d2229a03bcab7e80e55356ad3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 Sep 2021 17:47:12 +0900 Subject: [PATCH 046/161] Add extra safety check --- osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs index e8ff1c23f3..bbc7520bac 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy if (noteAnimation is Sprite sprite) texture = sprite.Texture; - else if (noteAnimation is TextureAnimation textureAnimation) + else if (noteAnimation is TextureAnimation textureAnimation && textureAnimation.FrameCount > 0) texture = textureAnimation.CurrentFrame; if (texture != null) From b9193aae6dcec54c1e5ff1a51f6863e240de7c74 Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Tue, 14 Sep 2021 17:37:57 +0300 Subject: [PATCH 047/161] Make IOsuScreen.AllowTrackAdjustments nullable Allows for inheriting value from the previous screen if undefined --- osu.Game/OsuGame.cs | 29 +++++++++++++++++-- .../Maintenance/DirectorySelectScreen.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/IOsuScreen.cs | 3 +- osu.Game/Screens/Import/FileImportScreen.cs | 2 +- osu.Game/Screens/Menu/MainMenu.cs | 2 +- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Screens/OnlinePlay/OnlinePlayScreen.cs | 2 +- .../Screens/OnlinePlay/OnlinePlaySubScreen.cs | 2 ++ osu.Game/Screens/OsuScreen.cs | 2 +- osu.Game/Screens/Play/Player.cs | 2 +- .../Play/ScreenWithBeatmapBackground.cs | 2 ++ osu.Game/Screens/StartupScreen.cs | 2 +- 13 files changed, 42 insertions(+), 12 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 2107b3a0e9..c6a07bbbba 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1075,8 +1075,6 @@ namespace osu.Game OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode); API.Activity.BindTo(newOsuScreen.Activity); - MusicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments; - if (newOsuScreen.HideOverlaysOnEnter) CloseAllOverlays(); else @@ -1093,6 +1091,24 @@ namespace osu.Game { ScreenChanged(lastScreen, newScreen); Logger.Log($"Screen changed → {newScreen}"); + + // set AllowTrackAdjustments if new screen defines it, inherit otherwise + if (newScreen is IOsuScreen newOsuScreen && newOsuScreen.AllowTrackAdjustments.HasValue) + { + allowTrackAdjustmentsStack.Push(newOsuScreen.AllowTrackAdjustments.Value); + Logger.Log($"Screen's AllowTrackAdjustments explicit → {allowTrackAdjustmentsStack.First()}"); + } + else if (allowTrackAdjustmentsStack.Any()) + { + allowTrackAdjustmentsStack.Push(allowTrackAdjustmentsStack.First()); + Logger.Log($"Screen's AllowTrackAdjustments inherit → {allowTrackAdjustmentsStack.First()}"); + } + else + { + allowTrackAdjustmentsStack.Push(false); + } + + MusicController.AllowTrackAdjustments = allowTrackAdjustmentsStack.First(); } private void screenExited(IScreen lastScreen, IScreen newScreen) @@ -1102,8 +1118,17 @@ namespace osu.Game if (newScreen == null) Exit(); + + if (allowTrackAdjustmentsStack.Count > 1) + { + allowTrackAdjustmentsStack.Pop(); + MusicController.AllowTrackAdjustments = allowTrackAdjustmentsStack.First(); + Logger.Log($"Screen's AllowTrackAdjustments return ← {allowTrackAdjustmentsStack.First()}"); + } } + private Stack allowTrackAdjustmentsStack = new Stack(); + IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying; } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs index 1d67968ab1..6d0e79e2c7 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private OsuDirectorySelector directorySelector; - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; /// /// Text to display in the header to inform the user of what they are selecting. diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 28ae7e620e..13e4a11915 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Edit public override bool DisallowExternalBeatmapRulesetChanges => true; - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; protected bool HasUnsavedChanges => lastSavedHash != changeHandler.CurrentStateHash; diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs index 17384c161c..a1e4d9ed01 100644 --- a/osu.Game/Screens/IOsuScreen.cs +++ b/osu.Game/Screens/IOsuScreen.cs @@ -60,8 +60,9 @@ namespace osu.Game.Screens /// /// Whether mod track adjustments are allowed to be applied. + /// Null means to inherit from the parent screen. /// - bool AllowTrackAdjustments { get; } + bool? AllowTrackAdjustments { get; } /// /// Invoked when the back button has been pressed to close any overlays before exiting this . diff --git a/osu.Game/Screens/Import/FileImportScreen.cs b/osu.Game/Screens/Import/FileImportScreen.cs index 606174193d..69fcf31876 100644 --- a/osu.Game/Screens/Import/FileImportScreen.cs +++ b/osu.Game/Screens/Import/FileImportScreen.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Import { public override bool HideOverlaysOnEnter => true; - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; private OsuFileSelector fileSelector; private Container contentContainer; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 8b2ec43e3e..00885a91c5 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Menu public override bool AllowExternalScreenChange => true; - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; private Screen songSelect; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index bf7c738882..c45e3a79da 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public override bool DisallowExternalBeatmapRulesetChanges => true; // We are managing our own adjustments. For now, this happens inside the Player instances themselves. - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; /// /// Whether all spectating players have finished loading. diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 62bfd2cfed..e3945c9cac 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay [Cached] protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; public override bool CursorVisible => (screenStack?.CurrentScreen as IOnlinePlaySubScreen)?.CursorVisible ?? true; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index 3411c4afb1..8c4f0c1394 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -11,6 +11,8 @@ namespace osu.Game.Screens.OnlinePlay { public override bool DisallowExternalBeatmapRulesetChanges => false; + public override bool? AllowTrackAdjustments => true; + public virtual string ShortTitle => Title; [Resolved(CanBeNull = true)] diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 9aec2a5c19..78908b5d8a 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -81,7 +81,7 @@ namespace osu.Game.Screens public virtual float BackgroundParallaxAmount => 1; - public virtual bool AllowTrackAdjustments => true; + public virtual bool? AllowTrackAdjustments => null; public Bindable Beatmap { get; private set; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e8a2790c94..9927467bd6 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered; // We are managing our own adjustments (see OnEntering/OnExiting). - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; private readonly IBindable gameActive = new Bindable(true); diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index 88dab88d42..9bec320e22 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -10,6 +10,8 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); + public override bool? AllowTrackAdjustments => true; + public void ApplyToBackground(Action action) => base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b)); } } diff --git a/osu.Game/Screens/StartupScreen.cs b/osu.Game/Screens/StartupScreen.cs index 15f75d7cff..7b73d36fdf 100644 --- a/osu.Game/Screens/StartupScreen.cs +++ b/osu.Game/Screens/StartupScreen.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens public override bool CursorVisible => false; - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; } From 01d2f4f17a98bfb372410838eb8159c260b6fa8a Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Tue, 14 Sep 2021 18:04:43 +0300 Subject: [PATCH 048/161] Make `allowTrackAdjustmentsStack` readonly --- 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 c6a07bbbba..5f1b2ac87d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1127,7 +1127,7 @@ namespace osu.Game } } - private Stack allowTrackAdjustmentsStack = new Stack(); + private readonly Stack allowTrackAdjustmentsStack = new Stack(); IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying; } From bd18c581c11a6437a9a055ae4b267425d8463d6f Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Tue, 14 Sep 2021 21:14:24 +0300 Subject: [PATCH 049/161] Replace `allowTrackAdjustmentsStack` with a Dictionary --- osu.Game/OsuGame.cs | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 5f1b2ac87d..499b561718 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1094,21 +1094,13 @@ namespace osu.Game // set AllowTrackAdjustments if new screen defines it, inherit otherwise if (newScreen is IOsuScreen newOsuScreen && newOsuScreen.AllowTrackAdjustments.HasValue) - { - allowTrackAdjustmentsStack.Push(newOsuScreen.AllowTrackAdjustments.Value); - Logger.Log($"Screen's AllowTrackAdjustments explicit → {allowTrackAdjustmentsStack.First()}"); - } - else if (allowTrackAdjustmentsStack.Any()) - { - allowTrackAdjustmentsStack.Push(allowTrackAdjustmentsStack.First()); - Logger.Log($"Screen's AllowTrackAdjustments inherit → {allowTrackAdjustmentsStack.First()}"); - } + allowTrackAdjustmentsDict[newScreen] = newOsuScreen.AllowTrackAdjustments.Value; + else if (allowTrackAdjustmentsDict.ContainsKey(lastScreen)) + allowTrackAdjustmentsDict[newScreen] = allowTrackAdjustmentsDict[lastScreen]; else - { - allowTrackAdjustmentsStack.Push(false); - } + allowTrackAdjustmentsDict[newScreen] = true; - MusicController.AllowTrackAdjustments = allowTrackAdjustmentsStack.First(); + MusicController.AllowTrackAdjustments = allowTrackAdjustmentsDict[newScreen]; } private void screenExited(IScreen lastScreen, IScreen newScreen) @@ -1116,18 +1108,15 @@ namespace osu.Game ScreenChanged(lastScreen, newScreen); Logger.Log($"Screen changed ← {newScreen}"); + allowTrackAdjustmentsDict.Remove(lastScreen); + if (newScreen == null) Exit(); - - if (allowTrackAdjustmentsStack.Count > 1) - { - allowTrackAdjustmentsStack.Pop(); - MusicController.AllowTrackAdjustments = allowTrackAdjustmentsStack.First(); - Logger.Log($"Screen's AllowTrackAdjustments return ← {allowTrackAdjustmentsStack.First()}"); - } + else + MusicController.AllowTrackAdjustments = allowTrackAdjustmentsDict[newScreen]; } - private readonly Stack allowTrackAdjustmentsStack = new Stack(); + private readonly Dictionary allowTrackAdjustmentsDict = new Dictionary(); IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying; } From 34bde293abebbe144c6e7ab425aa874af8289da2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 15 Sep 2021 13:26:39 +0900 Subject: [PATCH 050/161] Fix tests --- osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs index bbc7520bac..321a87f8b1 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs @@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy private readonly IBindable direction = new Bindable(); private Container directionContainer; + + [CanBeNull] private Drawable noteAnimation; private float? minimumColumnWidth; @@ -41,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = noteAnimation = GetAnimation(skin) + Child = noteAnimation = GetAnimation(skin) ?? Empty() }; direction.BindTo(scrollingInfo.Direction); From 8217b90b1cb71f793a25e31dc644794da4b1d189 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 5 Sep 2021 00:41:34 +0300 Subject: [PATCH 051/161] Consider legacy glyph texture heights as the baselines for simplicity Mixing `LegacySpriteText` with legitment fonts should never be the case, so it's fine to consuder the height as the baseline, since there's really no other way around it. --- osu.Game/Skinning/LegacySpriteText.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacySpriteText.cs b/osu.Game/Skinning/LegacySpriteText.cs index 7895fcccca..8fc6cbde7d 100644 --- a/osu.Game/Skinning/LegacySpriteText.cs +++ b/osu.Game/Skinning/LegacySpriteText.cs @@ -56,7 +56,7 @@ namespace osu.Game.Skinning if (texture == null) return null; - return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture.Width, null), texture, 1f / texture.ScaleAdjust); + return new TexturedCharacterGlyph(new CharacterGlyph(character, 0, 0, texture.Width, texture.Height, null), texture, 1f / texture.ScaleAdjust); } private static string getLookupName(char character) From b87af3dd68e3de7b19483210e6d94437a6a6c651 Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Wed, 15 Sep 2021 10:55:16 +0300 Subject: [PATCH 052/161] Move the inherited `AllowTrackAdjustments` into `OsuScreen` --- osu.Game/OsuGame.cs | 21 +++++---------------- osu.Game/Screens/IOsuScreen.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 8 +++++++- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 499b561718..f2f925a778 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1075,6 +1075,11 @@ namespace osu.Game OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode); API.Activity.BindTo(newOsuScreen.Activity); + if (newOsuScreen.AllowTrackAdjustments.HasValue) + MusicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments.Value; + else + newOsuScreen.AllowTrackAdjustments = MusicController.AllowTrackAdjustments; + if (newOsuScreen.HideOverlaysOnEnter) CloseAllOverlays(); else @@ -1091,16 +1096,6 @@ namespace osu.Game { ScreenChanged(lastScreen, newScreen); Logger.Log($"Screen changed → {newScreen}"); - - // set AllowTrackAdjustments if new screen defines it, inherit otherwise - if (newScreen is IOsuScreen newOsuScreen && newOsuScreen.AllowTrackAdjustments.HasValue) - allowTrackAdjustmentsDict[newScreen] = newOsuScreen.AllowTrackAdjustments.Value; - else if (allowTrackAdjustmentsDict.ContainsKey(lastScreen)) - allowTrackAdjustmentsDict[newScreen] = allowTrackAdjustmentsDict[lastScreen]; - else - allowTrackAdjustmentsDict[newScreen] = true; - - MusicController.AllowTrackAdjustments = allowTrackAdjustmentsDict[newScreen]; } private void screenExited(IScreen lastScreen, IScreen newScreen) @@ -1108,16 +1103,10 @@ namespace osu.Game ScreenChanged(lastScreen, newScreen); Logger.Log($"Screen changed ← {newScreen}"); - allowTrackAdjustmentsDict.Remove(lastScreen); - if (newScreen == null) Exit(); - else - MusicController.AllowTrackAdjustments = allowTrackAdjustmentsDict[newScreen]; } - private readonly Dictionary allowTrackAdjustmentsDict = new Dictionary(); - IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying; } } diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs index a1e4d9ed01..262bbfedc6 100644 --- a/osu.Game/Screens/IOsuScreen.cs +++ b/osu.Game/Screens/IOsuScreen.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens /// Whether mod track adjustments are allowed to be applied. /// Null means to inherit from the parent screen. /// - bool? AllowTrackAdjustments { get; } + bool? AllowTrackAdjustments { set; get; } /// /// Invoked when the back button has been pressed to close any overlays before exiting this . diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 78908b5d8a..0deaa3e80e 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -81,7 +81,13 @@ namespace osu.Game.Screens public virtual float BackgroundParallaxAmount => 1; - public virtual bool? AllowTrackAdjustments => null; + private bool? allowTrackAdjustments = null; + + public virtual bool? AllowTrackAdjustments + { + set => allowTrackAdjustments = value; + get => allowTrackAdjustments; + } public Bindable Beatmap { get; private set; } From 48cf98ef9325cfd40fca7ab91bb50cc102517c53 Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Wed, 15 Sep 2021 11:00:49 +0300 Subject: [PATCH 053/161] Rephrase null meaning in `IOsuScreen.AllowTrackAdjustments` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Screens/IOsuScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs index 262bbfedc6..735853e462 100644 --- a/osu.Game/Screens/IOsuScreen.cs +++ b/osu.Game/Screens/IOsuScreen.cs @@ -60,7 +60,7 @@ namespace osu.Game.Screens /// /// Whether mod track adjustments are allowed to be applied. - /// Null means to inherit from the parent screen. + /// A value means that the parent screen's value of this setting will be used. /// bool? AllowTrackAdjustments { set; get; } From 9b101ea9eb6576d7d579150ce90eb887ff61f6e8 Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Wed, 15 Sep 2021 11:40:23 +0300 Subject: [PATCH 054/161] Add a test for `AllowTrackAdjustments` --- .../Menus/TestSceneMusicActionHandling.cs | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs index 9037338e23..50226ae2e2 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs @@ -9,6 +9,7 @@ using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Input.Bindings; using osu.Game.Overlays; +using osu.Game.Screens; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Menus @@ -79,5 +80,55 @@ namespace osu.Game.Tests.Visual.Menus trackChangeQueue.Count == 1 && trackChangeQueue.Dequeue().changeDirection == TrackChangeDirection.Next); } + + [Test] + public void TestAllowTrackAdjustments() + { + AddStep("push allowing screen", () => Game.ScreenStack.Push(new AllowScreen())); + AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); + + AddStep("push inheriting screen", () => Game.ScreenStack.Push(new InheritScreen())); + AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); + + AddStep("push disallowing screen", () => Game.ScreenStack.Push(new DisallowScreen())); + AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); + + AddStep("push inheriting screen", () => Game.ScreenStack.Push(new InheritScreen())); + AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); + + AddStep("push inheriting screen", () => Game.ScreenStack.Push(new InheritScreen())); + AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); + + AddStep("push allowing screen", () => Game.ScreenStack.Push(new AllowScreen())); + AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); + + // Now start exiting from screens + AddStep("exit screen", () => Game.ScreenStack.Exit()); + AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); + + AddStep("exit screen", () => Game.ScreenStack.Exit()); + AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); + + AddStep("exit screen", () => Game.ScreenStack.Exit()); + AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); + + AddStep("exit screen", () => Game.ScreenStack.Exit()); + AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); + + AddStep("exit screen", () => Game.ScreenStack.Exit()); + AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); + } + + private class AllowScreen : OsuScreen + { + public override bool? AllowTrackAdjustments => true; + } + + private class DisallowScreen : OsuScreen + { + public override bool? AllowTrackAdjustments => false; + } + + private class InheritScreen : OsuScreen { } } } From 1181317c729455c2e81b409933c37167e84d55df Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Wed, 15 Sep 2021 12:01:56 +0300 Subject: [PATCH 055/161] Fix issues found by code quality ci --- .../Visual/Menus/TestSceneMusicActionHandling.cs | 4 +++- osu.Game/Screens/IOsuScreen.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 8 +------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs index 50226ae2e2..79acaedb73 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs @@ -129,6 +129,8 @@ namespace osu.Game.Tests.Visual.Menus public override bool? AllowTrackAdjustments => false; } - private class InheritScreen : OsuScreen { } + private class InheritScreen : OsuScreen + { + } } } diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs index 735853e462..fd884586d1 100644 --- a/osu.Game/Screens/IOsuScreen.cs +++ b/osu.Game/Screens/IOsuScreen.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens /// Whether mod track adjustments are allowed to be applied. /// A value means that the parent screen's value of this setting will be used. /// - bool? AllowTrackAdjustments { set; get; } + bool? AllowTrackAdjustments { get; set; } /// /// Invoked when the back button has been pressed to close any overlays before exiting this . diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 0deaa3e80e..9b4d7f9eda 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -81,13 +81,7 @@ namespace osu.Game.Screens public virtual float BackgroundParallaxAmount => 1; - private bool? allowTrackAdjustments = null; - - public virtual bool? AllowTrackAdjustments - { - set => allowTrackAdjustments = value; - get => allowTrackAdjustments; - } + public virtual bool? AllowTrackAdjustments { get; set; } public Bindable Beatmap { get; private set; } From 33e1273df8095a1afb0a64950d82d13e79a55475 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Wed, 15 Sep 2021 19:03:42 +1000 Subject: [PATCH 056/161] Include Flashlight in total SR calculation --- .../Difficulty/OsuDifficultyCalculator.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index da879cb02e..5087da6153 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -37,7 +37,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty 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; - double basePerformance = Math.Pow(Math.Pow(baseAimPerformance, 1.1) + Math.Pow(baseSpeedPerformance, 1.1), 1 / 1.1); + double baseFlashlightPerformance = 0.0; + if (mods.Any(h => h is OsuModFlashlight)) + baseFlashlightPerformance = Math.Pow(flashlightRating, 2.0) * 25.0; + double basePerformance = + Math.Pow( + Math.Pow(baseAimPerformance, 1.1) + + Math.Pow(baseSpeedPerformance, 1.1) + + 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; HitWindows hitWindows = new OsuHitWindows(); @@ -95,6 +103,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty new OsuModHalfTime(), new OsuModEasy(), new OsuModHardRock(), + new OsuModFlashlight(), }; } -} +} \ No newline at end of file From a8539bc75b6e88589fa16619b729a13c73611fcf Mon Sep 17 00:00:00 2001 From: MBmasher Date: Wed, 15 Sep 2021 19:04:36 +1000 Subject: [PATCH 057/161] Add newline to end of file --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 5087da6153..411140c756 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -106,4 +106,4 @@ namespace osu.Game.Rulesets.Osu.Difficulty new OsuModFlashlight(), }; } -} \ No newline at end of file +} From 07fec268c028dc65b43f38a2cde6da8fe77cd212 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 15 Sep 2021 18:32:52 +0900 Subject: [PATCH 058/161] Limit maximum triangles to avoid GL buffer overflow --- osu.Game/Graphics/Backgrounds/Triangles.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 35c48a50d0..ab8763e576 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -13,6 +13,7 @@ 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.Lists; @@ -181,7 +182,10 @@ namespace osu.Game.Graphics.Backgrounds private void addTriangles(bool randomY) { - AimCount = (int)(DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio); + // limited by the maximum size of QuadVertexBuffer for safety. + const int max_triangles = QuadVertexBuffer.MAX_QUADS; + + 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)); From f0439ef50b0dd9217e43508217b34c0e47dcba7b Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Wed, 15 Sep 2021 13:12:57 +0300 Subject: [PATCH 059/161] Remove unnecessary `AllowTrackAdjustments` overrides, add true to `SongSelect` --- .../Settings/Sections/Maintenance/DirectorySelectScreen.cs | 2 -- osu.Game/Screens/Import/FileImportScreen.cs | 2 -- osu.Game/Screens/Menu/MainMenu.cs | 2 -- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 2 -- osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs | 2 -- osu.Game/Screens/Select/SongSelect.cs | 2 ++ osu.Game/Screens/StartupScreen.cs | 2 -- 7 files changed, 2 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs index 6d0e79e2c7..e509cac2f1 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs @@ -24,8 +24,6 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private OsuDirectorySelector directorySelector; - public override bool? AllowTrackAdjustments => false; - /// /// Text to display in the header to inform the user of what they are selecting. /// diff --git a/osu.Game/Screens/Import/FileImportScreen.cs b/osu.Game/Screens/Import/FileImportScreen.cs index 69fcf31876..7e1d55b3e2 100644 --- a/osu.Game/Screens/Import/FileImportScreen.cs +++ b/osu.Game/Screens/Import/FileImportScreen.cs @@ -23,8 +23,6 @@ namespace osu.Game.Screens.Import { public override bool HideOverlaysOnEnter => true; - public override bool? AllowTrackAdjustments => false; - private OsuFileSelector fileSelector; private Container contentContainer; private TextFlowContainer currentFileText; diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 00885a91c5..221b31f855 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -36,8 +36,6 @@ namespace osu.Game.Screens.Menu public override bool AllowExternalScreenChange => true; - public override bool? AllowTrackAdjustments => false; - private Screen songSelect; private MenuSideFlashes sideFlashes; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index e3945c9cac..fc20b21b60 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -24,8 +24,6 @@ namespace osu.Game.Screens.OnlinePlay [Cached] protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); - public override bool? AllowTrackAdjustments => false; - public override bool CursorVisible => (screenStack?.CurrentScreen as IOnlinePlaySubScreen)?.CursorVisible ?? true; // this is required due to PlayerLoader eventually being pushed to the main stack diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index 9bec320e22..88dab88d42 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -10,8 +10,6 @@ namespace osu.Game.Screens.Play { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); - public override bool? AllowTrackAdjustments => true; - public void ApplyToBackground(Action action) => base.ApplyToBackground(b => action.Invoke((BackgroundScreenBeatmap)b)); } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index f11f9fd614..1f0f134ba7 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -53,6 +53,8 @@ namespace osu.Game.Screens.Select protected virtual bool DisplayStableImportPrompt => stableImportManager?.SupportsImportFromStable == true; + public override bool? AllowTrackAdjustments => true; + /// /// Can be null if is false. /// diff --git a/osu.Game/Screens/StartupScreen.cs b/osu.Game/Screens/StartupScreen.cs index 7b73d36fdf..be217d6b1f 100644 --- a/osu.Game/Screens/StartupScreen.cs +++ b/osu.Game/Screens/StartupScreen.cs @@ -16,8 +16,6 @@ namespace osu.Game.Screens public override bool CursorVisible => false; - public override bool? AllowTrackAdjustments => false; - protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled; } } From 318f0941ca8f53af7bff53cc8ce54226f8a0fbba Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Wed, 15 Sep 2021 21:25:39 +0300 Subject: [PATCH 060/161] Move all the "inherit previous `AllowTrackAdjustments`" logic into `OsuScreen` --- osu.Game/OsuGame.cs | 5 +---- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/IOsuScreen.cs | 2 +- .../Multiplayer/Spectate/MultiSpectatorScreen.cs | 2 +- osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 7 ++++++- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- 8 files changed, 13 insertions(+), 11 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f2f925a778..2107b3a0e9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1075,10 +1075,7 @@ namespace osu.Game OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode); API.Activity.BindTo(newOsuScreen.Activity); - if (newOsuScreen.AllowTrackAdjustments.HasValue) - MusicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments.Value; - else - newOsuScreen.AllowTrackAdjustments = MusicController.AllowTrackAdjustments; + MusicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments; if (newOsuScreen.HideOverlaysOnEnter) CloseAllOverlays(); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 028662172d..5bb47e1c11 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Edit public override bool DisallowExternalBeatmapRulesetChanges => true; - public override bool? AllowTrackAdjustments => false; + public override bool AllowTrackAdjustments => false; protected bool HasUnsavedChanges => lastSavedHash != changeHandler.CurrentStateHash; diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs index fd884586d1..b12baf233f 100644 --- a/osu.Game/Screens/IOsuScreen.cs +++ b/osu.Game/Screens/IOsuScreen.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens /// Whether mod track adjustments are allowed to be applied. /// A value means that the parent screen's value of this setting will be used. /// - bool? AllowTrackAdjustments { get; set; } + bool AllowTrackAdjustments { get; } /// /// Invoked when the back button has been pressed to close any overlays before exiting this . diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index c45e3a79da..bf7c738882 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public override bool DisallowExternalBeatmapRulesetChanges => true; // We are managing our own adjustments. For now, this happens inside the Player instances themselves. - public override bool? AllowTrackAdjustments => false; + public override bool AllowTrackAdjustments => false; /// /// Whether all spectating players have finished loading. diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index 8c4f0c1394..054009a228 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.OnlinePlay { public override bool DisallowExternalBeatmapRulesetChanges => false; - public override bool? AllowTrackAdjustments => true; + public override bool AllowTrackAdjustments => true; public virtual string ShortTitle => Title; diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 9b4d7f9eda..01dc703b66 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -81,7 +81,12 @@ namespace osu.Game.Screens public virtual float BackgroundParallaxAmount => 1; - public virtual bool? AllowTrackAdjustments { get; set; } + [Resolved] + private MusicController musicController { get; set; } + + private bool? allowTrackAdjustments; + + public virtual bool AllowTrackAdjustments => allowTrackAdjustments ??= (musicController?.AllowTrackAdjustments ?? false); public Bindable Beatmap { get; private set; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9927467bd6..e8a2790c94 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered; // We are managing our own adjustments (see OnEntering/OnExiting). - public override bool? AllowTrackAdjustments => false; + public override bool AllowTrackAdjustments => false; private readonly IBindable gameActive = new Bindable(true); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 1f0f134ba7..9b6cbad7d1 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Select protected virtual bool DisplayStableImportPrompt => stableImportManager?.SupportsImportFromStable == true; - public override bool? AllowTrackAdjustments => true; + public override bool AllowTrackAdjustments => true; /// /// Can be null if is false. From 30c458c662e403bcadaf25a8ac975242989ba35a Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Wed, 15 Sep 2021 21:34:41 +0300 Subject: [PATCH 061/161] Oops, fix not compiling test --- osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs index 79acaedb73..8f6ab5e755 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs @@ -121,12 +121,12 @@ namespace osu.Game.Tests.Visual.Menus private class AllowScreen : OsuScreen { - public override bool? AllowTrackAdjustments => true; + public override bool AllowTrackAdjustments => true; } private class DisallowScreen : OsuScreen { - public override bool? AllowTrackAdjustments => false; + public override bool AllowTrackAdjustments => false; } private class InheritScreen : OsuScreen From 32d65adb35c225dac77a43604012f0d426293508 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Wed, 15 Sep 2021 21:22:37 +0200 Subject: [PATCH 062/161] Fix cursor particle scale --- .../Skinning/Legacy/LegacyCursorParticles.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index ccccd1810c..73820b8df9 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -39,6 +39,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy var texture = skin.GetTexture("star2"); var starBreakAdditive = skin.GetConfig(OsuSkinColour.StarBreakAdditive)?.Value ?? new Color4(255, 182, 193, 255); + if (texture != null) + { + // stable "magic ratio". see OsuPlayfieldAdjustmentContainer for full explanation. + texture.ScaleAdjust *= 1.6f; + } + InternalChildren = new[] { breakSpewer = new LegacyCursorParticleSpewer(texture, 20) From 3cd3e133ce2a98205988c480cd44c4e61a5fae59 Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Thu, 16 Sep 2021 01:21:29 +0300 Subject: [PATCH 063/161] Move `AllowTrackAdjustments` test to `TestSceneOsuScreenStack` --- .../Menus/TestSceneMusicActionHandling.cs | 53 +----------- .../Visual/TestSceneOsuScreenStack.cs | 83 ++++++++++++++++++- 2 files changed, 80 insertions(+), 56 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs index 8f6ab5e755..bf6491cd81 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; @@ -80,57 +81,5 @@ namespace osu.Game.Tests.Visual.Menus trackChangeQueue.Count == 1 && trackChangeQueue.Dequeue().changeDirection == TrackChangeDirection.Next); } - - [Test] - public void TestAllowTrackAdjustments() - { - AddStep("push allowing screen", () => Game.ScreenStack.Push(new AllowScreen())); - AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); - - AddStep("push inheriting screen", () => Game.ScreenStack.Push(new InheritScreen())); - AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); - - AddStep("push disallowing screen", () => Game.ScreenStack.Push(new DisallowScreen())); - AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); - - AddStep("push inheriting screen", () => Game.ScreenStack.Push(new InheritScreen())); - AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); - - AddStep("push inheriting screen", () => Game.ScreenStack.Push(new InheritScreen())); - AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); - - AddStep("push allowing screen", () => Game.ScreenStack.Push(new AllowScreen())); - AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); - - // Now start exiting from screens - AddStep("exit screen", () => Game.ScreenStack.Exit()); - AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); - - AddStep("exit screen", () => Game.ScreenStack.Exit()); - AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); - - AddStep("exit screen", () => Game.ScreenStack.Exit()); - AddAssert("disallows adjustments", () => !Game.MusicController.AllowTrackAdjustments); - - AddStep("exit screen", () => Game.ScreenStack.Exit()); - AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); - - AddStep("exit screen", () => Game.ScreenStack.Exit()); - AddAssert("allows adjustments", () => Game.MusicController.AllowTrackAdjustments); - } - - private class AllowScreen : OsuScreen - { - public override bool AllowTrackAdjustments => true; - } - - private class DisallowScreen : OsuScreen - { - public override bool AllowTrackAdjustments => false; - } - - private class InheritScreen : OsuScreen - { - } } } diff --git a/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs b/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs index c55988d1bb..ed3935e101 100644 --- a/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs +++ b/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs @@ -5,8 +5,8 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Screens; -using osu.Framework.Testing; using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; using osu.Game.Screens; using osu.Game.Screens.Play; using osuTK.Graphics; @@ -18,10 +18,20 @@ namespace osu.Game.Tests.Visual { private TestOsuScreenStack stack; - [SetUpSteps] - public void SetUpSteps() + [Cached] + private MusicController musicController = new MusicController(); + + [BackgroundDependencyLoader] + private void load() { - AddStep("Create new screen stack", () => { Child = stack = new TestOsuScreenStack { RelativeSizeAxes = Axes.Both }; }); + stack = new TestOsuScreenStack { RelativeSizeAxes = Axes.Both }; + stack.ScreenPushed += screenChanged; + stack.ScreenExited += screenChanged; + + Add(musicController); + Add(stack); + + LoadComponent(stack); } [Test] @@ -42,6 +52,44 @@ namespace osu.Game.Tests.Visual AddAssert("Parallax is off", () => stack.ParallaxAmount == 0); } + [Test] + public void AllowTrackAdjustmentsTest() + { + AddStep("push allowing screen", () => stack.Push(loadNewScreen())); + AddAssert("allows adjustments 1", () => musicController.AllowTrackAdjustments); + + AddStep("push inheriting screen", () => stack.Push(loadNewScreen())); + AddAssert("allows adjustments 2", () => musicController.AllowTrackAdjustments); + + AddStep("push disallowing screen", () => stack.Push(loadNewScreen())); + AddAssert("disallows adjustments 3", () => !musicController.AllowTrackAdjustments); + + AddStep("push inheriting screen", () => stack.Push(loadNewScreen())); + AddAssert("disallows adjustments 4", () => !musicController.AllowTrackAdjustments); + + AddStep("push inheriting screen", () => stack.Push(loadNewScreen())); + AddAssert("disallows adjustments 5", () => !musicController.AllowTrackAdjustments); + + AddStep("push allowing screen", () => stack.Push(loadNewScreen())); + AddAssert("allows adjustments 6", () => musicController.AllowTrackAdjustments); + + // Now start exiting from screens + AddStep("exit screen", () => stack.Exit()); + AddAssert("disallows adjustments 7", () => !musicController.AllowTrackAdjustments); + + AddStep("exit screen", () => stack.Exit()); + AddAssert("disallows adjustments 8", () => !musicController.AllowTrackAdjustments); + + AddStep("exit screen", () => stack.Exit()); + AddAssert("disallows adjustments 9", () => !musicController.AllowTrackAdjustments); + + AddStep("exit screen", () => stack.Exit()); + AddAssert("allows adjustments 10", () => musicController.AllowTrackAdjustments); + + AddStep("exit screen", () => stack.Exit()); + AddAssert("allows adjustments 11", () => musicController.AllowTrackAdjustments); + } + public class TestScreen : ScreenWithBeatmapBackground { private readonly string screenText; @@ -78,5 +126,32 @@ namespace osu.Game.Tests.Visual { public new float ParallaxAmount => base.ParallaxAmount; } + + private class AllowScreen : OsuScreen + { + public override bool AllowTrackAdjustments => true; + } + + public class DisallowScreen : OsuScreen + { + public override bool AllowTrackAdjustments => false; + } + + private class InheritScreen : OsuScreen + { + } + + private OsuScreen loadNewScreen() where T : OsuScreen, new() + { + OsuScreen screen = new T(); + LoadComponent(screen); + return screen; + } + + private void screenChanged(IScreen current, IScreen newScreen) + { + if (newScreen is IOsuScreen newOsuScreen) + musicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments; + } } } From 9057be1a02069917e065a94290685933dd9cf73e Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Thu, 16 Sep 2021 01:30:53 +0300 Subject: [PATCH 064/161] Remove unused usings --- osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs index bf6491cd81..9037338e23 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs @@ -4,13 +4,11 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Input.Bindings; using osu.Game.Overlays; -using osu.Game.Screens; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Menus From 45b07aa362b7048ee9ceb3f31e34ad68b4399943 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 15:33:55 +0900 Subject: [PATCH 065/161] Add some basic animated textures to mania metric skin --- .../Resources/metrics-skin/mania-note1-0@2x.png | Bin 0 -> 1874 bytes .../Resources/metrics-skin/mania-note1-1@2x.png | Bin 0 -> 2828 bytes .../Resources/metrics-skin/mania-note1H-0@2x.png | Bin 0 -> 5154 bytes .../Resources/metrics-skin/mania-note1H-1@2x.png | Bin 0 -> 6025 bytes .../Resources/metrics-skin/mania-note2-0@2x.png | Bin 0 -> 1865 bytes .../Resources/metrics-skin/mania-note2-1@2x.png | Bin 0 -> 2847 bytes .../Resources/metrics-skin/mania-note2H@2x.png | Bin 0 -> 5294 bytes .../Resources/metrics-skin/mania-noteS@2x.png | Bin 0 -> 3963 bytes .../Resources/metrics-skin/mania-noteSH@2x.png | Bin 0 -> 3963 bytes 9 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1-0@2x.png create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1-1@2x.png create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1H-0@2x.png create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1H-1@2x.png create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note2-0@2x.png create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note2-1@2x.png create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note2H@2x.png create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-noteS@2x.png create mode 100644 osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-noteSH@2x.png diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1-0@2x.png b/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1-0@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2db5d76e7828a025037cbe434f15eb5737ab749f GIT binary patch literal 1874 zcmbVNeM}Q)7=K|Ub}TA!n*`?ca%75Q+_j}p?w~+zVKiH@gJw1oKd#qDXX3h3;tje?9c zQB37iguV2wQ&c(tPt9~%tb*0_I!>}QLP#};mv%{9AU)ITBFGX-fNWH;lhMMxEr(&q zY1hK@l1&PeOHVnRxn&$xP?l#Q%SuSh4rgXS>0VqUpeccXy!29r$GuuO$cu}VrGbt}$AMAAKkB#ZWKdLY0U@x>KmoWcu$?njWj>g?#Ga zy#GqfTS{FNnosepn13qL z>>$Ks!i@|s5DZBf4O&&A5D{So`?1q>hV4#bHos zw~y>PloACbxnt55gE8?_jHq}{ly;^2Y@hhWd~Y=9EZ)G)%X1x@BES#*SJI+~E8)a9 zu1D=_Jy!IQ`h}`BYgCh~qvJ-*+kamf^KD~a)6qOWg(CIn^J%g|t1R;Bkq?mR$NK8z zWm8s8v8Bq-|Fkw4M=mbZt?GU^qxM4EwqpO){r%-vGRf-t&A>dzJrhI$AOj!_WPvAg zpAc@%`tIrY-7oemi>v7^bu3Q_ObGME?n78lS9{<~O++}L8r5x?ZLLFh4|K2@a_~og z-uz4Fzj@ieC0yof@*)jF{b7s^2A}O@=6-l9_eN7XGcgLBw&^qe%w_ezei|%1zuJA_#|#`j%ZyzmY@qf`!86;i>d$AW%2l;<{TVWuZ+l_Y39&;oKWxRB z&WhuUC)I|TE%z}Y?b*SteeW>t?!|>E%|q`2bHVUQc2V~o?PODTLqSZ(CU+)v(hPy0 z>v}KnFMZNg-p?(&SmhaN8e(ReWZ_w7ufNuP`)1Pc$mMg#Hk3D_4GaAKO<`emCl<8b z=~;KL>af4Fg?8RkE(*x@bT;_n4<4C@*KBCRN+SCreOz;m(X;%Y%Y0%@grpR*|En(F z>befubAdevZ!gSfzS28?T5+00KZR{h&nGEL7LW!~t)F6g-lDOgG5&n3&)Qtt0mnT0v*p($g)g-rNDiW6aJo J?47f?;%`E8Pn`e& literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1-1@2x.png b/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1-1@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..6e7aded39f315120b9eb7c9fbac3c543faf90c22 GIT binary patch literal 2828 zcmbVOeK?bQAOCGR<@6%;R7%MXPoda5v*k4-)Nn}%#ca1(Z1>v6#u3huUa3o^S`KsS zlvJpslt|}1qG+>99^yEak-VKyt~Knr*V{RN)VZ#w{qy_%zSrmT`F_6N-}k=n?G5l- zH)p2lOaQ@J^-dN-8+>8Ap$%|%*04}@q7_Y>TK~&mxk>1VVni# z9Yh@GZ1LVyC?f#l0Sh4v1&g<1;qiD3g^Fb}qnWJeXj=>sPbA>*WE_EPhsV=MR2rF# z`S7zq(h1oyv_QJohh)gf*&R2-g&BNFWpgq@tg#(-E@42xo6 z0ftD#k}=i{CX370M{M3v7z~;ZUnFMoS&$Fi*#Z&4a=C1pyC-3-mjl5A?@3=vAb5H> zIugn54(>?U(Tn14@9~jKhgk_ch%f%gW&g#cf03&n2c7`QOoxQrM2PJrgn5{ERnxei z@#07zk-Z2MuP^F-;IcpC)5YUWww1XR)XujZ1)_M# z)69Xi*gIaWx}@q~>mGEa?N&c|*rnACC!Jfyou2OSh-rX4?CAht05H@)_y7O)YdE%B zi{=IVzGl2-%k^`lJep{`y-CmmXI3({6u~)@{A~I)j@@N@54!>qV`5%=BpXP7Q=JxU>uTp324eo6pG54ULe z{hetml}73ts)%bZI@6f2ys3BhNKfBHiTa@Luqn>S4MY`ZsYQo1TU0Nlsi{t7^81z? zL1Xr^Ws0MH6BTuY^Oq}5P&8N!xM*;K>U7BNl*TVmck8qU_gKgi)u1`4&#iWuV9g3} zw8BH%B3+(WrGwf)ZWdJks^gLOU|Qrkb%6#~kX!pm7_xs_aL+dXZ#_Yj4WoDJ=lJ}) zq|r2&9P=!B^}j}oJJuY|@I2o#R@Sht$sCn_I!L)u$r<$?a+Dp+?+jnA{LL=7s=V$` zn;HJoGEE8=@owOCwlwDx_vE`oxi(K{0^hSa9_1Q|>Sgp+`{~F?v_u%0*lj9Tr5FS2 zlH>ym?KUlP@vf-fgB*)C!b@A9)%WCj?F4R{?ZZnMi;dAh9mLgaD~l;0Sr~wOZ!<2H z#umSt|2q$D02Gpz3%IazoCdwtb}&=kPd#?3Cj+=qH$CXe-M=rG<6n)MX9$i2gj}tV zHY#Nks&{D$Zk~!QmbJ+S9Q2Z=>A#L^e^SWvmK%71!Xv@m9$T(g#wHN8S%#=|;Y+(I z@ef{itV9RreFp;8wnSVf!nm;fhUfQZ=gmih6_1WRS=~n)3?#k2l+vPC|51Vr zxQUKmBrAS8aJJVb1F0`4n5}iIiI}(|e=Fd>uEn7N^e{JW#^|8$jr~Sv)%-FI0*a@N zUcK$qoYSIrQM0#$sdwRPA2Pe=_O|K!j2va=+3JncGlARPp=ZbD#z;6=Yg&};_kQdu zcckr?wc{)L%df3AS!jkYh|KDl_8!?$w!BFhHau04sZ5VQz7V;MCzIykISkJk8+uwR z;>(eyH78c-ysu(!4wx8#cFwrG;dxP_Zgcs``w6BfUWHa$?OKU0G?VBq4P4b`faYCQ zI)AUx)GAj)u%gO5vc^RlHZWy1Qmu-B12EtSJl^#rH)P=jN?cnKQBJlt2EM0HP_9Z# zVAAWH4r)R8oS9o2%F{!Ks?wfnC&(nyq3|=pGWQ>l3Odso-wv#5pIjXfAXE z)@^2z{**@$$yhj2|ECU$eEs!2972-Ks_MLHolV z*;zmJr`?G+(kwtBueQdNW7SvchUA(4sa<2l36d$b@B7=rUT&daWsmT`#>OC42__of zuTCsOLvV!yj25HOfLB!TG-g*53YG5QG?}I_wnmjr1A=e9;&b!2uN3-g>9yR+kaQF% YQlD)6McVfS`Fjd{JpJgUYomVrA1bYTegFUf literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1H-0@2x.png b/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1H-0@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f11fb4f853f011a3e76be6851249fab8cfb31ace GIT binary patch literal 5154 zcmb_fcT`hZx4%J90Yygz6bFe|0FmB92`wOCC=!Y|fFT43m_iaD(os=FKvC&U0YitO zg&K+|=paZ72$5z(K&1EfF3vdbTW`(x{`lUzYh|5t&)xgCe|zuW$-U>UxvAlP9w8n8 z0QMVQ(7yx#9N-kl+`BUn_Cox@;TRQROSL4rP<_y3ETH2|bizW7@Mu@;B`n(cy60=G z1_10ji$mE`ZIKsY7$RO8y<;Oy!;^Nf01Y^egvNMasZb}ZD~_NkI$cvQ3dK2VirOe4 zWsxL3tQ+ovFBxm;Yl_17dSKL?Md4ad4H^stz+Oyj41Sn z3DrYW^iNW@NOPzjk&K0^NXtrLWMyTcDr(ZsXeTtr$>}^)URGXCMpjWqPEkr$7N(#E zQ&fchb%}!E$j&aXOZoYq8_Nq@rQpz`w4icoPR8iOP3tVsNDK_X#B1PT>Rz+jE^HAO)XX&lZOCaZ|h zQ_(jtkVWY0$;lz~R8{2_b(D2<5OS&pDmqGfKYjIy7%x1QK>g|K{L>c!HtgT|?#Ka8 z0we2V$vAJUvjLfihyKVKhWiIDU{GBHWqD-~Pxqg>{ORlb@3`n2ApR{E8IX+3PH+FE z*FTp)0qsoxmM(bnxA?IHQ1N6?+DG6gR{-GPLnD116m8(!ppQSl)mHPY7$?WcgNGl8 zo{8Lh;TK+UsMUk?uwdS>aOhW2o-kf<WL;#_4>Y^a^_gyFE_!6U z3Jwllkh8eF8EctUPA;dv?Hzu!F(5(YGyhmqI7D3u8_-Ni^FFCQK3+|-5R?}GoNt=i z75#Cb_=*R^ZS3u@Zsf)p*Ph&dR?_!x+SlJ72Yz|!)iT8>z?!TEM&4#wk-n(1=^+kZ zGuC`^wUvn<5C&g|1bX{CWZXBLBUkd|yEZ!|Vm{*Y%7{T)?9h@{3Ks(tr%de5El*sC zx%8Iu-qU&>=IaqpDAYMq`+*3oBFo(Z)Ey{i^K_WkL^ikUvw4J+ZP|ifJN+bbOAC2z zrmnCy(UE~BExjJEQOu3Z=eiOR(+GjS7x2j>+^?J5fXW0L(OQpcb>ZQeYunTO(#`3{ zp<%0NQBqV>_>D>FL0vb{xQ z^7TX0sd8^du7L$+dv@VtMoQTS$u^o}F*c_~DaXo)SL}+Q?dR;%kdfyO=bmKBO?0wc z#kT6L3UVK2j5qEnlfHb@&phJSE%y!VgIKW~BfW4Ppt2{QbFfd|Z}?&K z)7H4sWhs71w`LkEB4enEq$Equekhhr<$U?-_8uXeN6GF53tNluXodIZTj#Zo6*3B# zGTt9DV+%VbyzH13#~G9Q;frbLr`2kvUhddaZ+0m*Z#WdyF3`5!h zW$=ZS#3N`;GBwNnj?3kD{Mwj0PnMF`d8~E-3e1IMsgJ)VIK=iBn}|eq z`=vQNlUS^^CKT5xzFc!<-xgYkSX_Ca^O=SWFe|7$g`VygTzox7=Snx3Y<9DXVnur9 zdOpgvVeP+Mqhc>%P07j$Sl*tLe|K~ye)n?U;+Y&y$cVd=)54l0eSIrVS`wYVyB5b> zNaCl&+Bq`S-Cwkx`vq5H+v?&w&drpIJ@M*kKudnnDtu!NzT9gW$LG#A9vyY4tGI}3 z+erF8p4sLn@o78P#-4bXX>(xRGR^p;VY(6>T zEECbVH8pCzhO6^kMnyj#5_I_8)~CEP4Nkwtsl7E7%OM1N#aR4fzc+w&tb_n0vAGflfHjEk1K z603T5bvQT%RgrW=?%Tw;2*Hz5?g6j1ef#07j~=E6>iIL$Pm0*xeB57E6D`z}sggXm za&OJM4i|E%&!cCgp}?%o{j%?L!0NJlmjm<86*+(dIy@Oz@5TGBz2|K~jf$4y#4a{{ zmo>K&7Y&8g5qgW{G(f8T>0w{C3$dQsUmar2tkOzu zHq{3zFZ3UBciT?y^)aE&R8HF@u7u((oo}Unzfhs-wx-c`#m(*sezHM0&+C(F0ehx? zyUK-W=Uqm4GFu0Oj3_fIgtabdks3DGRS7EXQCaU6`!JCK$VSph7%er8%YS+M}E;NNVG7 zL3huwUTV@^1*_631LW19lfZ9(P?DLO0_@&$)6~WDSFmhUetdP=6H2nu%N0BA6gJ1& z^^UEg$t}Z$4hoF?P%{)D$-MRKrIeMIQlH(-OI?l3DMw&nEtk2|F3-PWb8}ntF+hHn zu8UKk4mg9^O3G2)3AH_qRz-sZ-%o`uN}%nrafjwRZm9dBApoh|eM#X(Dhw~2AzU7i zg}3xS18ea#v5vPRx|Ap%1irh_wp%r5S!UmUcSID+D&--!RV8OVx_KeRosdme@XaV~ zqhNZ*9JIR5b&ThDz^Lxx~W^JJf`Z=<4*9xA+m zMhLiWAYAe96PheJgMn8MeSJQ4?pH`2J{Hwl7vu7q#pm!hwWIlmC9L1E_wPA=>6N?F zkmL$qMetn2^U$gLt+>E}+q{Cv0<3YDNtB71N_q2RI+)1&Y`1Luqfssk5l6_;N6nPo z;lH(y9765o)DAY9?~{5GanaJ_BuB#m`v*GvwE@ofl4b?s{PbzF z$I_v3067Vr&le2Le19b;HS|DG<-9_-(A;t^&uU(h?!6hwXtoW2Ko;DIvOKwR5X@v> z(|k~%-$t{4j^~^r^Hb&XX6bi65j z;EzZ7YKFIDZO^}9NN5fU$p}S-E0|W3&W7&zN;DPuj6UZ%(E1rrjWZThlO8w<)F=Pw z^2Fm=KEDE5(6yUrZCDcuG86Mo+;Y-l3;Zf;DBu%T9{QCO2x|~UplWG+DhISIsvhQe z4MTni;7#e)8rpb>{el08Guu5ipGWH#L5%xg`JJ7RIUl#Xz72AdQNxYcrywgfsNJ?Xtj_E%9?uUhs(?Q|8zj&XNqd*s;P@p`qT)*3I~ zq5{?G1#_~e#C9OstFxkWye7@S?gi)JE9!ZVSm``Fm2B@9a~z+v^le_=?w3OQ6gIM8 zQu)%!gFqqUbzt)#2Uich_+}m-uhlihth6e+H$SWLb(waTe>f;(mcV(Xa^;-qk=&ZH zOFHW($6^aJDanf{o9@r+ll;?|x=t z9DlJw_3O&7tGyMAAFT8n@W3JL5HX9a1NmG>c8grzo&WZ^w9%f)IqB(&{NI zajyc8gsrGtc6~tgsEE+!G5b-!)R`@Glu*xn$vZ<#xtk`719I@e?tOisyo>@1{>7=& zR@EoR(%^(!1Lehdq*)(tQ08I(^Oa8w_V>Kkw^~}#YDs@4G;@|~7vx~JHJ)`#g3hHO zHa&lcHP?PEh}?f@&AZn3sG~%@vgPZ%an3aE1KkgX25R(ottU47Z^emJ3!RzVR;2XZsKXmTOK-s(YL0|W)w>Xo~fv&ScvTCC+F{ zO50o4H`+}!KOOU#p6@pt?CXk_O0LmPSvz+ohPhSW6V^8}=D(59zp2duRJqudh&r-r zh~lSTtUqsT438?QBR5bMrnl42`j5BE6W%mg+R^E_o^>Iu#1vspAP}?QYOI!Z%i=Qg zesU?sd^=9jJ64^SHk+-xFu}Kq9%PxlA5+@JmP693&+a?P&G@cbEE4Avh`H@ zPHbvMop?)0qJ9pyF0>vK>sk0EY6}XCw0+p0%d&fvC3&jJH7y|_=dJ4`!_R)JW301Q zF?DcUAu%SCK832!pufe`8%Tc;Ft2;)>tMeJr<;Cze~-Oa>GG}D!~%!Bz9F8ls@(^K zUw_^|!#OpyIZ%dhJnNzRP`;}_P6vP*3gma*xRYti?|9r%)hJObwU$x-_D!ihhrC<{w`MhpK+yK~IRSR18T`zVFgSB6zxBqAM%Z<` z`sA*VQ?*yX*DC;Q95;hN{$EbqJ81uM>i$0;;??HOAiIIF&?C4D1oL(f956zd>KE!> Gz42f2c@AFy literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1H-1@2x.png b/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note1H-1@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4eac5f6f2a62e9ad22096d02b1ba310e69c00a82 GIT binary patch literal 6025 zcmb_g2UJr_w>}h61Vt%|NN9=*ND&A~=uMiT_bNi9gd|83dH_X5MZf|mz4sfR?J-uU8<-&X02rX{iMkFGF+#X|!7O3!o*_3oU}^xs za?Z!v9%B!^3h_W8WZZx2$OI$&e{%t9n!*0=9&i{&@$pm_vjaor zp#HirZy&?Z0GL&%skKKa+(X4vOjAQdEf~TeK)^8WBEbkhBpMQ|F7^j6gwg*!EGs7R zhYAL+F7^+n?4jl&x~Kq{h_Z~Fw1=FWoQSfDjHml`caQ7WFN(;^$zPI{QDvJF1h%w9sc;0|m>RtKM7~@M_%o~I8hseqX1qI0jDafD#yksw_sHn)w$;-;i zOEWa2(IH5Td$2STedaF)Js8>}z{elsgF=e@W^})f!eZ3L7_R;!2891VX_4qZ=ZP_6 zvcc~DvX^A!e#i8eA{6@Ht0EBp)J9`0VgK^?za&Omhxo%}En#RBHo$|iayQQWHsue| z4S>00PyyB`l;2;|Xzq=|pwQkZe-U|k8AXu`P~*ryrK+`^_jF;F0x-4L>Ph<0HPS;7^5*x04;|2pa1;dq5hLS?*@M3UcR&O<|K(F zT>R6T#KfF8LJy71O=<*u)2r$a+kh-aWs=G*MpdmjT=Y6w3nKNK0tRbZLemQufPuX*-r4tW+s?`3^y-8)it(vEI)!e3ETCd zns%YjWUbeN5^*V(2Wz*SOa-mJ#dJox7)0>&nV#Ae?i3(}S}mAix<3=CC*&D>qAjD) zamc2Wa22dy`pNF&m7&!e**7Wa`cHRzhFeQI1@qP%(A0K714Zyb^`*$1+_4aDSy7wlD*xur$U;Pm?S4r7rWFZgVU4=WR<6+IJqu0!mDp^P`#|^t z`8@IJ2}Jh{CN9L{3$nM4v^2Fqr^C_ud`niD&WBNE15AIC4s9(3qGQhU@ z@HytKGj`b&dqz~rVl+g6j>hGgd$`&5^BZ$tneR@;yPQEK_@~ezCEq}KK*?1DqciGMp-xn2&{dStE+u^HUg!0m(LzNxVVd!tFdT8idUb-%y*nn0NbL9W9&{nj z>7HmpWBbY+Rql?RmTu9#+cTnczsq*|nmD=i%QYCMUE9lbmfq+6#KEN4E#lDICb)#8 zEf49a!fs6e_Q2h-ANM8g?v0jXZf)Z0(%494)j=0Ty9u;6!pptk86!f)q3FY(+PUvZ zQJBV6dJ97Z;IUGWA}^IPj|)AbYqUjhf&nXI#Lcy73Gix8lwgp_M=}Ch57OkTMkZn zjga%#$(CUk2f}??K?JG54bo6EopCqfld9c6?g6(}j%!S-T=#wC6qG?|Mzg@z{$x$W4&ffbmx1F+jbNb))IjR_(Mg{DgkMva!3Jn!vin1b8)6%V4 z&#Ag%iC^ESaHhn(K=ug)s)D9-z$DHZ{-u{yQX1!54UF+)xRyOl!jv*`K>q43>w>Ex zb8FpJ!?IRsAGEN@Of} zfQ<>*{`doH8>=|Fohfj5lC)S^*H(DPdaES~`Q5x@d8}a&BKqR3W5rsToN#bR?GHhw zsC70XK{_mro_bz&a=UhQnwp-1iG8g!Nh!bK@p(!SM(5EFaKKiFm_K4So#qBKo?%ON zq@8l7?bJtoJRTfH$PsSDv#&TlI35s=uh{o|d7cuoYsII#QXnnZbHrneA7tFH@d9xgia!fFh zDMB}5*NrmdWP5o*MG?y8XP=*UI&mb19nhOtoIzCRo2X4-x6TcPBmKIkM44QB4AL+o z^%{EfA9*{V$>*1c><$)jvPNZ5g?#-WH$R`sQ{US0YAd7)LfX-Hh3ylL_7vzKjTaD^ zoJq%k%i>Jen(1YJugPJW$tb^v%Q=bc)P&bZiTI2crl3#l0P>advV)BtAhKcg6rJe3 z&rx-e`s+ZVlS1M40nC%vOM%O8cE&ywBaO+=_@C<)Ns4!kIPS7DMcp?6!QmAn%R3y! zFPkZ0M{{Evd!}%NVd@j>Pas@nE$)zWVpcb)xzKK>vqPO2z^+YV)5wd$`GU-K<)6$zWoY0U!Z7_1xtsu*`jd zy{^=;oqsx~cVWOD?tD}ULUbs2RhJCGPJ9aELj*VLqn{CI^4?ohypJPaU2cw^d6mZU z80-H)GtPCx8J$-FMgn|GZ)&9yRVUSGZc7)tjDe}a`%uN#cs)s=+-N{L-gRSNHXj*>WddBT<tT;ZSpyaM6d{ zZ!|kyemz<>IxYNFxHdNO5Rm0_xu4zD6U_peqq*CPf&E86oljC38`&Klhpg*egYz_Y zY1vH{5A4>`E^x-93yC%$Rk z$0&OZTI|T2@(Hj1K&nS4$gNV>d!Tm-m#uxTNbwJps=`}W#qy|GqJdl z4{B`?np$;&>xS(+l{Su{j37fkKHv6FO8d|PE+qmb%uO{yFXa$GDlS`@@?kpZP?>lL zB>RO25HhLNz_!1#7T)iCaZ+*Wx(D2+*_N1V$k>AR`;8vce4r=rb!jH^cIrTwdU-;4 z$xixVe8(ug@OUIj#-k+Jwf)sS)+iEl>u&s2f#VOpTyuE5#wrX1%Z6lE;Ok!;zWW>( z)0Wb+syOVsvu)G#0CF7Au!1$Up6S>#*a%#%T?-A-2JSxka1x=%hwiaht;;CQGk{02IZs}tg6Hf-C#gk{`v+3h-K*!WS`o`J+KiH~ngTpOp<&V>y=0M@JP z)d`y`O>DvY%$D5;Pj$yZ>Z2I279+y&(+ulkEIZkINo`9`Q^NgActuMlBj9Gc-IQvH zf|l#M!42C~(fLJsvs@Y9w^>*`9)AK=s8bQQuM1v9Y<0>bAJZ#`{W~<7dL;zGSvMXm z6>1DLg`YVqF%*7e+M+N^$V4Dd<2~ZEpuORfeaBxZslRMr^wFbx-Jl8uVgMvsw+m6> z?9~(TZd&>vtMqZx1?R#q$`pLK2(j zCJMbdqc|96bIXIa!uczF%{t`Z3zCj11AeD@%d-tvg=nO-Pn%%&DB}G36%Q-Ncy5D` z6Tr+P=*My9X3t78<6h;ttf0N=mTS1mPusq@bDc`w(Pz~vs)?))$>g6)zp$>;c9E=m zW5&~0Vsd(w8u>w*aKt#Ucm=dHINYa6cd2;MxnKrh`hj4b^PgjxRn8w)TX;2b`Vkbm zHAXu-Ih}(Rw(C*wJG~N|B8JCO>7GJayNuhsgZKQappC{NslamM@_18oH*|NZXe{I;Rt%_roEO>4 zw5hG-mwS$8TTL?!ls(y8sqy|%g#lq<$_jILPv@IDF8Y=1;hNDlx034z@>(iicnQ+d zmhit!SDUl8d6|0W!hh=Ko7MI)aS^Uw-HHSyW#3hG%;(jRBb>Da3+FwU4*%Mu*7n>pz- z*iAqXS_(JBF}LBlVZQ5v-ID&9w%!h#J3Z}@4YeC^?JE0DJ!lq6kOuGCB5s9iVK=T{ zxD|EExA9vs2%AU;!SP2UU?HoU*eXocb)6v7d;duQ&FHz znanRsz92fJhJQ5h2?bvOkJVTo;IL7Ay@gG)D)OEp`AnT12er7Bs#b0z;}@oTj84^4 zPi9i)qE#vnw6;nmY2+r+6CPUnad}M+ulW#Vhc+L{o_lGr`m;k^wRTpL+;L1hIs8ds zi%%HA4pBgi)Cz4Ke}2<1=vbzh7Vy()>xy)Pja39_zERtmD+7n$9Qsu*$zg*VRM8#l zU%6VT`>jvPR)*pZsJebGgg zC&8z-+EtjNxDp!+x2?e6`s9K*aV6s?dy?>)j>Ag3bS(qdl~h>y$P(#`ty=|_Yq2JB zu6ylF(ycd4nOwJ2qod7y`npRu1Caaz(aHNB&zsh2s!h)m_NaKi@?PN$ei}{LW90N5 z($h0hrnw7z(iaBrkl#dMyoxyw^5QxY?m$qlP7mqq<-F)u{P7a*wx7m{bOcTqdaEQpyi{?L-0b3qmJ!Re( z@kV<`*7q~6bKiHbQf|lT?lS(H*R9~;sqgQLLYqk|<;xDQpa&ucznu)ROd<^>mR8>Z zqBP0py6}E=XpWK58t{~*cz!Kqe7P)Rlc<_yvv@n(x?J)$Q?Gs5JszSi$hQmo>#-z< zHNom5$9P~K+lxzj*4ABU7fR4W+X*cX_yXl+-SC`xTUwO~{POfFcq_+^KsmCcti7n4 z9vk^o-cj>naaF*L>?}%eP7;J_sVBQh-@KZafL2~9;ZE(wFK-y{ITdfIL_AyCz7$ZO z?G$u!xDGO^yD9)?6=SKt4zN0Sr$g18ZZ1AFv9Nx$)MZVt^W|creH8;Lj`AmFo3KN% zQYIHzqLe^L3+Df~YSzEir9>Fzu>VtmEL(TqAc_f)s#Z}I{dPEzK?fM=o9b2ST)X`r DP%iL7 literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note2-0@2x.png b/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note2-0@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..456cee538227bd08e4edcb652d421db6cf08d5a2 GIT binary patch literal 1865 zcmbVLeNYr-7=MqDPDjhi$;45%GX=G~-TP3y^-ekOKuaWdPv0DemM{G1ZoUlPs+wBpa2N<|Hm)nCs;TGK&%s2bJk&jEc^0YZQpvX;i#D z!-m;7Gv#tG$m6NSd5OtnUKXi$D(22X3|<@((3D6ZUV1qr;9jF*fES0dq(&9UfQgu8 zR6GhQ)n-S`EKecPDojaY7=}daRZhY|kPgS2hz8TBQA~%bbxI7wwR&8qLk5omy5pTo z@gz&!pfmU~DqNz-;VA0ycvK#(isds=wO+4BF%7EGD4~T?$Yn&rt7L>p0R{^tki44{ z-7JGhjD&;D5seBM>Z2TJE=bD=gLQ%xL%jrts#TbjQ^3$>`*%~C4q6Lh67@LVeH7PLf=4xS6L2k>!(Fc6p$Tb{8wMf{W!4jYg$IqHF}|W+ctj0f^0p zTNyzl7?QGDj0#Aia=V?lDONo%Zl*?u#aia6)v@MTvot!>OcPYkii9TJPeU{I;IPxLyV zf&(Op!O?|};P6unoOm9N_9*3|yKrNCR*Nawd!_A{3|Go9aOzfL^WMv^C4BOAVc}(D z8%^%qf?1u1TjFo0qAywQy?lCI#n_0j@AtW)7DlaaJGri+cw%2k{I1D;$H#7zzn*4a zV;jRaU7^E%EE(x}e%g-wIc4SF2py~LwR6XIv{zKG^^FI0<<~>udKUnI03eq({n^F; zgMqH5yD*vm{Os*#kNaO-^=D!3Xs|DK{Qb(--G-m(;h~^T@UcI{7gye?I*@&1EwE3V zkgwqo<)YM((1M>_9kunv74G86F(7JFb+6%}=}2d7^%SxI*uyv1e0;65ynS4}^vJqe z(X}8i!`2r*@YnD{`RX^$9NY?IJ9TMCD9+H1riFa13n|E0>-C23`c{_6zsuEiinwXbER_R}vH9y6Ab={+~h zB{5YiN31__-x1ZgsJZu@_<~5Va4&!ET0|%SG7tm6XaGWk_YhjdKo z<~2#nYi$0bxEAIE;}1H1oKjHr#P3sxfr|VmyrB3-hAa%2e`niUCL4AEc&xFBmP7NF G6#fPM1W^yn0|%cV4pHWG6)E;Etaj9Un)2svYXhM0?)VP=Gx%C0>$bUCH7 zyRcD`B)i-igL5Ls$z=9b&d9G3Ohlef~I|=Q(}H{c z&&nI?&31vJqTLfY(C$Q^09s-UjTnJ)*nzYYkYEA^#G@hwj94a@B(O&<@RDF#<;I|p z3n9E1d(@|*0=<2aE-Vg&v_WGnXjm*3X+uOuP{XOT@Njb^9*f6eumlW_V1dPwEQurn z0r~ks!Ra^=ktBbz>*r+f$sQHO&@#E7b%GVc2&ilf4vkgyv>52^ z{l7yQj4#n#o9C)?4a;h@` z%QHR5P62|aZ+eq&bj5G1n^+a1>xCqH<{*N6wO33MP{U>ia85#v2Zv?u&y2}9t^OitR0|?*SnV$Ou`?G|i}y=Wz>O zKiT~Bj>OoTQ~Oh>PIrgjp6^U{-EYr}n{ltMvMH}#ElV)aU0UEoD6wAZpBI#Vp6#Yp zv-QL889RehQfmb-qN=Mc&)xiSD8@@0Ax<2+j>a)OwdCLLFaKC;_^LP=r|dp&)kxL` zm9NW~8#7x^oT{L7Tzxf)Q+|x}x?nhT!FxSIoZfZm%EYfn+sj+ti(Ysczidr!>S)%5 z{a*KSXIkFqT9Wh$mEthy-hEwb5`NE1DX43BKDmq1Jy3bIzj31MK+;yvV{X>85e?8; zwyPpt3dMDur5{SNz91V=$k+HymDrw@+?VFwnzw`adxfdtT5fi$yj9_FaGw3-8n=Hg=Hnna zDLG(+^3VW+Lcu|&O%Mn%i9<42GcM8WZwc*Egk`q1&OH}uHa8zvY-Hb?s^VvE-dMea zoZKZlWd2jOY(v!ZT;17AiueCG#COZW7~jk=*wlu`rCdZf_6kR(uj51Q-aZrd&Bfd> zeNeGKN!mTA1^lloUWNBxjynIgx4lS~H$HVN)e^YpsV^TKtu?+`9z%E50Qrx9c9HB{ zKhT z#v!QYmxlt_F42-@E_60=c0C=O ztWl~{COX$hWFqNbGoQ?9!z!B4DJ7RBMMG_k7wK9O-lWdzrK7D61s|H~gKIYu_3dY0 zr7VY$W^!5M4L2RWa(6-aWPl9b)WVLt@#aD2WmBTlVXcy(m}Ut<0fXO5clpHz8$4cT zVt8xx2UER+KDO%O&LFHw|5&ZkvB&z+Nm#5)*{wg~^49FzW;XDSRW-H-A?~a?wfL=ryM1 zH`Q{HTCX>4%c_T()+g_n@=7|CMuf+Xmdo6PL3gU`Cd3VGl;O~qu$Fguzv&Nc%X68n zSKnJK(Z2G@H|HE1c!@PFN}*}#=@r~|rEH!w#uj!Brv=KJ$5yoh)9PN)z3Z=gwoZuG zhozlm!Ldc@f23k^j5E^<6O^Jb|KzuMW~TcPELZTWcH{fSP?gk31&<$ zN94RsP(s@V9OS-KYmhe-9P5QN;$EC?t=vR%xO%RUbZ~OM7R>RYM>{(`Fkc`@bKX z-*oYWvpiO9%Z(=<-+_6I*ros$YIT zl0{1nx)XIuPo?K?v+0e<+c`J^?%3p_%C@uSx1qDYE+n^ja z`cHDkG7Ydc|LF1-fDj+K!_U@(zeXn$s>4<8%V}vn4Od|YyN?*VEdOw}x@t?s03ZR- nQ2mAe|K_(~7E(DD&s)?1(zQFTFZk)Z0sMGSe8@MQ|9s@%;dFKP literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note2H@2x.png b/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-note2H@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e6da7a10550e46638ecb65a4460eea43eb4d66c8 GIT binary patch literal 5294 zcmb`KXHZjH)c5xZp#(%gX`(;`Q9&spMHE6*xKgBuND(Q5C`AY$z2%@+MO2C?5fDKs zp-6{Nq{K#*8tE;f^eTiF2zhcp+z;=je>q_qch-+06Ootsw7a zXH5VEP4#uon+Fcgr?kHK)gYjI0x}~>mw5$FXs=(|dR%4}_>Rjp3zhLl3YDguw=b0D zqB0dpaf=JwUrChX5p8Dfu8tuA(3aqR%rb;n`p2L31>p6K2M*@%Fo-{=7Cpq7)0;{7 zRHjT!q1D?YbGwq&l_;a2!0SO%jXl;A^2GQW`ibD4-hRm#Vrg#fRx##da9CgX46(pg z`zB>AzMYHV|8a9tw@}e7?x*vc9fC1)^X$$^l!G3AYoorqgW1%ZKe+M5z1m@t=a_G8 zYrMu0%I=Q@xj3DDCSYH*z@6l8qggFJnW9O$=k(S3AVbeAzEIrS7o5Bi=9}lYr2+-m zc)LI{{JLc###hUY;nTBhmfD=RSu@JLmNVjYyZcVX4%KaK`g~WTMH=5B5iNR7LIGQq zE}rtNaHo57VT0CM$f{=pG|-q+9Tokl@9|O0^JrUjW}_4&`xkb1EYBnA;gX==zDNtj zAT%~?+wt1T*W}sjWV`$ z&UCp$V{|j9@}BFh)pE5tPgEn)G+9=OfGN496?nH6r^CmCHEhhREGv1lm&f5<9Ld9Y zVY79dZQyH2CbG<(7T`1;;6$^3gl}LTqC@d)4Po(N4Ut2mf>S;tmtMp*RDs_IAU&*M zyF|XAly&Tujq{~DRh(Y7N&QbO1>s_mfok9KGblff-&R+QKik5AQ{Na_Z}wZswH|6; z*qzH9^N;EycI*vK%LYbtt8IAqfd-`_=1>!y6`t1rH(iYlbr+a`M}cP z7&4zk8nJ9jH+a)j@ONeL1=*7x`+Jh933pNchW?TRFNkG5bTvo1ID)@0q&(R!DpPJP zO3zFL4(vK9dtLKH6w`(2AV4M*j+uk&x!6N4+J9NtMO)@?fFC@vhJcQMTx#>~g>HTO zI&rN-u*XkH<1)f4lr*@MM(;qKur_g*o+lhaqTn3G_)8yc)g)w_fwW7V^MS4f! zC+Go4FeaO`4eAho3{4KuVz{v52>x{Ql0?grm$9}Py+p!XOe`o7-f$~u`{NyQc)+gd zP@CDA7j6|a8Nr+v3lUu<{zz&7>WdcaQ=Dyu$mOQ`bSX+QCVbM6f_#YQFWG${9Rn=g z0Gd9;OmcJrZe>{u5-?pn;&WW_UfANIk{k&82+9r(+=Qm%eBy_ZozV--@W7M~Mis7H zQsMsO%Z6}rgar8ry!cBwgE`SkXol=Rwob!2$9=7UBRBS0o=pjv76Kd-0!SLJ6))BC zE5czGq!xDcP3U(zmt)z4G$QssAkDUz|5Nl*yzBb&X-~zkYG&s_iH5aDN}~amb7<4- z&-Xz4uMZHN$Jo<6XO1d!eegegq4nTOB~UpD|K`F5FwH7<{LDe}!YQc|g&3pCJc}>3 zrRgFfaNRYq@S4eRBkC?H$lJ@n_5Sx{#w2$2A7-MfAtb`E! z6q9-5rf)Kv= zzN(^?ewCjhPKZoDE+l6}@0w}U)y71VWK_EqdVh&;*+O4W^qo08(R{IWRbgm9KV0`0 z2s(Fz4bkbtmAgpUg#qmvcr!JIsnDN*$VA14WBE~4}ez8p&G2Z1exJut( zSkY2*nNBo3V{=oPVYeT9_9&1YHIY(>^s+gNEFQ{$0UmS=wI(;5Y3>8vB^D#m$<)zx zJ&Tny$AL8=?ADs1b&Av+Bg_D7i9VUXPOAbL$HA)=>K2g(bZE*v)E95kx&-Av*O-8~ z1gb4?yZm0)&-U2bU~c;<6pD<&%q^VUxH69D{J`mT8Mtv_TPIRJFljGA_Z(7*v_m8@ zHII9_4ZZsrj(O^L;q9|k-0S*eQSs$dbqNJzhx>+oBRGx`yCp}@1?PVqhXif*fq3dJ=dqI<~Oc zNjrfr#MP9x6loy;V;}}a?K%aBqqf;g1SGYb<^g4}4t1L!7LyN?{wgWPX0?|3R)p+k z@SGPeWbagQYO7BPINwb>gB?;MQ1}Nu`cwy}49kPT1MO;0Z?X|vtLd^481dgj)kW}M z0yF2KdFgAjy;^FA*tLbBcgn2K#DHvz<;&%Coo&$)= zLc`VZw}QV$J*p&Y2g=rGLY2ps5ZpA-;slbp_CCHJzZiTOR4-^{Tu9WDJPGx%r@h)2 zD?&Lj6U;~+7bTY>BKIKX)J0%n_ReU&+31ehtcjqa!wllIeT!O{Vw?or&c`rb9ai-! z|0D&6&m%<>A$fp_Y6(#{pgDnh|nvsrHUE_7F_Uw};KFlfd_sSd8>NzcA=sgWR4 z5X-^9XXt4jD7g4>djdDR)QiuG(cRaCPS+P(@kK*TJLrC23_b?Y`5tsr5S>M! z`#kg=ACJ`mbTKF+2`olzw;|I^xE)*;?M>?bY!p;Y?5Z-RLN;WSInq`s_30c9mfG@j z>vR=pSi-YiqGW9_c_7eP*6dr7;hX6jCaJGv)P_pkWuMv@=WvsU)KDk~o7>)UvU9@0 z{;$iG(0M(xp{^>HJb2y4JG(L$oIc&t?1)K#RlHIg&atNzfU=|D-t#C>rp&QS6ePRt zac~uH^I+B`mIT)cxQGe7&e;H2iqu(HtJWAF)WWbXGFmmPxf4Ors>l_|2%Sr7CVcP3)dMEqB(U90 zly{R_8o{?vB+$|UX-b21;(bt84zl^DwakC%^%VH#$rT+(-xLA9B zme4F=S%O*mzy0tphW&RL(X3LiEWs@Cga04*{(GPQKI1=?|9hHPRtU57?;apo@qcUi zzh$I`Ox&tDw%VGm|6ZT&YGB=_!YB>C6J%eIYHT=sIkkH|Wld^=ekalW^wdi9u%*;S zW^qx_OD0tB-3u?u))jtln+jVKZo!32i zJbzT=R6flOYKlkj3j~=1`g?x!iz{~h!ApEgE-oQo->mT_2)Lh{@-V;i3OBHCWXDs2 zu(mF^w+d6GbzOregQV<7z&yG~i7q_+UYs|wr&mKmInl3M?_6CHN!&gxFH9Sk)Z*3o zdjz33_7Jpa!DX!57Y)3Tu@?|l6%!SdB^KnA4U}#KAYzHZz>FVDH-|E2G}Q}~dK}k- zQ)e0b*NCz=C}LxePNu4@o-NI(_$z-Y=c9+1mVprDaq_;ybxL^<}PE`Dahxyen@swY6~^G>3q^nKf6a$<0KSFRf=O*c80quKdx{b@kZS z9@HmiR3fk#%4+VPoF{)E#D9nxlY?m)prJG>~!_JWmO)Rx^$UW&Cyid%lg^1mw52`Si-0{<^RD@M8gKfLl!d zp$|!B#uW-|yj1Fx_pw%KEWm$P710TUZgml?9Cw;E((7!+)aqubmdE8zm0}5O=}DJo zyOgS>>TvX$Ycw;9@>8|AcJy0~jv=Dx(U{u8R~wXz2=3>;PIq=wQKZ`MJ3M63Nujx` z%^VT=6Cd2^CHZOx+~UF#tykRYED?h|WQCder?vu+UM8pM2M&#^21UpWM&L~vkxdIW zpM$LG4U5H(MS~v$9DfFzgrLBi`O#6ctoC{gxaFs>bx3RP4*a?2j#J!+^+{siy<*FQ zRYRPySM|ECqBK%3Ep~v-Wiac&?Sn`!Ow5e7hhKa{!6z!)LMYU93OZxd5W0u;p7=m@ z;zBR57vTgB%AgDN#tE>QMNP?<_D&Nk&|u-w;D6OyF`C=KK2nwsk!(L@C%UMm`|a>| zkr-%?{$R`25j(9xNrMzcP1$u&*3ahED8^>kc^`c54hR~(c97J|rpL*icH2nrsx_E_ zpp$+(cSo~9F3X88bGtJ9_8zJ;f(3sRni#v%-$AEe!DWMNRvKv@L|R|?-EEVL&Q2W; z`>=Q+Y)(czvE?E{?-UeyO<=UQMj86OHXQ|C$N>F3n+SiKx0VH^KAqK{-_E%0|Joo5 zkMyfWxjts6Mjpwmy*<2C>nmbf5O1rjJ-~K6M&`q4_Z8rnpJ9dX_+=JVWwV!EeYiYB zl2^6LaAB^7*G2#v{2cVAiaPUG1YQ$kTjq#xLg=MR!H$i}mb$rpyDIrZ&3#wk;%2;E zH$K>?jY;)L>zm+R%~*9c#wR|GANq8JP`ouJDU4NScQBeBdo*2+<#`a10N!9b!kh(7 zzR$QLiVSTMIT8Piw~TD?;xO!UzV0||z7HFYG*eA9%wfJi1?Rk$!XH%N(~o%C#`V<4 zb^0C2P6tc~JBGcXRsu6CFv~@@$r2!NvQwi!2^wmRembYg5sL^B%ob-o9t_uZRq7^b z%$d-$sSQfFdG~ie*kW^Vp+-znm9IxYSGWLnkQ>b&3?>v7PSAIsJ8~Mn)dQg``5>i zN~3#%lLVD^G}WiNkd#&E5>m)!BKww09_qZFqZN?9_hn@bXZ;-6c%V z_JN7rOF9ysb3+GCXWxA_K=*&JriEB8At}Hsc9n6qvh80(z{H}y2K7X|fjXw|_26PQ z=x#+i5YF$-in2B^_>=e)5&1Q*x0;tVSUL}*!jhiZJymb+dYj78_gbX#!ksIZ!NwiG zDPwZZs~O?62?} z&p%-yGnQbWshYrUnp|-NUg;hV!yAAIpXVFA5)2-R@uZxT>p97f8WuaCztd-P_L&Ce z1bfxKOMX2YFkh(!W0!kwbAMmMK$Q=ZU|{AOqw@P_wchyin6jYUu<9qwGEKfWZhX~u z5S6|&6=NIuD>Ic%n&?no{3X!!)O5I}d6I8fW?#_q2rjKLInD=Nbc7#!3UYC7+$%}{ ztRrT<%flkm%}r-S=Q}OR+LsQt{G!K5ew^~71bz*r#}ZO?5+_s>yzZ+1cDT{Np2H^| zZ|bgf!~f~s1Wctzqe18+&>Qo|m^YcBbFs+2IttKY3TFuRlpNL8#}x--30A@5ir6^f z(Xdd@35p%!5d`N9%at^dJ b9^wF<;)Fjl4vsg(S7D|NirDw%t_mPhsRH&ps0wx=kk!{c4Px{Wy7o(s`5trFz~m-V_g zT}vyxjFM-rAM#gRP|l%;0I<&Hse}Lk$w>QZ zHR$J=QF~o4Xr_ccigPF(4_a`qdO!~Q2Mmcr*HWv#4|eFBWo{?-K>;( z)U-b)v8zlhz&C-RQkC7xX^m@`jPU}`mTAR=P-2Fg5Ze!t@B9X6ex1w#5`~sea@ua) zZfgy7w%)QMc** zkdz^;`q7RGG}fh-W^Jgjgvo9#KMLtBez&3M?W3@GJgznSPGp^5W1$Z_EU;uH3Xv6U zmW0!5Q%`pZw_k|#fK0=))&5D%^_Crng9l*cfzAPpa`|7!ZM zXiJ$Hwf${km}jo>Wc+tDSU@VkUs=4%nXI-jWF=hy_IMUn+u!0dR^8P@X;Sa3#Ierg zR_{>idUn6kSV}>h*?d1tpoiip1gVm6#|7XO!c5Tb;Qgw$L!giT{$T#31!&ZIW)I?8 z?0K+x5kyOVf>uLs_iV4Lwb(r#enW$I^fxOV6K&Mf?e*)C@VoAihlp*8R^;!%yp&2_ zgBb_Wy>YG2mtR%*V+0Vgss{;FdgaWP zsyYxT$Yu!=!_tnhpr25!E$y!LoKgOkOy)<+x69bx?RYqB1Xy(x^hb$Hy0du#$s0E+$aV7~gYw#^SR@Po9B(HhDWXJgjn}GQvGl5L;C&SWjBRKFl&=ZlAxY{fm zu=$pku#7|vGSwr|$8^#KnJUW?NZtYt9N3su+N3q;xJi+0e^$mx_^5ylh&+ppU~vco zGn3gk4ZcS)&scFl#fbZICEuHG|LNWP=r;aVvRPfM6uC(BV-Qj87u;NRDXYMTQ%$3%@gV)m_*?z zyZc9FA0W^aqGySO4)-ylN78-BJSHqB)#g_*S1ef~&x&}7IC;fhMF&iy!F^lkW#{dQ zOsIs1;Qi&^dFtZ=R$t7UKjT`%lO&;KbGQ~hTFd>sLo?YH0^ zUR2DySum5dh5)mZ5(p;@@h5?lSQHe>_DqQeYYS zXY>5?5&vfQ|K#r9y!dZ6pc#(*$3>`1tVO0MbrajWJGzSkMWhevQkq-d)QT-ni!EmK zWj=V;_FZ5^ZK`KQNKP_2ZT{Sj?FA{BeKpJ#!?_z@UMBZRMBe(-)|c=51{bb7GDAM^ zJJMH-nm*c~af7DRF*#a4rVTDZ8MV)>$-(~IrTL%p8V*O2do%quuIg?|JITfaH($l;g5o4f_9)5RbuZJaA4#xA%#1J- zM6kBZgyBSI`9aCx?nsJXh0s@FC~`qA#f?S{N(?{oN=BZRmF9_d@3&1E+D_!LN!Oa7 zgruc;rd{}83`?^cY#$(-Nqi@1WoTVKM{5Xv@sieG$c<&ZLnN39uMnuD>9*%SM*sTt z-4;yf0{IBbzVhBfwRw5({AsD~K^L);d6L)+-ru;ncN@OF@pOvK4j*`{3|IJ&%39Q} z>Fp_8CB-v(k*UnfjjVVoYb!8kacj2{QITG-D4QVWkqEOAg5pI{8oOk6HnwGwu-1>A z3PqE+WewV%FMKBD8t9zUm&ez$66{UDuLIcmLK}{e5^E6=IPQU2ABCHEO4`4LX=Z(~YtdIT50~w4`%FbdZkpyY% zI48CUKGe|ZezrsvcD~r@HCWWlb%Pp6C}7EhwLjLl<<{V3BeXBo{@$9m>^A87@nC%o z*A|rXuRYsd1+3h>phnq#t}j{J9b-ffD?ApQJ@C`~_(2%V3W?HB<-gc@K9mc+ZzTQK z_C8a45)UMEE=8Gl4stBVF*|fPGCm zUYK%XE}wInQb!`U5ob(*v?zA9LM=4e9rn@n{z3r?{|*=oujf1e5#V1hiFFzhGqCO0 z5=)9RWZc^Byl9K=1$VFlceryqiL|8&_|F0}T;Jv~!W0^GpliC`yLKanJxzkiTxjdI z1&+{OU9S_h&z+-YPgPli{t0JnE(pQN^+_OP-@1rDE_*9X#PAd8(y)q>CgZaqy&ajh zNJ5;ZY|MJFG&k`mb%-Tv?l5&Uzzwn*m)l;kWF=7YZ9{Kay&RE>d3s^!B4Xy31PHBG zs_QF1Hu6Oh>&P)PkxgM7s`S?`u=o8tMKNC<_LRN8cI3L?!DAC(Kk#dvGm8~!$N?G3 zRpsY^d+dv!rGf_^U7>~^ErX6md7O`=?vj^tOUdo}9fNPIR~n=AQdPvE8bz3_rH{Wj zHXzoLH7fvbAMC|^wHioL!Y?xbZ0XfYS#s*!=*3r7t4HxV@JCSl9nZ^-VB`h84KIIE zI_`0_@DMr9K1EkAz+6@bpH$&>db^}5WLEQzPkz&(QWW0B z0&SEPmt#icvcW$@LSqP=v=*rsbunOJT#Sy;5`%U0tzG<az>% z$_#Ab4*u>hKt{fkpI_kY86Q6Mg6*;j%;TXq5TXR>DgvfXEkryowwM`;4uLiruq79|&Bl(8kZSB;w}kG2Pb zHh7El(E|zCDAgNYHH%v45vQiX8dTJO>B;7ImyUfEZr*q^xl%H@6)*WsIjO4k<|lmYrWH?Edx HIXwI~zp|9c literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-noteSH@2x.png b/osu.Game.Rulesets.Mania.Tests/Resources/metrics-skin/mania-noteSH@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c9bc23e8d9233fbb3b3adb132c50eef6d7f78a11 GIT binary patch literal 3963 zcmb`KXHe72`p5Sd6A2*Fi-HnVK&8V$0Vx4Qs!EfN(tA-l0w&iZ2nxgl3JNG4M0y8- z5T!{|Ff=LB4j=-C9v~#SIWPV*|1)#%t9xF2XLo0Ip6A)`?(Anb&iIBd8_P)+005i5 z-c?foV2m!vL;ltHA)!b{b0SE`D#*;=EhyA6z!hk^_&d3x^nD%OT}@pbUBd5myQ%`f zeoFtUrg_-->g(S7D|NirDw%t_mPhsRH&ps0wx=kk!{c4Px{Wy7o(s`5trFz~m-V_g zT}vyxjFM-rAM#gRP|l%;0I<&Hse}Lk$w>QZ zHR$J=QF~o4Xr_ccigPF(4_a`qdO!~Q2Mmcr*HWv#4|eFBWo{?-K>;( z)U-b)v8zlhz&C-RQkC7xX^m@`jPU}`mTAR=P-2Fg5Ze!t@B9X6ex1w#5`~sea@ua) zZfgy7w%)QMc** zkdz^;`q7RGG}fh-W^Jgjgvo9#KMLtBez&3M?W3@GJgznSPGp^5W1$Z_EU;uH3Xv6U zmW0!5Q%`pZw_k|#fK0=))&5D%^_Crng9l*cfzAPpa`|7!ZM zXiJ$Hwf${km}jo>Wc+tDSU@VkUs=4%nXI-jWF=hy_IMUn+u!0dR^8P@X;Sa3#Ierg zR_{>idUn6kSV}>h*?d1tpoiip1gVm6#|7XO!c5Tb;Qgw$L!giT{$T#31!&ZIW)I?8 z?0K+x5kyOVf>uLs_iV4Lwb(r#enW$I^fxOV6K&Mf?e*)C@VoAihlp*8R^;!%yp&2_ zgBb_Wy>YG2mtR%*V+0Vgss{;FdgaWP zsyYxT$Yu!=!_tnhpr25!E$y!LoKgOkOy)<+x69bx?RYqB1Xy(x^hb$Hy0du#$s0E+$aV7~gYw#^SR@Po9B(HhDWXJgjn}GQvGl5L;C&SWjBRKFl&=ZlAxY{fm zu=$pku#7|vGSwr|$8^#KnJUW?NZtYt9N3su+N3q;xJi+0e^$mx_^5ylh&+ppU~vco zGn3gk4ZcS)&scFl#fbZICEuHG|LNWP=r;aVvRPfM6uC(BV-Qj87u;NRDXYMTQ%$3%@gV)m_*?z zyZc9FA0W^aqGySO4)-ylN78-BJSHqB)#g_*S1ef~&x&}7IC;fhMF&iy!F^lkW#{dQ zOsIs1;Qi&^dFtZ=R$t7UKjT`%lO&;KbGQ~hTFd>sLo?YH0^ zUR2DySum5dh5)mZ5(p;@@h5?lSQHe>_DqQeYYS zXY>5?5&vfQ|K#r9y!dZ6pc#(*$3>`1tVO0MbrajWJGzSkMWhevQkq-d)QT-ni!EmK zWj=V;_FZ5^ZK`KQNKP_2ZT{Sj?FA{BeKpJ#!?_z@UMBZRMBe(-)|c=51{bb7GDAM^ zJJMH-nm*c~af7DRF*#a4rVTDZ8MV)>$-(~IrTL%p8V*O2do%quuIg?|JITfaH($l;g5o4f_9)5RbuZJaA4#xA%#1J- zM6kBZgyBSI`9aCx?nsJXh0s@FC~`qA#f?S{N(?{oN=BZRmF9_d@3&1E+D_!LN!Oa7 zgruc;rd{}83`?^cY#$(-Nqi@1WoTVKM{5Xv@sieG$c<&ZLnN39uMnuD>9*%SM*sTt z-4;yf0{IBbzVhBfwRw5({AsD~K^L);d6L)+-ru;ncN@OF@pOvK4j*`{3|IJ&%39Q} z>Fp_8CB-v(k*UnfjjVVoYb!8kacj2{QITG-D4QVWkqEOAg5pI{8oOk6HnwGwu-1>A z3PqE+WewV%FMKBD8t9zUm&ez$66{UDuLIcmLK}{e5^E6=IPQU2ABCHEO4`4LX=Z(~YtdIT50~w4`%FbdZkpyY% zI48CUKGe|ZezrsvcD~r@HCWWlb%Pp6C}7EhwLjLl<<{V3BeXBo{@$9m>^A87@nC%o z*A|rXuRYsd1+3h>phnq#t}j{J9b-ffD?ApQJ@C`~_(2%V3W?HB<-gc@K9mc+ZzTQK z_C8a45)UMEE=8Gl4stBVF*|fPGCm zUYK%XE}wInQb!`U5ob(*v?zA9LM=4e9rn@n{z3r?{|*=oujf1e5#V1hiFFzhGqCO0 z5=)9RWZc^Byl9K=1$VFlceryqiL|8&_|F0}T;Jv~!W0^GpliC`yLKanJxzkiTxjdI z1&+{OU9S_h&z+-YPgPli{t0JnE(pQN^+_OP-@1rDE_*9X#PAd8(y)q>CgZaqy&ajh zNJ5;ZY|MJFG&k`mb%-Tv?l5&Uzzwn*m)l;kWF=7YZ9{Kay&RE>d3s^!B4Xy31PHBG zs_QF1Hu6Oh>&P)PkxgM7s`S?`u=o8tMKNC<_LRN8cI3L?!DAC(Kk#dvGm8~!$N?G3 zRpsY^d+dv!rGf_^U7>~^ErX6md7O`=?vj^tOUdo}9fNPIR~n=AQdPvE8bz3_rH{Wj zHXzoLH7fvbAMC|^wHioL!Y?xbZ0XfYS#s*!=*3r7t4HxV@JCSl9nZ^-VB`h84KIIE zI_`0_@DMr9K1EkAz+6@bpH$&>db^}5WLEQzPkz&(QWW0B z0&SEPmt#icvcW$@LSqP=v=*rsbunOJT#Sy;5`%U0tzG<az>% z$_#Ab4*u>hKt{fkpI_kY86Q6Mg6*;j%;TXq5TXR>DgvfXEkryowwM`;4uLiruq79|&Bl(8kZSB;w}kG2Pb zHh7El(E|zCDAgNYHH%v45vQiX8dTJO>B;7ImyUfEZr*q^xl%H@6)*WsIjO4k<|lmYrWH?Edx HIXwI~zp|9c literal 0 HcmV?d00001 From fa693bb8a83ff8ec32c59e31f2a31211af76b8ea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 16:08:09 +0900 Subject: [PATCH 066/161] Move `MusicController` adjustment set to inside `OsuScreen` itself (and result `nullable`) --- .../Visual/TestSceneOsuScreenStack.cs | 12 ++--------- osu.Game/OsuGame.cs | 2 -- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/IOsuScreen.cs | 4 ++-- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Screens/OnlinePlay/OnlinePlaySubScreen.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 20 +++++++++++++------ osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- 9 files changed, 23 insertions(+), 25 deletions(-) diff --git a/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs b/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs index ed3935e101..7729ad0ff3 100644 --- a/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs +++ b/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs @@ -25,8 +25,6 @@ namespace osu.Game.Tests.Visual private void load() { stack = new TestOsuScreenStack { RelativeSizeAxes = Axes.Both }; - stack.ScreenPushed += screenChanged; - stack.ScreenExited += screenChanged; Add(musicController); Add(stack); @@ -129,12 +127,12 @@ namespace osu.Game.Tests.Visual private class AllowScreen : OsuScreen { - public override bool AllowTrackAdjustments => true; + public override bool? AllowTrackAdjustments => true; } public class DisallowScreen : OsuScreen { - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; } private class InheritScreen : OsuScreen @@ -147,11 +145,5 @@ namespace osu.Game.Tests.Visual LoadComponent(screen); return screen; } - - private void screenChanged(IScreen current, IScreen newScreen) - { - if (newScreen is IOsuScreen newOsuScreen) - musicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments; - } } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 2107b3a0e9..ce84c4bd2a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1075,8 +1075,6 @@ namespace osu.Game OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode); API.Activity.BindTo(newOsuScreen.Activity); - MusicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments; - if (newOsuScreen.HideOverlaysOnEnter) CloseAllOverlays(); else diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 5bb47e1c11..028662172d 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Edit public override bool DisallowExternalBeatmapRulesetChanges => true; - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; protected bool HasUnsavedChanges => lastSavedHash != changeHandler.CurrentStateHash; diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs index b12baf233f..910a0c7d61 100644 --- a/osu.Game/Screens/IOsuScreen.cs +++ b/osu.Game/Screens/IOsuScreen.cs @@ -59,10 +59,10 @@ namespace osu.Game.Screens Bindable Ruleset { get; } /// - /// Whether mod track adjustments are allowed to be applied. + /// Whether mod track adjustments should be applied on entering this screen. /// A value means that the parent screen's value of this setting will be used. /// - bool AllowTrackAdjustments { get; } + bool? AllowTrackAdjustments { get; } /// /// Invoked when the back button has been pressed to close any overlays before exiting this . diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index bf7c738882..c45e3a79da 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public override bool DisallowExternalBeatmapRulesetChanges => true; // We are managing our own adjustments. For now, this happens inside the Player instances themselves. - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; /// /// Whether all spectating players have finished loading. diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index 054009a228..8c4f0c1394 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.OnlinePlay { public override bool DisallowExternalBeatmapRulesetChanges => false; - public override bool AllowTrackAdjustments => true; + public override bool? AllowTrackAdjustments => true; public virtual string ShortTitle => Title; diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 01dc703b66..d3981b715c 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -11,11 +11,11 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Beatmaps; -using osu.Game.Rulesets; -using osu.Game.Screens.Menu; using osu.Game.Overlays; -using osu.Game.Users; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Menu; +using osu.Game.Users; namespace osu.Game.Screens { @@ -84,9 +84,7 @@ namespace osu.Game.Screens [Resolved] private MusicController musicController { get; set; } - private bool? allowTrackAdjustments; - - public virtual bool AllowTrackAdjustments => allowTrackAdjustments ??= (musicController?.AllowTrackAdjustments ?? false); + public virtual bool? AllowTrackAdjustments => null; public Bindable Beatmap { get; private set; } @@ -96,6 +94,8 @@ namespace osu.Game.Screens private OsuScreenDependencies screenDependencies; + private bool trackAdjustmentStateAtSuspend; + internal void CreateLeasedDependencies(IReadOnlyDependencyContainer dependencies) => createDependencies(dependencies); protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -175,8 +175,11 @@ namespace osu.Game.Screens { if (PlayResumeSound) sampleExit?.Play(); + applyArrivingDefaults(true); + musicController.AllowTrackAdjustments = trackAdjustmentStateAtSuspend; + base.OnResuming(last); } @@ -184,6 +187,8 @@ namespace osu.Game.Screens { base.OnSuspending(next); + trackAdjustmentStateAtSuspend = musicController.AllowTrackAdjustments; + onSuspendingLogo(); } @@ -191,6 +196,9 @@ namespace osu.Game.Screens { applyArrivingDefaults(false); + if (AllowTrackAdjustments != null) + musicController.AllowTrackAdjustments = AllowTrackAdjustments.Value; + if (backgroundStack?.Push(ownedBackground = CreateBackground()) != true) { // If the constructed instance was not actually pushed to the background stack, we don't want to track it unnecessarily. diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e8a2790c94..9927467bd6 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered; // We are managing our own adjustments (see OnEntering/OnExiting). - public override bool AllowTrackAdjustments => false; + public override bool? AllowTrackAdjustments => false; private readonly IBindable gameActive = new Bindable(true); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 9b6cbad7d1..1f0f134ba7 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Select protected virtual bool DisplayStableImportPrompt => stableImportManager?.SupportsImportFromStable == true; - public override bool AllowTrackAdjustments => true; + public override bool? AllowTrackAdjustments => true; /// /// Can be null if is false. From b58415fe198b571dd00640f8689fe22f304bcebd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 16:12:14 +0900 Subject: [PATCH 067/161] Make suspend stored state nullable to ensure we don't break it --- osu.Game/Screens/OsuScreen.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index d3981b715c..f425144c6b 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -94,7 +95,7 @@ namespace osu.Game.Screens private OsuScreenDependencies screenDependencies; - private bool trackAdjustmentStateAtSuspend; + private bool? trackAdjustmentStateAtSuspend; internal void CreateLeasedDependencies(IReadOnlyDependencyContainer dependencies) => createDependencies(dependencies); @@ -178,7 +179,9 @@ namespace osu.Game.Screens applyArrivingDefaults(true); - musicController.AllowTrackAdjustments = trackAdjustmentStateAtSuspend; + Debug.Assert(trackAdjustmentStateAtSuspend != null); + + musicController.AllowTrackAdjustments = trackAdjustmentStateAtSuspend.Value; base.OnResuming(last); } From 3495fae5191eaca5fb0842873830071e3c65b9ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 16:31:41 +0900 Subject: [PATCH 068/161] Handle potential for `OnResuming` call without an `OnSuspending` first --- osu.Game/Screens/OsuScreen.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index f425144c6b..ccc891d3bf 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; @@ -179,9 +178,10 @@ namespace osu.Game.Screens applyArrivingDefaults(true); - Debug.Assert(trackAdjustmentStateAtSuspend != null); - - musicController.AllowTrackAdjustments = trackAdjustmentStateAtSuspend.Value; + // it's feasible to resume to a screen if the target screen never loaded successfully. + // in such a case there's no need to restore this value. + if (trackAdjustmentStateAtSuspend != null) + musicController.AllowTrackAdjustments = trackAdjustmentStateAtSuspend.Value; base.OnResuming(last); } From 29ce2f05bdfeaeb317220383f608b081f39195f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 16:44:46 +0900 Subject: [PATCH 069/161] Remove implied defaults --- .../Skinning/Legacy/LegacyCursorParticles.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 73820b8df9..3357508d24 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -53,10 +53,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Origin = Anchor.Centre, Colour = starBreakAdditive, Direction = SpewDirection.None, - Active = - { - Value = false, - } }, kiaiSpewer = new LegacyCursorParticleSpewer(texture, 60) { @@ -64,10 +60,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Origin = Anchor.Centre, Colour = starBreakAdditive, Direction = SpewDirection.None, - Active = - { - Value = false, - } }, }; From 2df4073946bed60dc96fe5f3e44b925af63a0a13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 16:50:03 +0900 Subject: [PATCH 070/161] `SpawnParticle` -> `CreateParticle` (and set time outside of `virtual` call) Allows easier overriding (no need to call the `base.CreateParticle` call and worry about overwriting the time value. --- .../Skinning/Legacy/LegacyCursorParticles.cs | 35 ++++++++++--------- .../Gameplay/TestSceneParticleSpewer.cs | 26 +++++++------- osu.Game/Graphics/ParticleSpewer.cs | 13 +++---- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 3357508d24..858ba98b86 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -179,47 +179,48 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy velocityFrameLength = 0; } - protected override FallingParticle SpawnParticle() - { - var p = base.SpawnParticle(); + protected override FallingParticle CreateParticle() => + new FallingParticle + { + StartPosition = ToLocalSpace(cursorScreenPosition ?? Vector2.Zero), + Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max), + StartAngle = (float)(RNG.NextDouble() * 4 - 2), + EndAngle = RNG.NextSingle(-2f, 2f), + EndScale = RNG.NextSingle(2f), + Velocity = getVelocity(), + }; - p.StartPosition = ToLocalSpace(cursorScreenPosition ?? Vector2.Zero); - p.Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max); - p.StartAngle = (float)(RNG.NextDouble() * 4 - 2); - p.EndAngle = RNG.NextSingle(-2f, 2f); - p.EndScale = RNG.NextSingle(2f); + private Vector2 getVelocity() + { + Vector2 velocity = Vector2.Zero; switch (Direction) { - case SpewDirection.None: - p.Velocity = Vector2.Zero; - break; - case SpewDirection.Left: - p.Velocity = new Vector2( + velocity = new Vector2( RNG.NextSingle(-460f, 0), RNG.NextSingle(-40f, 40f) ); break; case SpewDirection.Right: - p.Velocity = new Vector2( + velocity = new Vector2( RNG.NextSingle(0, 460f), RNG.NextSingle(-40f, 40f) ); break; case SpewDirection.Omni: - p.Velocity = new Vector2( + velocity = new Vector2( RNG.NextSingle(-460f, 460f), RNG.NextSingle(-160f, 160f) ); break; } - p.Velocity += cursorVelocity * 40; + velocity += cursorVelocity * 40; - return p; + return velocity; } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index e6b5763f2c..c259718a7a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -75,20 +75,18 @@ namespace osu.Game.Tests.Visual.Gameplay { } - protected override FallingParticle SpawnParticle() - { - var p = base.SpawnParticle(); - p.Velocity = new Vector2( - RNG.NextSingle(-MaxVelocity, MaxVelocity), - RNG.NextSingle(-MaxVelocity, MaxVelocity) - ); - p.Duration = RNG.NextSingle(lifetime); - p.StartAngle = RNG.NextSingle(MathF.PI * 2); - p.EndAngle = RNG.NextSingle(MathF.PI * 2); - p.EndScale = RNG.NextSingle(0.5f, 1.5f); - - return p; - } + protected override FallingParticle CreateParticle() => + new FallingParticle + { + Velocity = new Vector2( + RNG.NextSingle(-MaxVelocity, MaxVelocity), + RNG.NextSingle(-MaxVelocity, MaxVelocity) + ), + Duration = RNG.NextSingle(lifetime), + StartAngle = RNG.NextSingle(MathF.PI * 2), + EndAngle = RNG.NextSingle(MathF.PI * 2), + EndScale = RNG.NextSingle(0.5f, 1.5f) + }; } } } diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 8b82dfb7c6..fc119b3ea2 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -53,7 +53,10 @@ namespace osu.Game.Graphics if (Active.Value && CanSpawnParticles && Time.Current > lastParticleAdded + cooldown) { - particles[currentIndex] = SpawnParticle(); + var newParticle = CreateParticle(); + newParticle.StartTime = (float)Time.Current; + + particles[currentIndex] = newParticle; currentIndex = (currentIndex + 1) % particles.Length; lastParticleAdded = Time.Current; @@ -65,13 +68,7 @@ namespace osu.Game.Graphics /// /// Called each time a new particle should be spawned. /// - protected virtual FallingParticle SpawnParticle() - { - return new FallingParticle - { - StartTime = (float)Time.Current, - }; - } + protected virtual FallingParticle CreateParticle() => new FallingParticle(); protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this); From 9127a706ac2444daf504ae60fffb0dc38754fd0f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 16:54:22 +0900 Subject: [PATCH 071/161] Use `private` for internally used property --- osu.Game/Graphics/ParticleSpewer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index fc119b3ea2..c022fd4598 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -26,12 +26,13 @@ namespace osu.Game.Graphics /// public readonly BindableBool Active = new BindableBool(); - public bool HasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current; - public override bool IsPresent => base.IsPresent && HasActiveParticles; + public override bool IsPresent => base.IsPresent && hasActiveParticles; protected virtual bool CanSpawnParticles => true; protected virtual float ParticleGravity => 0; + private bool hasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current; + protected ParticleSpewer(Texture texture, int perSecond, double maxLifetime) { Texture = texture; From 51997fa5330e6694220e7fa0e730d00efae58863 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 16 Sep 2021 16:02:04 +0800 Subject: [PATCH 072/161] Add localisation for GlobalActions --- .../Input/Bindings/GlobalActionContainer.cs | 50 ++++ .../GlobalActionKeyBindingStrings.cs | 254 ++++++++++++++++++ .../Settings/Sections/Input/KeyBindingRow.cs | 2 +- 3 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Localisation/GlobalActionKeyBindingStrings.cs diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 0176a00e9d..73d824a5d2 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -7,6 +7,8 @@ using System.Linq; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Input.Bindings { @@ -137,151 +139,199 @@ namespace osu.Game.Input.Bindings public enum GlobalAction { + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleChat))] [Description("Toggle chat overlay")] ToggleChat, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleSocial))] [Description("Toggle social overlay")] ToggleSocial, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ResetInputSettings))] [Description("Reset input settings")] ResetInputSettings, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleToolbar))] [Description("Toggle toolbar")] ToggleToolbar, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleSettings))] [Description("Toggle settings")] ToggleSettings, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleBeatmapListing))] [Description("Toggle beatmap listing")] ToggleBeatmapListing, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.IncreaseVolume))] [Description("Increase volume")] IncreaseVolume, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.DecreaseVolume))] [Description("Decrease volume")] DecreaseVolume, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleMute))] [Description("Toggle mute")] ToggleMute, // In-Game Keybindings + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SkipCutscene))] [Description("Skip cutscene")] SkipCutscene, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.QuickRetry))] [Description("Quick retry (hold)")] QuickRetry, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.TakeScreenshot))] [Description("Take screenshot")] TakeScreenshot, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleGameplayMouseButtons))] [Description("Toggle gameplay mouse buttons")] ToggleGameplayMouseButtons, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.Back))] [Description("Back")] Back, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.IncreaseScrollSpeed))] [Description("Increase scroll speed")] IncreaseScrollSpeed, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.DecreaseScrollSpeed))] [Description("Decrease scroll speed")] DecreaseScrollSpeed, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.Select))] [Description("Select")] Select, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.QuickExit))] [Description("Quick exit (hold)")] QuickExit, // Game-wide beatmap music controller keybindings + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.MusicNext))] [Description("Next track")] MusicNext, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.MusicPrev))] [Description("Previous track")] MusicPrev, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.MusicPlay))] [Description("Play / pause")] MusicPlay, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleNowPlaying))] [Description("Toggle now playing overlay")] ToggleNowPlaying, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectPrevious))] [Description("Previous selection")] SelectPrevious, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectNext))] [Description("Next selection")] SelectNext, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.Home))] [Description("Home")] Home, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleNotifications))] [Description("Toggle notifications")] ToggleNotifications, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.PauseGameplay))] [Description("Pause gameplay")] PauseGameplay, // Editor + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorSetupMode))] [Description("Setup mode")] EditorSetupMode, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorComposeMode))] [Description("Compose mode")] EditorComposeMode, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorDesignMode))] [Description("Design mode")] EditorDesignMode, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTimingMode))] [Description("Timing mode")] EditorTimingMode, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.HoldForHUD))] [Description("Hold for HUD")] HoldForHUD, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.RandomSkin))] [Description("Random skin")] RandomSkin, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.TogglePauseReplay))] [Description("Pause / resume replay")] TogglePauseReplay, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleInGameInterface))] [Description("Toggle in-game interface")] ToggleInGameInterface, // Song select keybindings + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleModSelection))] [Description("Toggle Mod Select")] ToggleModSelection, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectNextRandom))] [Description("Random")] SelectNextRandom, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectPreviousRandom))] [Description("Rewind")] SelectPreviousRandom, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleBeatmapOptions))] [Description("Beatmap Options")] ToggleBeatmapOptions, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorVerifyMode))] [Description("Verify mode")] EditorVerifyMode, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorNudgeLeft))] [Description("Nudge selection left")] EditorNudgeLeft, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorNudgeRight))] [Description("Nudge selection right")] EditorNudgeRight, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleSkinEditor))] [Description("Toggle skin editor")] ToggleSkinEditor, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.PreviousVolumeMeter))] [Description("Previous volume meter")] PreviousVolumeMeter, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.NextVolumeMeter))] [Description("Next volume meter")] NextVolumeMeter, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SeekReplayForward))] [Description("Seek replay forward")] SeekReplayForward, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SeekReplayBackward))] [Description("Seek replay backward")] SeekReplayBackward, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleChatFocus))] [Description("Toggle chat focus")] ToggleChatFocus } diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs new file mode 100644 index 0000000000..14159f0d34 --- /dev/null +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -0,0 +1,254 @@ +// 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 GlobalActionKeyBindingStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.GlobalActionKeyBinding"; + + /// + /// "Toggle chat overlay" + /// + public static LocalisableString ToggleChat => new TranslatableString(getKey(@"toggle_chat"), @"Toggle chat overlay"); + + /// + /// "Toggle social overlay" + /// + public static LocalisableString ToggleSocial => new TranslatableString(getKey(@"toggle_social"), @"Toggle social overlay"); + + /// + /// "Reset input settings" + /// + public static LocalisableString ResetInputSettings => new TranslatableString(getKey(@"reset_input_settings"), @"Reset input settings"); + + /// + /// "Toggle toolbar" + /// + public static LocalisableString ToggleToolbar => new TranslatableString(getKey(@"toggle_toolbar"), @"Toggle toolbar"); + + /// + /// "Toggle settings" + /// + public static LocalisableString ToggleSettings => new TranslatableString(getKey(@"toggle_settings"), @"Toggle settings"); + + /// + /// "Toggle beatmap listing" + /// + public static LocalisableString ToggleBeatmapListing => new TranslatableString(getKey(@"toggle_beatmap_listing"), @"Toggle beatmap listing"); + + /// + /// "Increase volume" + /// + public static LocalisableString IncreaseVolume => new TranslatableString(getKey(@"increase_volume"), @"Increase volume"); + + /// + /// "Decrease volume" + /// + public static LocalisableString DecreaseVolume => new TranslatableString(getKey(@"decrease_volume"), @"Decrease volume"); + + /// + /// "Toggle mute" + /// + public static LocalisableString ToggleMute => new TranslatableString(getKey(@"toggle_mute"), @"Toggle mute"); + + /// + /// "Skip cutscene" + /// + public static LocalisableString SkipCutscene => new TranslatableString(getKey(@"skip_cutscene"), @"Skip cutscene"); + + /// + /// "Quick retry (hold)" + /// + public static LocalisableString QuickRetry => new TranslatableString(getKey(@"quick_retry"), @"Quick retry (hold)"); + + /// + /// "Take screenshot" + /// + public static LocalisableString TakeScreenshot => new TranslatableString(getKey(@"take_screenshot"), @"Take screenshot"); + + /// + /// "Toggle gameplay mouse buttons" + /// + public static LocalisableString ToggleGameplayMouseButtons => new TranslatableString(getKey(@"toggle_gameplay_mouse_buttons"), @"Toggle gameplay mouse buttons"); + + /// + /// "Back" + /// + public static LocalisableString Back => new TranslatableString(getKey(@"back"), @"Back"); + + /// + /// "Increase scroll speed" + /// + public static LocalisableString IncreaseScrollSpeed => new TranslatableString(getKey(@"increase_scroll_speed"), @"Increase scroll speed"); + + /// + /// "Decrease scroll speed" + /// + public static LocalisableString DecreaseScrollSpeed => new TranslatableString(getKey(@"decrease_scroll_speed"), @"Decrease scroll speed"); + + /// + /// "Select" + /// + public static LocalisableString Select => new TranslatableString(getKey(@"select"), @"Select"); + + /// + /// "Quick exit (hold)" + /// + public static LocalisableString QuickExit => new TranslatableString(getKey(@"quick_exit"), @"Quick exit (hold)"); + + /// + /// "Next track" + /// + public static LocalisableString MusicNext => new TranslatableString(getKey(@"music_next"), @"Next track"); + + /// + /// "Previous track" + /// + public static LocalisableString MusicPrev => new TranslatableString(getKey(@"music_prev"), @"Previous track"); + + /// + /// "Play / pause" + /// + public static LocalisableString MusicPlay => new TranslatableString(getKey(@"music_play"), @"Play / pause"); + + /// + /// "Toggle now playing overlay" + /// + public static LocalisableString ToggleNowPlaying => new TranslatableString(getKey(@"toggle_now_playing"), @"Toggle now playing overlay"); + + /// + /// "Previous selection" + /// + public static LocalisableString SelectPrevious => new TranslatableString(getKey(@"select_previous"), @"Previous selection"); + + /// + /// "Next selection" + /// + public static LocalisableString SelectNext => new TranslatableString(getKey(@"select_next"), @"Next selection"); + + /// + /// "Home" + /// + public static LocalisableString Home => new TranslatableString(getKey(@"home"), @"Home"); + + /// + /// "Toggle notifications" + /// + public static LocalisableString ToggleNotifications => new TranslatableString(getKey(@"toggle_notifications"), @"Toggle notifications"); + + /// + /// "Pause gameplay" + /// + public static LocalisableString PauseGameplay => new TranslatableString(getKey(@"pause_gameplay"), @"Pause gameplay"); + + /// + /// "Setup mode" + /// + public static LocalisableString EditorSetupMode => new TranslatableString(getKey(@"editor_setup_mode"), @"Setup mode"); + + /// + /// "Compose mode" + /// + public static LocalisableString EditorComposeMode => new TranslatableString(getKey(@"editor_compose_mode"), @"Compose mode"); + + /// + /// "Design mode" + /// + public static LocalisableString EditorDesignMode => new TranslatableString(getKey(@"editor_design_mode"), @"Design mode"); + + /// + /// "Timing mode" + /// + public static LocalisableString EditorTimingMode => new TranslatableString(getKey(@"editor_timing_mode"), @"Timing mode"); + + /// + /// "Hold for HUD" + /// + public static LocalisableString HoldForHUD => new TranslatableString(getKey(@"hold_for_hud"), @"Hold for HUD"); + + /// + /// "Random skin" + /// + public static LocalisableString RandomSkin => new TranslatableString(getKey(@"random_skin"), @"Random skin"); + + /// + /// "Pause / resume replay" + /// + public static LocalisableString TogglePauseReplay => new TranslatableString(getKey(@"toggle_pause_replay"), @"Pause / resume replay"); + + /// + /// "Toggle in-game interface" + /// + public static LocalisableString ToggleInGameInterface => new TranslatableString(getKey(@"toggle_in_game_interface"), @"Toggle in-game interface"); + + /// + /// "Toggle Mod Select" + /// + public static LocalisableString ToggleModSelection => new TranslatableString(getKey(@"toggle_mod_selection"), @"Toggle Mod Select"); + + /// + /// "Random" + /// + public static LocalisableString SelectNextRandom => new TranslatableString(getKey(@"select_next_random"), @"Random"); + + /// + /// "Rewind" + /// + public static LocalisableString SelectPreviousRandom => new TranslatableString(getKey(@"select_previous_random"), @"Rewind"); + + /// + /// "Beatmap Options" + /// + public static LocalisableString ToggleBeatmapOptions => new TranslatableString(getKey(@"toggle_beatmap_options"), @"Beatmap Options"); + + /// + /// "Verify mode" + /// + public static LocalisableString EditorVerifyMode => new TranslatableString(getKey(@"editor_verify_mode"), @"Verify mode"); + + /// + /// "Nudge selection left" + /// + public static LocalisableString EditorNudgeLeft => new TranslatableString(getKey(@"editor_nudge_left"), @"Nudge selection left"); + + /// + /// "Nudge selection right" + /// + public static LocalisableString EditorNudgeRight => new TranslatableString(getKey(@"editor_nudge_right"), @"Nudge selection right"); + + /// + /// "Toggle skin editor" + /// + public static LocalisableString ToggleSkinEditor => new TranslatableString(getKey(@"toggle_skin_editor"), @"Toggle skin editor"); + + /// + /// "Previous volume meter" + /// + public static LocalisableString PreviousVolumeMeter => new TranslatableString(getKey(@"previous_volume_meter"), @"Previous volume meter"); + + /// + /// "Next volume meter" + /// + public static LocalisableString NextVolumeMeter => new TranslatableString(getKey(@"next_volume_meter"), @"Next volume meter"); + + /// + /// "Seek replay forward" + /// + public static LocalisableString SeekReplayForward => new TranslatableString(getKey(@"seek_replay_forward"), @"Seek replay forward"); + + /// + /// "Seek replay backward" + /// + public static LocalisableString SeekReplayBackward => new TranslatableString(getKey(@"seek_replay_backward"), @"Seek replay backward"); + + /// + /// "Toggle chat focus" + /// + public static LocalisableString ToggleChatFocus => new TranslatableString(getKey(@"toggle_chat_focus"), @"Toggle chat focus"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index c38c516f21..85d88c96f8 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -115,7 +115,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input }, text = new OsuSpriteText { - Text = action.GetDescription(), + Text = action.GetLocalisableDescription(), Margin = new MarginPadding(padding), }, buttons = new FillFlowContainer From 18e7d86dd4cd60fd81aeff9fd5b7b42723ebd63e Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 16 Sep 2021 17:08:19 +0800 Subject: [PATCH 073/161] Resolve test failure after localizing --- osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 57ba051214..168d9fafcf 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -234,7 +234,7 @@ namespace osu.Game.Tests.Visual.Settings { AddAssert($"Check {name} is bound to {keyName}", () => { - var firstRow = panel.ChildrenOfType().First(r => r.ChildrenOfType().Any(s => s.Text == name)); + var firstRow = panel.ChildrenOfType().First(r => r.ChildrenOfType().Any(s => s.Text.ToString() == name)); var firstButton = firstRow.ChildrenOfType().First(); return firstButton.Text.Text == keyName; @@ -247,7 +247,7 @@ namespace osu.Game.Tests.Visual.Settings AddStep($"Scroll to {name}", () => { - var firstRow = panel.ChildrenOfType().First(r => r.ChildrenOfType().Any(s => s.Text == name)); + var firstRow = panel.ChildrenOfType().First(r => r.ChildrenOfType().Any(s => s.Text.ToString() == name)); firstButton = firstRow.ChildrenOfType().First(); panel.ChildrenOfType().First().ScrollTo(firstButton); From e323f10cd5334f19c9c2578f0e7ea5bd3f262373 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 16 Sep 2021 17:10:29 +0800 Subject: [PATCH 074/161] Remove unused [Description] --- .../Input/Bindings/GlobalActionContainer.cs | 48 ------------------- 1 file changed, 48 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 73d824a5d2..cfb377f74a 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -140,199 +140,151 @@ namespace osu.Game.Input.Bindings public enum GlobalAction { [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleChat))] - [Description("Toggle chat overlay")] ToggleChat, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleSocial))] - [Description("Toggle social overlay")] ToggleSocial, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ResetInputSettings))] - [Description("Reset input settings")] ResetInputSettings, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleToolbar))] - [Description("Toggle toolbar")] ToggleToolbar, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleSettings))] - [Description("Toggle settings")] ToggleSettings, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleBeatmapListing))] - [Description("Toggle beatmap listing")] ToggleBeatmapListing, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.IncreaseVolume))] - [Description("Increase volume")] IncreaseVolume, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.DecreaseVolume))] - [Description("Decrease volume")] DecreaseVolume, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleMute))] - [Description("Toggle mute")] ToggleMute, // In-Game Keybindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SkipCutscene))] - [Description("Skip cutscene")] SkipCutscene, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.QuickRetry))] - [Description("Quick retry (hold)")] QuickRetry, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.TakeScreenshot))] - [Description("Take screenshot")] TakeScreenshot, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleGameplayMouseButtons))] - [Description("Toggle gameplay mouse buttons")] ToggleGameplayMouseButtons, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.Back))] - [Description("Back")] Back, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.IncreaseScrollSpeed))] - [Description("Increase scroll speed")] IncreaseScrollSpeed, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.DecreaseScrollSpeed))] - [Description("Decrease scroll speed")] DecreaseScrollSpeed, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.Select))] - [Description("Select")] Select, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.QuickExit))] - [Description("Quick exit (hold)")] QuickExit, // Game-wide beatmap music controller keybindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.MusicNext))] - [Description("Next track")] MusicNext, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.MusicPrev))] - [Description("Previous track")] MusicPrev, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.MusicPlay))] - [Description("Play / pause")] MusicPlay, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleNowPlaying))] - [Description("Toggle now playing overlay")] ToggleNowPlaying, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectPrevious))] - [Description("Previous selection")] SelectPrevious, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectNext))] - [Description("Next selection")] SelectNext, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.Home))] - [Description("Home")] Home, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleNotifications))] - [Description("Toggle notifications")] ToggleNotifications, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.PauseGameplay))] - [Description("Pause gameplay")] PauseGameplay, // Editor [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorSetupMode))] - [Description("Setup mode")] EditorSetupMode, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorComposeMode))] - [Description("Compose mode")] EditorComposeMode, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorDesignMode))] - [Description("Design mode")] EditorDesignMode, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTimingMode))] - [Description("Timing mode")] EditorTimingMode, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.HoldForHUD))] - [Description("Hold for HUD")] HoldForHUD, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.RandomSkin))] - [Description("Random skin")] RandomSkin, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.TogglePauseReplay))] - [Description("Pause / resume replay")] TogglePauseReplay, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleInGameInterface))] - [Description("Toggle in-game interface")] ToggleInGameInterface, // Song select keybindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleModSelection))] - [Description("Toggle Mod Select")] ToggleModSelection, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectNextRandom))] - [Description("Random")] SelectNextRandom, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SelectPreviousRandom))] - [Description("Rewind")] SelectPreviousRandom, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleBeatmapOptions))] - [Description("Beatmap Options")] ToggleBeatmapOptions, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorVerifyMode))] - [Description("Verify mode")] EditorVerifyMode, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorNudgeLeft))] - [Description("Nudge selection left")] EditorNudgeLeft, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorNudgeRight))] - [Description("Nudge selection right")] EditorNudgeRight, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleSkinEditor))] - [Description("Toggle skin editor")] ToggleSkinEditor, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.PreviousVolumeMeter))] - [Description("Previous volume meter")] PreviousVolumeMeter, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.NextVolumeMeter))] - [Description("Next volume meter")] NextVolumeMeter, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SeekReplayForward))] - [Description("Seek replay forward")] SeekReplayForward, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.SeekReplayBackward))] - [Description("Seek replay backward")] SeekReplayBackward, [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleChatFocus))] - [Description("Toggle chat focus")] ToggleChatFocus } } From f9d5abff8a8d3b6752343c185eb7767a3944a532 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 16 Sep 2021 18:26:12 +0900 Subject: [PATCH 075/161] Update with keybinding changes --- .../UI/PippidonCharacter.cs | 7 ++++--- osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs | 4 ++-- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 9 +++++---- .../Objects/Drawables/DrawableHoldNote.cs | 9 +++++---- .../Objects/Drawables/DrawableHoldNoteHead.cs | 5 +++-- .../Objects/Drawables/DrawableHoldNoteTail.cs | 5 +++-- .../Objects/Drawables/DrawableNote.cs | 7 ++++--- .../Skinning/Legacy/LegacyColumnBackground.cs | 9 +++++---- .../Skinning/Legacy/LegacyKeyArea.cs | 9 +++++---- osu.Game.Rulesets.Mania/UI/Column.cs | 7 ++++--- .../UI/Components/ColumnBackground.cs | 9 +++++---- .../UI/Components/DefaultColumnBackground.cs | 9 +++++---- .../UI/Components/DefaultKeyArea.cs | 9 +++++---- .../Components/PathControlPointVisualiser.cs | 6 +++--- .../Objects/Drawables/DrawableHitCircle.cs | 9 +++++---- .../UI/Cursor/OsuCursorContainer.cs | 9 +++++---- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 6 +++--- .../DrawableTestHit.cs | 3 ++- .../DrawableTestStrongHit.cs | 3 ++- .../Objects/Drawables/DrawableDrumRoll.cs | 5 +++-- .../Objects/Drawables/DrawableDrumRollTick.cs | 7 ++++--- .../Objects/Drawables/DrawableHit.cs | 17 +++++++++-------- .../Objects/Drawables/DrawableSwell.cs | 5 +++-- .../Objects/Drawables/DrawableSwellTick.cs | 3 ++- .../Objects/Drawables/DrawableTaikoHitObject.cs | 5 +++-- .../Skinning/Legacy/LegacyInputDrum.cs | 9 +++++---- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 9 +++++---- .../Visual/Gameplay/TestSceneKeyBindings.cs | 7 ++++--- .../Visual/Gameplay/TestSceneReplayRecorder.cs | 4 ++-- .../Visual/Gameplay/TestSceneReplayRecording.cs | 4 ++-- .../Gameplay/TestSceneSpectatorPlayback.cs | 4 ++-- .../Containers/OsuFocusedOverlayContainer.cs | 6 +++--- osu.Game/Graphics/ScreenshotManager.cs | 7 ++++--- osu.Game/Graphics/UserInterface/BackButton.cs | 7 ++++--- .../Graphics/UserInterface/FocusedTextBox.cs | 6 +++--- .../Graphics/UserInterface/SearchTextBox.cs | 6 +++--- osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs | 7 ++++--- osu.Game/Input/IdleTracker.cs | 8 ++++---- osu.Game/OsuGame.cs | 7 ++++--- .../BeatmapListingSearchControl.cs | 4 ++-- osu.Game/Overlays/ChangelogOverlay.cs | 5 +++-- osu.Game/Overlays/ChatOverlay.cs | 6 +++--- osu.Game/Overlays/DialogOverlay.cs | 7 ++++--- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 2 +- .../Overlays/Music/MusicKeyBindingHandler.cs | 15 ++++++++------- osu.Game/Overlays/Toolbar/Toolbar.cs | 6 +++--- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 6 +++--- .../Overlays/Volume/VolumeControlReceptor.cs | 14 +++++++------- osu.Game/Overlays/Volume/VolumeMeter.cs | 6 +++--- osu.Game/Rulesets/UI/ReplayRecorder.cs | 8 ++++---- osu.Game/Rulesets/UI/RulesetInputManager.cs | 6 +++--- .../UI/Scrolling/DrawableScrollingRuleset.cs | 7 ++++--- .../Compose/Components/BlueprintContainer.cs | 6 +++--- .../Edit/Compose/Components/SelectionHandler.cs | 6 +++--- .../Timeline/TimelineSelectionHandler.cs | 7 ++++--- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 7 ++++--- osu.Game/Screens/Edit/Editor.cs | 12 ++++++------ osu.Game/Screens/Menu/ButtonSystem.cs | 6 +++--- osu.Game/Screens/Menu/ExitConfirmOverlay.cs | 9 +++++---- .../Lounge/Components/RoomsContainer.cs | 14 +++++++------- .../OnlinePlay/Lounge/DrawableLoungeRoom.cs | 6 +++--- .../Match/Components/CreateRoomButton.cs | 7 ++++--- .../Match/Components/RoomSettingsOverlay.cs | 7 ++++--- .../Multiplayer/GameplayChatDisplay.cs | 6 +++--- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 6 +++--- osu.Game/Screens/Play/HUD/HoldForMenuButton.cs | 8 ++++---- osu.Game/Screens/Play/HUDOverlay.cs | 9 +++++---- osu.Game/Screens/Play/HotkeyExitOverlay.cs | 9 +++++---- osu.Game/Screens/Play/HotkeyRetryOverlay.cs | 9 +++++---- osu.Game/Screens/Play/ReplayPlayer.cs | 9 +++++---- osu.Game/Screens/Play/SkipOverlay.cs | 6 +++--- osu.Game/Screens/Ranking/ResultsScreen.cs | 7 ++++--- osu.Game/Screens/Select/BeatmapCarousel.cs | 14 +++++++------- osu.Game/Screens/Select/FooterButton.cs | 6 +++--- osu.Game/Screens/Select/FooterButtonRandom.cs | 11 ++++++----- osu.Game/Screens/Select/SongSelect.cs | 6 +++--- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 7 ++++--- 77 files changed, 302 insertions(+), 257 deletions(-) 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 dd0a20f1b4..98dba622d0 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 @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; using osuTK; @@ -61,9 +62,9 @@ namespace osu.Game.Rulesets.Pippidon.UI } } - public bool OnPressed(PippidonAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case PippidonAction.MoveUp: changeLane(-1); @@ -78,7 +79,7 @@ namespace osu.Game.Rulesets.Pippidon.UI } } - public void OnReleased(PippidonAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs index 73b60f51a4..d0a94767d1 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs @@ -44,9 +44,9 @@ namespace osu.Game.Rulesets.Catch.Mods } // disable keyboard controls - public bool OnPressed(CatchAction action) => true; + public bool OnPressed(KeyBindingPressEvent e) => true; - public void OnReleased(CatchAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index b30c3d82a4..604e878782 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Catch.Replays; @@ -144,9 +145,9 @@ namespace osu.Game.Rulesets.Catch.UI Catcher.VisualDirection = Direction.Left; } - public bool OnPressed(CatchAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case CatchAction.MoveLeft: currentDirection--; @@ -164,9 +165,9 @@ namespace osu.Game.Rulesets.Catch.UI return false; } - public void OnReleased(CatchAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - switch (action) + switch (e.Action) { case CatchAction.MoveLeft: currentDirection++; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 2923a2af2f..4e9781f336 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -7,6 +7,7 @@ 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.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -253,12 +254,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables HoldBrokenTime = Time.Current; } - public bool OnPressed(ManiaAction action) + public bool OnPressed(KeyBindingPressEvent e) { if (AllJudged) return false; - if (action != Action.Value) + if (e.Action != Action.Value) return false; // do not run any of this logic when rewinding, as it inverts order of presses/releases. @@ -288,12 +289,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables isHitting.Value = true; } - public void OnReleased(ManiaAction action) + public void OnReleased(KeyBindingReleaseEvent e) { if (AllJudged) return; - if (action != Action.Value) + if (e.Action != Action.Value) return; // do not run any of this logic when rewinding, as it inverts order of presses/releases. diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs index 8458345998..6722ad8ab8 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Mania.Objects.Drawables @@ -43,9 +44,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables // it will be hidden along with its parenting hold note when required. } - public override bool OnPressed(ManiaAction action) => false; // Handled by the hold note + public override bool OnPressed(KeyBindingPressEvent e) => false; // Handled by the hold note - public override void OnReleased(ManiaAction action) + public override void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs index 18aa3f66d4..803685363c 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mania.Objects.Drawables @@ -68,9 +69,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables }); } - public override bool OnPressed(ManiaAction action) => false; // Handled by the hold note + public override bool OnPressed(KeyBindingPressEvent e) => false; // Handled by the hold note - public override void OnReleased(ManiaAction action) + public override void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index d53c28868d..51727908c9 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Configuration; @@ -97,9 +98,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables ApplyResult(r => r.Type = result); } - public virtual bool OnPressed(ManiaAction action) + public virtual bool OnPressed(KeyBindingPressEvent e) { - if (action != Action.Value) + if (e.Action != Action.Value) return false; if (CheckHittable?.Invoke(this, Time.Current) == false) @@ -108,7 +109,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables return UpdateResult(true); } - public virtual void OnReleased(ManiaAction action) + public virtual void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs index 661e7f66f4..54ddcbd5fe 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; @@ -76,9 +77,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } } - public bool OnPressed(ManiaAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action == Column.Action.Value) + if (e.Action == Column.Action.Value) { light.FadeIn(); light.ScaleTo(Vector2.One); @@ -87,12 +88,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy return false; } - public void OnReleased(ManiaAction action) + public void OnReleased(KeyBindingReleaseEvent e) { // Todo: Should be 400 * 100 / CurrentBPM const double animation_length = 250; - if (action == Column.Action.Value) + if (e.Action == Column.Action.Value) { light.FadeTo(0, animation_length); light.ScaleTo(new Vector2(1, 0), animation_length); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs index 10319a7d4d..9c339345c4 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; 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.UI; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; @@ -86,9 +87,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } } - public bool OnPressed(ManiaAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action == column.Action.Value) + if (e.Action == column.Action.Value) { upSprite.FadeTo(0); downSprite.FadeTo(1); @@ -97,9 +98,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy return false; } - public void OnReleased(ManiaAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - if (action == column.Action.Value) + if (e.Action == column.Action.Value) { upSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(1); downSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(0); diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index f5e30efd91..9d060944cd 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; 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.UI.Components; using osu.Game.Rulesets.UI.Scrolling; @@ -122,16 +123,16 @@ namespace osu.Game.Rulesets.Mania.UI HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result))); } - public bool OnPressed(ManiaAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action != Action.Value) + if (e.Action != Action.Value) return false; sampleTriggerSource.Play(); return true; } - public void OnReleased(ManiaAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs index 75cc351310..77ddc6fbbf 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs @@ -9,6 +9,7 @@ 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; @@ -91,16 +92,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components direction.Value == ScrollingDirection.Up ? dimPoint : brightPoint); } - public bool OnPressed(ManiaAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action == this.action.Value) + if (e.Action == action.Value) backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); return false; } - public void OnReleased(ManiaAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - if (action == this.action.Value) + if (e.Action == action.Value) backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); } } diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs index 4b4bc157d5..807f6a77d9 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs @@ -9,6 +9,7 @@ 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.UI.Scrolling; using osuTK.Graphics; @@ -74,16 +75,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components } } - public bool OnPressed(ManiaAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action == column.Action.Value) + if (e.Action == column.Action.Value) backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); return false; } - public void OnReleased(ManiaAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - if (action == column.Action.Value) + if (e.Action == column.Action.Value) backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); } } diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs index 47cb9bd45a..267ed1f5f4 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs @@ -10,6 +10,7 @@ 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.UI.Scrolling; using osuTK; using osuTK.Graphics; @@ -101,16 +102,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components } } - public bool OnPressed(ManiaAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action == column.Action.Value) + if (e.Action == column.Action.Value) keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint); return false; } - public void OnReleased(ManiaAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - if (action == column.Action.Value) + if (e.Action == column.Action.Value) keyIcon.ScaleTo(1f, 125, Easing.OutQuint); } } 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 6269a41350..1be9b5bf2e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -127,9 +127,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components return false; } - public bool OnPressed(PlatformAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case PlatformAction.Delete: return DeleteSelected(); @@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components return false; } - public void OnReleased(PlatformAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 46fc8f99b2..b6ac62d370 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -9,6 +9,7 @@ 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.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; @@ -228,15 +229,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables CornerExponent = 2; } - public bool OnPressed(OsuAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case OsuAction.LeftButton: case OsuAction.RightButton: if (IsHovered && (Hit?.Invoke() ?? false)) { - HitAction = action; + HitAction = e.Action; return true; } @@ -246,7 +247,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return false; } - public void OnReleased(OsuAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 5812e8cf75..8c76f8a128 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Configuration; @@ -115,9 +116,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor (ActiveCursor as OsuCursor)?.Contract(); } - public bool OnPressed(OsuAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case OsuAction.LeftButton: case OsuAction.RightButton: @@ -129,9 +130,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor return false; } - public void OnReleased(OsuAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - switch (action) + switch (e.Action) { case OsuAction.LeftButton: case OsuAction.RightButton: diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 27d48d1296..4d4340936d 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -89,9 +89,9 @@ namespace osu.Game.Rulesets.Osu.UI base.OnHoverLost(e); } - public bool OnPressed(OsuAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case OsuAction.LeftButton: case OsuAction.RightButton: @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Osu.UI return false; } - public void OnReleased(OsuAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs index f048cad18c..6d4cac0ebe 100644 --- a/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.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.Input.Events; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Scoring; @@ -37,6 +38,6 @@ namespace osu.Game.Rulesets.Taiko.Tests Result.Type = Type; } - public override bool OnPressed(TaikoAction action) => false; + public override bool OnPressed(KeyBindingPressEvent e) => false; } } diff --git a/osu.Game.Rulesets.Taiko.Tests/DrawableTestStrongHit.cs b/osu.Game.Rulesets.Taiko.Tests/DrawableTestStrongHit.cs index 829bcf34a1..ea877c9e17 100644 --- a/osu.Game.Rulesets.Taiko.Tests/DrawableTestStrongHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/DrawableTestStrongHit.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects.Drawables; @@ -30,6 +31,6 @@ namespace osu.Game.Rulesets.Taiko.Tests nestedStrongHit.Result.Type = hitBoth ? Type : HitResult.Miss; } - public override bool OnPressed(TaikoAction action) => false; + public override bool OnPressed(KeyBindingPressEvent e) => false; } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index d066abf767..521189d36c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -11,6 +11,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osuTK.Graphics; using osu.Framework.Graphics; 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; @@ -112,7 +113,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollBody), _ => new ElongatedCirclePiece()); - public override bool OnPressed(TaikoAction action) => false; + public override bool OnPressed(KeyBindingPressEvent e) => false; private void onNewResult(DrawableHitObject obj, JudgementResult result) { @@ -196,7 +197,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); } - public override bool OnPressed(TaikoAction action) => false; + 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 0df45c424d..dc2ed200a1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -4,6 +4,7 @@ using System; using JetBrains.Annotations; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; @@ -61,9 +62,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } } - public override bool OnPressed(TaikoAction action) + public override bool OnPressed(KeyBindingPressEvent e) { - JudgementType = action == TaikoAction.LeftRim || action == TaikoAction.RightRim ? HitType.Rim : HitType.Centre; + JudgementType = e.Action == TaikoAction.LeftRim || e.Action == TaikoAction.RightRim ? HitType.Rim : HitType.Centre; return UpdateResult(true); } @@ -91,7 +92,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); } - public override bool OnPressed(TaikoAction action) => false; + public override bool OnPressed(KeyBindingPressEvent e) => false; } } } diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 1e9fc187eb..97adc5f197 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -8,6 +8,7 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Audio; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; @@ -145,19 +146,19 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = result); } - public override bool OnPressed(TaikoAction action) + public override bool OnPressed(KeyBindingPressEvent e) { if (pressHandledThisFrame) return true; if (Judged) return false; - validActionPressed = HitActions.Contains(action); + validActionPressed = HitActions.Contains(e.Action); // Only count this as handled if the new judgement is a hit var result = UpdateResult(true); if (IsHit) - HitAction = action; + HitAction = e.Action; // Regardless of whether we've hit or not, any secondary key presses in the same frame should be discarded // E.g. hitting a non-strong centre as a strong should not fall through and perform a hit on the next note @@ -165,11 +166,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return result; } - public override void OnReleased(TaikoAction action) + public override void OnReleased(KeyBindingReleaseEvent e) { - if (action == HitAction) + if (e.Action == HitAction) HitAction = null; - base.OnReleased(action); + base.OnReleased(e); } protected override void Update() @@ -265,7 +266,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => r.Type = r.Judgement.MaxResult); } - public override bool OnPressed(TaikoAction action) + public override bool OnPressed(KeyBindingPressEvent e) { // Don't process actions until the main hitobject is hit if (!ParentHitObject.IsHit) @@ -276,7 +277,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return false; // Don't handle invalid hit action presses - if (!ParentHitObject.HitActions.Contains(action)) + if (!ParentHitObject.HitActions.Contains(e.Action)) return false; return UpdateResult(true); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 888f47d341..2d19296d06 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; 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; @@ -266,13 +267,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private bool? lastWasCentre; - public override bool OnPressed(TaikoAction action) + public override bool OnPressed(KeyBindingPressEvent e) { // Don't handle keys before the swell starts if (Time.Current < HitObject.StartTime) return false; - var isCentre = action == TaikoAction.LeftCentre || action == TaikoAction.RightCentre; + var isCentre = e.Action == TaikoAction.LeftCentre || e.Action == TaikoAction.RightCentre; // Ensure alternating centre and rim hits if (lastWasCentre == isCentre) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 47fc7e5ab3..d4ea9ed29f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -3,6 +3,7 @@ using JetBrains.Annotations; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; @@ -34,7 +35,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { } - public override bool OnPressed(TaikoAction action) => false; + public override bool OnPressed(KeyBindingPressEvent e) => false; protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollTick), _ => new TickPiece()); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 6a8d8a611c..eb64ba72f2 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Audio; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Skinning; @@ -76,9 +77,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// public Drawable CreateProxiedContent() => proxiedContent.CreateProxy(); - public abstract bool OnPressed(TaikoAction action); + public abstract bool OnPressed(KeyBindingPressEvent e); - public virtual void OnReleased(TaikoAction action) + public virtual void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs index 9d35093591..86be40dea8 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Skinning; @@ -141,16 +142,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy Centre.Texture = skin.GetTexture(@"taiko-drum-inner"); } - public bool OnPressed(TaikoAction action) + public bool OnPressed(KeyBindingPressEvent e) { Drawable target = null; - if (action == CentreAction) + if (e.Action == CentreAction) { target = Centre; sampleTriggerSource.Play(HitType.Centre); } - else if (action == RimAction) + else if (e.Action == RimAction) { target = Rim; sampleTriggerSource.Play(HitType.Rim); @@ -173,7 +174,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy return false; } - public void OnReleased(TaikoAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index ddfaf64549..861b800038 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -8,6 +8,7 @@ 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.Rulesets.Taiko.Objects; using osu.Game.Rulesets.UI; @@ -151,19 +152,19 @@ namespace osu.Game.Rulesets.Taiko.UI [Resolved(canBeNull: true)] private GameplayClock gameplayClock { get; set; } - public bool OnPressed(TaikoAction action) + public bool OnPressed(KeyBindingPressEvent e) { Drawable target = null; Drawable back = null; - if (action == CentreAction) + if (e.Action == CentreAction) { target = centreHit; back = centre; sampleTriggerSource.Play(HitType.Centre); } - else if (action == RimAction) + else if (e.Action == RimAction) { target = rimHit; back = rim; @@ -195,7 +196,7 @@ namespace osu.Game.Rulesets.Taiko.UI return false; } - public void OnReleased(TaikoAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyBindings.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyBindings.cs index 6de85499c5..0a39d94027 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyBindings.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyBindings.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Input.Bindings; @@ -80,13 +81,13 @@ namespace osu.Game.Tests.Visual.Gameplay { public bool ReceivedAction; - public bool OnPressed(TestAction action) + public bool OnPressed(KeyBindingPressEvent e) { - ReceivedAction = action == TestAction.Down; + ReceivedAction = e.Action == TestAction.Down; return true; } - public void OnReleased(TestAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs index 2ce0213ea2..0a3fedaf8e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs @@ -226,13 +226,13 @@ namespace osu.Game.Tests.Visual.Gameplay return base.OnMouseMove(e); } - public bool OnPressed(TestAction action) + public bool OnPressed(KeyBindingPressEvent e) { box.Colour = Color4.White; return true; } - public void OnReleased(TestAction action) + public void OnReleased(KeyBindingReleaseEvent e) { box.Colour = Color4.Black; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs index 85a2870bf9..dfd5e2dc58 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs @@ -159,13 +159,13 @@ namespace osu.Game.Tests.Visual.Gameplay return base.OnMouseMove(e); } - public bool OnPressed(TestAction action) + public bool OnPressed(KeyBindingPressEvent e) { box.Colour = Color4.White; return true; } - public void OnReleased(TestAction action) + public void OnReleased(KeyBindingReleaseEvent e) { box.Colour = Color4.Black; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs index d9d0dc6c58..6f5f774758 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs @@ -279,13 +279,13 @@ namespace osu.Game.Tests.Visual.Gameplay return base.OnMouseMove(e); } - public bool OnPressed(TestAction action) + public bool OnPressed(KeyBindingPressEvent e) { box.Colour = Color4.White; return true; } - public void OnReleased(TestAction action) + public void OnReleased(KeyBindingReleaseEvent e) { box.Colour = Color4.Black; } diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index b9b098df80..16ec7ab838 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -88,9 +88,9 @@ namespace osu.Game.Graphics.Containers base.OnMouseUp(e); } - public virtual bool OnPressed(GlobalAction action) + public virtual bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Back: Hide(); @@ -103,7 +103,7 @@ namespace osu.Game.Graphics.Containers return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs index fb7fe4947b..9cd403f409 100644 --- a/osu.Game/Graphics/ScreenshotManager.cs +++ b/osu.Game/Graphics/ScreenshotManager.cs @@ -12,6 +12,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Configuration; @@ -57,9 +58,9 @@ namespace osu.Game.Graphics shutter = audio.Samples.Get("UI/shutter"); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.TakeScreenshot: shutter.Play(); @@ -70,7 +71,7 @@ namespace osu.Game.Graphics return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index 1607762908..c965fbcf45 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Input.Bindings; namespace osu.Game.Graphics.UserInterface @@ -61,9 +62,9 @@ namespace osu.Game.Graphics.UserInterface { public Action OnBackPressed; - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Back: OnBackPressed?.Invoke(); @@ -73,7 +74,7 @@ namespace osu.Game.Graphics.UserInterface return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index 6c8238a1b8..ceea9620c8 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -70,11 +70,11 @@ namespace osu.Game.Graphics.UserInterface return base.OnKeyDown(e); } - public virtual bool OnPressed(GlobalAction action) + public virtual bool OnPressed(KeyBindingPressEvent e) { if (!HasFocus) return false; - if (action == GlobalAction.Back) + if (e.Action == GlobalAction.Back) { if (Text.Length > 0) { @@ -86,7 +86,7 @@ namespace osu.Game.Graphics.UserInterface return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs index 4a91741ce6..6937782be6 100644 --- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs @@ -30,9 +30,9 @@ namespace osu.Game.Graphics.UserInterface PlaceholderText = "type to search"; } - public override bool OnPressed(PlatformAction action) + public override bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case PlatformAction.MoveBackwardLine: case PlatformAction.MoveForwardLine: @@ -43,7 +43,7 @@ namespace osu.Game.Graphics.UserInterface return false; } - return base.OnPressed(action); + return base.OnPressed(e); } protected override bool OnKeyDown(KeyDownEvent e) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs index 2cb696be0a..226c39c030 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Overlays; using osuTK; @@ -55,12 +56,12 @@ namespace osu.Game.Graphics.UserInterfaceV2 this.FadeOut(fade_duration, Easing.OutQuint); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { if (State.Value == Visibility.Hidden) return false; - if (action == GlobalAction.Back) + if (e.Action == GlobalAction.Back) { Hide(); return true; @@ -69,7 +70,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game/Input/IdleTracker.cs b/osu.Game/Input/IdleTracker.cs index f3d531cf6c..bfe21f650a 100644 --- a/osu.Game/Input/IdleTracker.cs +++ b/osu.Game/Input/IdleTracker.cs @@ -55,13 +55,13 @@ namespace osu.Game.Input isIdle.Value = TimeSpentIdle > timeToIdle && AllowIdle; } - public bool OnPressed(PlatformAction action) => updateLastInteractionTime(); + public bool OnPressed(KeyBindingPressEvent e) => updateLastInteractionTime(); - public void OnReleased(PlatformAction action) => updateLastInteractionTime(); + public void OnReleased(KeyBindingReleaseEvent e) => updateLastInteractionTime(); - public bool OnPressed(GlobalAction action) => updateLastInteractionTime(); + public bool OnPressed(KeyBindingPressEvent e) => updateLastInteractionTime(); - public void OnReleased(GlobalAction action) => updateLastInteractionTime(); + public void OnReleased(KeyBindingReleaseEvent e) => updateLastInteractionTime(); protected override bool Handle(UIEvent e) { diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ce84c4bd2a..0e55a65aec 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -27,6 +27,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Collections; @@ -968,11 +969,11 @@ namespace osu.Game return component; } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { if (introScreen == null) return false; - switch (action) + switch (e.Action) { case GlobalAction.ResetInputSettings: Host.ResetInputHandlers(); @@ -1006,7 +1007,7 @@ namespace osu.Game #endregion - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index 07a0cfb57f..bbde03aa10 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -186,9 +186,9 @@ namespace osu.Game.Overlays.BeatmapListing return true; } - public override bool OnPressed(GlobalAction action) + public override bool OnPressed(KeyBindingPressEvent e) { - if (!base.OnPressed(action)) + if (!base.OnPressed(e)) return false; TextChanged?.Invoke(); diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index a8f2e654d7..ce12e9554d 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -91,9 +92,9 @@ namespace osu.Game.Overlays Show(); } - public override bool OnPressed(GlobalAction action) + public override bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Back: if (Current.Value == null) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 0445c63eb4..25c5154d4a 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -372,9 +372,9 @@ namespace osu.Game.Overlays return base.OnKeyDown(e); } - public bool OnPressed(PlatformAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case PlatformAction.TabNew: ChannelTabControl.SelectChannelSelectorTab(); @@ -392,7 +392,7 @@ namespace osu.Game.Overlays return false; } - public void OnReleased(PlatformAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index 43ef42a809..d5d31343f2 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -7,6 +7,7 @@ using osu.Game.Overlays.Dialog; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; using System.Linq; +using osu.Framework.Input.Events; namespace osu.Game.Overlays { @@ -83,16 +84,16 @@ namespace osu.Game.Overlays this.FadeOut(PopupDialog.EXIT_DURATION, Easing.InSine); } - public override bool OnPressed(GlobalAction action) + public override bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Select: CurrentDialog?.Buttons.OfType().FirstOrDefault()?.TriggerClick(); return true; } - return base.OnPressed(action); + return base.OnPressed(e); } } } diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index fdef48d556..ec7e49920c 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -416,7 +416,7 @@ namespace osu.Game.Overlays.Mods return base.OnKeyDown(e); } - public override bool OnPressed(GlobalAction action) => false; // handled by back button + public override bool OnPressed(KeyBindingPressEvent e) => false; // handled by back button private void updateAvailableMods() { diff --git a/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs b/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs index f06e02e5e1..dba4bf926f 100644 --- a/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs +++ b/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Input.Bindings; @@ -26,23 +27,23 @@ namespace osu.Game.Overlays.Music [Resolved(canBeNull: true)] private OnScreenDisplay onScreenDisplay { get; set; } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { if (beatmap.Disabled) return false; - switch (action) + switch (e.Action) { case GlobalAction.MusicPlay: // use previous state as TogglePause may not update the track's state immediately (state update is run on the audio thread see https://github.com/ppy/osu/issues/9880#issuecomment-674668842) bool wasPlaying = musicController.IsPlaying; if (musicController.TogglePause()) - onScreenDisplay?.Display(new MusicActionToast(wasPlaying ? "Pause track" : "Play track", action)); + onScreenDisplay?.Display(new MusicActionToast(wasPlaying ? "Pause track" : "Play track", e.Action)); return true; case GlobalAction.MusicNext: - musicController.NextTrack(() => onScreenDisplay?.Display(new MusicActionToast("Next track", action))); + musicController.NextTrack(() => onScreenDisplay?.Display(new MusicActionToast("Next track", e.Action))); return true; @@ -52,11 +53,11 @@ namespace osu.Game.Overlays.Music switch (res) { case PreviousTrackResult.Restart: - onScreenDisplay?.Display(new MusicActionToast("Restart track", action)); + onScreenDisplay?.Display(new MusicActionToast("Restart track", e.Action)); break; case PreviousTrackResult.Previous: - onScreenDisplay?.Display(new MusicActionToast("Previous track", action)); + onScreenDisplay?.Display(new MusicActionToast("Previous track", e.Action)); break; } }); @@ -67,7 +68,7 @@ namespace osu.Game.Overlays.Music return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 7481cfdbf5..dc0b06b255 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -178,12 +178,12 @@ namespace osu.Game.Overlays.Toolbar this.FadeOut(transition_time, Easing.InQuint); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { if (OverlayActivationMode.Value == OverlayActivation.Disabled) return false; - switch (action) + switch (e.Action) { case GlobalAction.ToggleToolbar: hiddenByUser = State.Value == Visibility.Visible; // set before toggling to allow the operation to always succeed. @@ -194,7 +194,7 @@ namespace osu.Game.Overlays.Toolbar return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 6da41b2b5f..dd554200ca 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -184,9 +184,9 @@ namespace osu.Game.Overlays.Toolbar tooltipContainer.FadeOut(100); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action == Hotkey) + if (e.Action == Hotkey) { TriggerClick(); return true; @@ -195,7 +195,7 @@ namespace osu.Game.Overlays.Toolbar return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs index b24214ff3d..4129b46ce3 100644 --- a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs +++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs @@ -19,27 +19,27 @@ namespace osu.Game.Overlays.Volume private ScheduledDelegate keyRepeat; - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.DecreaseVolume: case GlobalAction.IncreaseVolume: keyRepeat?.Cancel(); - keyRepeat = this.BeginKeyRepeat(Scheduler, () => ActionRequested?.Invoke(action), 150); + keyRepeat = this.BeginKeyRepeat(Scheduler, () => ActionRequested?.Invoke(e.Action), 150); return true; case GlobalAction.ToggleMute: case GlobalAction.NextVolumeMeter: case GlobalAction.PreviousVolumeMeter: - ActionRequested?.Invoke(action); + ActionRequested?.Invoke(e.Action); return true; } return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { keyRepeat?.Cancel(); } @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Volume return true; } - public bool OnScroll(GlobalAction action, float amount, bool isPrecise) => - ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false; + public bool OnScroll(KeyBindingScrollEvent e) => + ScrollActionRequested?.Invoke(e.Action, e.ScrollAmount, e.IsPrecise) ?? false; } } diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index 7249dd77e5..ff28b45ebb 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -365,12 +365,12 @@ namespace osu.Game.Overlays.Volume { } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { if (!IsHovered) return false; - switch (action) + switch (e.Action) { case GlobalAction.SelectPrevious: State = SelectionState.Selected; @@ -386,7 +386,7 @@ namespace osu.Game.Overlays.Volume return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Rulesets/UI/ReplayRecorder.cs b/osu.Game/Rulesets/UI/ReplayRecorder.cs index d18e0f9541..b57c224059 100644 --- a/osu.Game/Rulesets/UI/ReplayRecorder.cs +++ b/osu.Game/Rulesets/UI/ReplayRecorder.cs @@ -70,16 +70,16 @@ namespace osu.Game.Rulesets.UI return base.OnMouseMove(e); } - public bool OnPressed(T action) + public bool OnPressed(KeyBindingPressEvent e) { - pressedActions.Add(action); + pressedActions.Add(e.Action); recordFrame(true); return false; } - public void OnReleased(T action) + public void OnReleased(KeyBindingReleaseEvent e) { - pressedActions.Remove(action); + pressedActions.Remove(e.Action); recordFrame(true); } diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index e6cd2aa3dc..a3f311c7a6 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -152,12 +152,12 @@ namespace osu.Game.Rulesets.UI { } - public bool OnPressed(T action) => Target.Children.OfType>().Any(c => c.OnPressed(action, Clock.Rate >= 0)); + public bool OnPressed(KeyBindingPressEvent e) => Target.Children.OfType>().Any(c => c.OnPressed(e.Action, Clock.Rate >= 0)); - public void OnReleased(T action) + public void OnReleased(KeyBindingReleaseEvent e) { foreach (var c in Target.Children.OfType>()) - c.OnReleased(action, Clock.Rate >= 0); + c.OnReleased(e.Action, Clock.Rate >= 0); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index f8d5a6c5a9..7b30bb9574 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Lists; using osu.Framework.Threading; using osu.Game.Beatmaps; @@ -188,12 +189,12 @@ namespace osu.Game.Rulesets.UI.Scrolling /// The amount to adjust by. Greater than 0 if the scroll speed should be increased, less than 0 if it should be decreased. protected virtual void AdjustScrollSpeed(int amount) => this.TransformBindableTo(TimeRange, TimeRange.Value - amount * time_span_step, 200, Easing.OutQuint); - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { if (!UserScrollSpeedAdjustment) return false; - switch (action) + switch (e.Action) { case GlobalAction.IncreaseScrollSpeed: scheduleScrollSpeedAdjustment(1); @@ -209,7 +210,7 @@ namespace osu.Game.Rulesets.UI.Scrolling private ScheduledDelegate scheduledScrollSpeedAdjustment; - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { scheduledScrollSpeedAdjustment?.Cancel(); scheduledScrollSpeedAdjustment = null; diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index b99dacbd4a..75d4d13f94 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -228,9 +228,9 @@ namespace osu.Game.Screens.Edit.Compose.Components return false; } - public bool OnPressed(PlatformAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case PlatformAction.SelectAll: SelectAll(); @@ -240,7 +240,7 @@ namespace osu.Game.Screens.Edit.Compose.Components return false; } - public void OnReleased(PlatformAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 1d1d95890f..44eb062db8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -137,9 +137,9 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Whether any items could be reversed. public virtual bool HandleReverse() => false; - public bool OnPressed(PlatformAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case PlatformAction.Delete: DeleteSelected(); @@ -149,7 +149,7 @@ namespace osu.Game.Screens.Edit.Compose.Components return false; } - public void OnReleased(PlatformAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineSelectionHandler.cs index 354013a5fd..c43e554b85 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineSelectionHandler.cs @@ -4,6 +4,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Objects; using osuTK; @@ -20,9 +21,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline // for now we always allow movement. snapping is provided by the Timeline's "distance" snap implementation public override bool HandleMovement(MoveSelectionEvent moveEvent) => true; - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.EditorNudgeLeft: nudgeSelection(-1); @@ -36,7 +37,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index e324f1edeb..926a2ad4e0 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -9,6 +9,7 @@ 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.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Extensions; @@ -77,15 +78,15 @@ namespace osu.Game.Screens.Edit.Compose #region Input Handling - public bool OnPressed(PlatformAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action == PlatformAction.Copy) + if (e.Action == PlatformAction.Copy) host.GetClipboard()?.SetText(formatSelectionAsString()); return false; } - public void OnReleased(PlatformAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 028662172d..2ff0101dc0 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -347,9 +347,9 @@ namespace osu.Game.Screens.Edit clock.ProcessFrame(); } - public bool OnPressed(PlatformAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case PlatformAction.Cut: Cut(); @@ -379,7 +379,7 @@ namespace osu.Game.Screens.Edit return false; } - public void OnReleased(PlatformAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } @@ -434,9 +434,9 @@ namespace osu.Game.Screens.Edit return true; } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Back: // as we don't want to display the back button, manual handling of exit action is required. @@ -468,7 +468,7 @@ namespace osu.Game.Screens.Edit } } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 6c712e9d5b..5f76176aab 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -218,9 +218,9 @@ namespace osu.Game.Screens.Menu return base.OnKeyDown(e); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Back: return goBack(); @@ -234,7 +234,7 @@ namespace osu.Game.Screens.Menu } } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Menu/ExitConfirmOverlay.cs b/osu.Game/Screens/Menu/ExitConfirmOverlay.cs index a491283e5f..364da2f887 100644 --- a/osu.Game/Screens/Menu/ExitConfirmOverlay.cs +++ b/osu.Game/Screens/Menu/ExitConfirmOverlay.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Overlays; @@ -18,9 +19,9 @@ namespace osu.Game.Screens.Menu { } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action == GlobalAction.Back) + if (e.Action == GlobalAction.Back) { BeginConfirm(); return true; @@ -29,9 +30,9 @@ namespace osu.Game.Screens.Menu return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - if (action == GlobalAction.Back) + if (e.Action == GlobalAction.Back) { if (!Fired) AbortConfirm(); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index 76cb02199b..907b7e308a 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -141,29 +141,29 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components #region Key selection logic (shared with BeatmapCarousel) - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.SelectNext: - beginRepeatSelection(() => selectNext(1), action); + beginRepeatSelection(() => selectNext(1), e.Action); return true; case GlobalAction.SelectPrevious: - beginRepeatSelection(() => selectNext(-1), action); + beginRepeatSelection(() => selectNext(-1), e.Action); return true; } return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.SelectNext: case GlobalAction.SelectPrevious: - endRepeatSelection(action); + endRepeatSelection(e.Action); break; } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 95fa34ab43..d55cccd414 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -132,12 +132,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge }) }; - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { if (SelectedRoom.Value != Room) return false; - switch (action) + switch (e.Action) { case GlobalAction.Select: TriggerClick(); @@ -147,7 +147,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs index 3801463095..53131ab90e 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; namespace osu.Game.Screens.OnlinePlay.Match.Components { @@ -16,12 +17,12 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components Triangles.TriangleScale = 1.5f; } - public bool OnPressed(PlatformAction action) + public bool OnPressed(KeyBindingPressEvent e) { if (!Enabled.Value) return false; - switch (action) + switch (e.Action) { case PlatformAction.DocumentNew: // might as well also handle new tab. it's a bit of an undefined flow on this screen. @@ -33,7 +34,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components return false; } - public void OnReleased(PlatformAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } } diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs index 7a8839cdad..a6cdde14f6 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -63,9 +64,9 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components Settings.Delay(TRANSITION_DURATION / 2).FadeOut(TRANSITION_DURATION / 2); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Select: if (IsLoading) @@ -86,7 +87,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index 3af72fa25a..af0c50a848 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -71,9 +71,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer }, true); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.ToggleChatFocus: if (Textbox.HasFocus) @@ -94,7 +94,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index 0efa66bac0..9e3400b09d 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -187,9 +187,9 @@ namespace osu.Game.Screens.Play InternalButtons.Add(button); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.SelectPrevious: InternalButtons.SelectPrevious(); @@ -211,7 +211,7 @@ namespace osu.Game.Screens.Play return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 284ac899ed..850543136c 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -206,9 +206,9 @@ namespace osu.Game.Screens.Play.HUD base.OnHoverLost(e); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Back: case GlobalAction.PauseGameplay: // in the future this behaviour will differ for replays etc. @@ -220,9 +220,9 @@ namespace osu.Game.Screens.Play.HUD return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Back: case GlobalAction.PauseGameplay: diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 13df9fefa7..54c74a7177 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -11,6 +11,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Configuration; using osu.Game.Input.Bindings; using osu.Game.Overlays; @@ -280,9 +281,9 @@ namespace osu.Game.Screens.Play protected PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay(); - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.HoldForHUD: holdingForHUD = true; @@ -311,9 +312,9 @@ namespace osu.Game.Screens.Play return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.HoldForHUD: holdingForHUD = false; diff --git a/osu.Game/Screens/Play/HotkeyExitOverlay.cs b/osu.Game/Screens/Play/HotkeyExitOverlay.cs index 8d7e2481bf..13b72ffaf6 100644 --- a/osu.Game/Screens/Play/HotkeyExitOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyExitOverlay.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Overlays; @@ -9,17 +10,17 @@ namespace osu.Game.Screens.Play { public class HotkeyExitOverlay : HoldToConfirmOverlay, IKeyBindingHandler { - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action != GlobalAction.QuickExit) return false; + if (e.Action != GlobalAction.QuickExit) return false; BeginConfirm(); return true; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - if (action != GlobalAction.QuickExit) return; + if (e.Action != GlobalAction.QuickExit) return; AbortConfirm(); } diff --git a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs index 58fd941f36..308befe372 100644 --- a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Overlays; @@ -9,17 +10,17 @@ namespace osu.Game.Screens.Play { public class HotkeyRetryOverlay : HoldToConfirmOverlay, IKeyBindingHandler { - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - if (action != GlobalAction.QuickRetry) return false; + if (e.Action != GlobalAction.QuickRetry) return false; BeginConfirm(); return true; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - if (action != GlobalAction.QuickRetry) return; + if (e.Action != GlobalAction.QuickRetry) return; AbortConfirm(); } diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index adbb5a53f6..0c6f1ed911 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Extensions; @@ -49,11 +50,11 @@ namespace osu.Game.Screens.Play private ScheduledDelegate keyboardSeekDelegate; - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { const double keyboard_seek_amount = 5000; - switch (action) + switch (e.Action) { case GlobalAction.SeekReplayBackward: keyboardSeekDelegate?.Cancel(); @@ -83,9 +84,9 @@ namespace osu.Game.Screens.Play } } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.SeekReplayBackward: case GlobalAction.SeekReplayForward: diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index a2145b7014..b04fcba0c6 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -144,9 +144,9 @@ namespace osu.Game.Screens.Play return base.OnMouseMove(e); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.SkipCutscene: if (!button.Enabled.Value) @@ -159,7 +159,7 @@ namespace osu.Game.Screens.Play return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 822ee1cf90..af60296344 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -11,6 +11,7 @@ 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.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -327,9 +328,9 @@ namespace osu.Game.Screens.Ranking } } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Select: statisticsPanel.ToggleVisibility(); @@ -339,7 +340,7 @@ namespace osu.Game.Screens.Ranking return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index b05b7aeb32..5eceae3c6e 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -514,29 +514,29 @@ namespace osu.Game.Screens.Select base.OnKeyUp(e); } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.SelectNext: - beginRepeatSelection(() => SelectNext(1, false), action); + beginRepeatSelection(() => SelectNext(1, false), e.Action); return true; case GlobalAction.SelectPrevious: - beginRepeatSelection(() => SelectNext(-1, false), action); + beginRepeatSelection(() => SelectNext(-1, false), e.Action); return true; } return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.SelectNext: case GlobalAction.SelectPrevious: - endRepeatSelection(action); + endRepeatSelection(e.Action); break; } } diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs index 9c0a68133c..8d2ea47757 100644 --- a/osu.Game/Screens/Select/FooterButton.cs +++ b/osu.Game/Screens/Select/FooterButton.cs @@ -172,9 +172,9 @@ namespace osu.Game.Screens.Select return base.OnClick(e); } - public virtual bool OnPressed(GlobalAction action) + public virtual bool OnPressed(KeyBindingPressEvent e) { - if (action == Hotkey) + if (e.Action == Hotkey) { TriggerClick(); return true; @@ -183,6 +183,6 @@ namespace osu.Game.Screens.Select return false; } - public virtual void OnReleased(GlobalAction action) { } + public virtual void OnReleased(KeyBindingReleaseEvent e) { } } } diff --git a/osu.Game/Screens/Select/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs index 1eaf2c591e..1d4722cf5d 100644 --- a/osu.Game/Screens/Select/FooterButtonRandom.cs +++ b/osu.Game/Screens/Select/FooterButtonRandom.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; @@ -58,11 +59,11 @@ namespace osu.Game.Screens.Select }; } - public override bool OnPressed(GlobalAction action) + public override bool OnPressed(KeyBindingPressEvent e) { - rewindSearch = action == GlobalAction.SelectPreviousRandom; + rewindSearch = e.Action == GlobalAction.SelectPreviousRandom; - if (action != GlobalAction.SelectNextRandom && action != GlobalAction.SelectPreviousRandom) + if (e.Action != GlobalAction.SelectNextRandom && e.Action != GlobalAction.SelectPreviousRandom) { return false; } @@ -71,9 +72,9 @@ namespace osu.Game.Screens.Select return true; } - public override void OnReleased(GlobalAction action) + public override void OnReleased(KeyBindingReleaseEvent e) { - if (action == GlobalAction.SelectPreviousRandom) + if (e.Action == GlobalAction.SelectPreviousRandom) { rewindSearch = false; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 1f0f134ba7..9801098952 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -812,11 +812,11 @@ namespace osu.Game.Screens.Select Schedule(() => BeatmapDetails.Refresh()))); } - public virtual bool OnPressed(GlobalAction action) + public virtual bool OnPressed(KeyBindingPressEvent e) { if (!this.IsCurrentScreen()) return false; - switch (action) + switch (e.Action) { case GlobalAction.Select: FinaliseSelection(); @@ -826,7 +826,7 @@ namespace osu.Game.Screens.Select return false; } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 2562e9c57c..396852365f 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -6,6 +6,7 @@ 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.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Input.Bindings; @@ -32,9 +33,9 @@ namespace osu.Game.Skinning.Editor RelativeSizeAxes = Axes.Both; } - public bool OnPressed(GlobalAction action) + public bool OnPressed(KeyBindingPressEvent e) { - switch (action) + switch (e.Action) { case GlobalAction.Back: if (skinEditor?.State.Value != Visibility.Visible) @@ -97,7 +98,7 @@ namespace osu.Game.Skinning.Editor } } - public void OnReleased(GlobalAction action) + public void OnReleased(KeyBindingReleaseEvent e) { } From e8dea0138cb8fc4de9d6eba5ab9df355489aaf90 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 16 Sep 2021 18:28:35 +0900 Subject: [PATCH 076/161] Fix one more issue --- osu.Game/Screens/Edit/Verify/IssueTable.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Verify/IssueTable.cs b/osu.Game/Screens/Edit/Verify/IssueTable.cs index 05a8fdd26d..b38a62d838 100644 --- a/osu.Game/Screens/Edit/Verify/IssueTable.cs +++ b/osu.Game/Screens/Edit/Verify/IssueTable.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Input.Bindings; @@ -52,7 +53,7 @@ namespace osu.Game.Screens.Edit.Verify if (issue.Time != null) { clock.Seek(issue.Time.Value); - editor.OnPressed(GlobalAction.EditorComposeMode); + editor.OnPressed(new KeyBindingPressEvent(GetContainingInputManager().CurrentState, GlobalAction.EditorComposeMode)); } if (!issue.HitObjects.Any()) From a18fed0da49ba399974bf62322a52da9db1a3300 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 16 Sep 2021 17:38:33 +0800 Subject: [PATCH 077/161] Remove unused using --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index cfb377f74a..f62131e2d7 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Input; From d8f27633a4f05a75475fa330b8f758af2d81632d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 16 Sep 2021 19:35:15 +0900 Subject: [PATCH 078/161] Fix legacy approach circles accepting alpha --- .../TestSceneSkinFallbacks.cs | 5 +- .../Objects/Drawables/DrawableHitCircle.cs | 18 +++++-- osu.Game.Rulesets.Osu/OsuSkinComponents.cs | 1 + .../Skinning/Default/ApproachCircle.cs | 50 ------------------- .../Skinning/Default/DefaultApproachCircle.cs | 49 ++++++++++++++++++ .../Skinning/Legacy/LegacyApproachCircle.cs | 49 ++++++++++++++++++ .../Legacy/OsuLegacySkinTransformer.cs | 3 ++ 7 files changed, 120 insertions(+), 55 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Skinning/Default/ApproachCircle.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs index 662cbaee68..0f362851a9 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs @@ -20,6 +20,7 @@ using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osu.Game.Storyboards; using osu.Game.Tests.Visual; @@ -86,9 +87,9 @@ namespace osu.Game.Rulesets.Osu.Tests if (firstObject == null) return false; - var skinnable = firstObject.ApproachCircle.Child as SkinnableDrawable; + var skinnable = firstObject.ApproachCircle; - if (skin == null && skinnable?.Drawable is Sprite) + if (skin == null && skinnable?.Drawable is DefaultApproachCircle) // check for default skin provider return true; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 46fc8f99b2..7d28ec822d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public OsuAction? HitAction => HitArea.HitAction; protected virtual OsuSkinComponents CirclePieceComponent => OsuSkinComponents.HitCircle; - public ApproachCircle ApproachCircle { get; private set; } + public SkinnableDrawable ApproachCircle { get; private set; } public HitReceptor HitArea { get; private set; } public SkinnableDrawable CirclePiece { get; private set; } @@ -74,8 +74,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - ApproachCircle = new ApproachCircle + ApproachCircle = new ProxyableSkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ApproachCircle), _ => new DefaultApproachCircle()) { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, Alpha = 0, Scale = new Vector2(4), } @@ -88,7 +91,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue)); - AccentColour.BindValueChanged(accent => ApproachCircle.Colour = accent.NewValue); } protected override void LoadComplete() @@ -250,5 +252,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { } } + + private class ProxyableSkinnableDrawable : SkinnableDrawable + { + public override bool RemoveWhenNotAlive => false; + + public ProxyableSkinnableDrawable(ISkinComponent component, Func defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) + : base(component, defaultImplementation, confineMode) + { + } + } } } diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs index 46e501758b..59fe353bd2 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs @@ -18,5 +18,6 @@ namespace osu.Game.Rulesets.Osu SliderBall, SliderBody, SpinnerBody, + ApproachCircle, } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ApproachCircle.cs deleted file mode 100644 index 62f00a2b49..0000000000 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ApproachCircle.cs +++ /dev/null @@ -1,50 +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.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Textures; -using osu.Game.Skinning; -using osuTK; - -namespace osu.Game.Rulesets.Osu.Skinning.Default -{ - public class ApproachCircle : Container - { - public override bool RemoveWhenNotAlive => false; - - public ApproachCircle() - { - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - - RelativeSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load(TextureStore textures) - { - Child = new SkinnableApproachCircle(); - } - - private class SkinnableApproachCircle : SkinnableSprite - { - public SkinnableApproachCircle() - : base("Gameplay/osu/approachcircle") - { - } - - protected override Drawable CreateDefault(ISkinComponent component) - { - var drawable = base.CreateDefault(component); - - // 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. - drawable.Scale = new Vector2(128 / 118f); - - return drawable; - } - } - } -} diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs new file mode 100644 index 0000000000..a522367fe6 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.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.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Default +{ + public class DefaultApproachCircle : SkinnableSprite + { + private readonly IBindable accentColour = new Bindable(); + + [Resolved] + private DrawableHitObject drawableObject { get; set; } + + public DefaultApproachCircle() + : base("Gameplay/osu/approachcircle") + { + } + + [BackgroundDependencyLoader] + private void load() + { + accentColour.BindTo(drawableObject.AccentColour); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + accentColour.BindValueChanged(colour => Colour = colour.NewValue, true); + } + + protected override Drawable CreateDefault(ISkinComponent component) + { + var drawable = base.CreateDefault(component); + + // 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. + drawable.Scale = new Vector2(128 / 118f); + + return drawable; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs new file mode 100644 index 0000000000..09f759fe7d --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.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.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Skinning; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Legacy +{ + public class LegacyApproachCircle : SkinnableSprite + { + private readonly IBindable accentColour = new Bindable(); + + [Resolved] + private DrawableHitObject drawableObject { get; set; } + + public LegacyApproachCircle() + : base("approachcircle") + { + } + + [BackgroundDependencyLoader] + private void load() + { + accentColour.BindTo(drawableObject.AccentColour); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + accentColour.BindValueChanged(colour => Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true); + } + + protected override Drawable CreateDefault(ISkinComponent component) + { + var drawable = base.CreateDefault(component); + + // 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. + drawable.Scale = new Vector2(128 / 118f); + + return drawable; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 41b0a88f11..190195f0a6 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -108,6 +108,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return new LegacyOldStyleSpinner(); return null; + + case OsuSkinComponents.ApproachCircle: + return new LegacyApproachCircle(); } } From bcbd0e096165cd7d1cf3ad871e43b9fc1a79e3e6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 16 Sep 2021 20:06:20 +0900 Subject: [PATCH 079/161] Revert ctor param --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs index 09f759fe7d..6a2cb871b1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private DrawableHitObject drawableObject { get; set; } public LegacyApproachCircle() - : base("approachcircle") + : base("Gameplay/osu/approachcircle") { } From a1d33c1a46f954ae94705a3106ddc9b37e267a68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 22:38:19 +0900 Subject: [PATCH 080/161] 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 d4331a5e65..7707b717e9 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 5a302c5349..390b026497 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 73e0030114..6e852c4321 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From bb132f9509ee954625e75c6461b5b293832ea72b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 22:41:35 +0900 Subject: [PATCH 081/161] Update a few more missed event changes in tests --- .../TestSceneDrawableManiaHitObject.cs | 3 ++- osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs | 5 +++-- osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs index 4a6c59e297..92c95b8fde 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -58,7 +59,7 @@ namespace osu.Game.Rulesets.Mania.Tests AddStep("Hold key", () => { clock.CurrentTime = 0; - note.OnPressed(ManiaAction.Key1); + note.OnPressed(new KeyBindingPressEvent(GetContainingInputManager().CurrentState, ManiaAction.Key1)); }); AddStep("progress time", () => clock.CurrentTime = 500); AddAssert("head is visible", () => note.Head.Alpha == 1); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs index 2326a0c391..f9dc9abd75 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Framework.Input; +using osu.Framework.Input.Events; using osu.Framework.Testing.Input; using osu.Framework.Utils; using osu.Game.Audio; @@ -143,9 +144,9 @@ namespace osu.Game.Rulesets.Osu.Tests pressed = value; if (value) - OnPressed(OsuAction.LeftButton); + OnPressed(new KeyBindingPressEvent(GetContainingInputManager().CurrentState, OsuAction.LeftButton)); else - OnReleased(OsuAction.LeftButton); + OnReleased(new KeyBindingReleaseEvent(GetContainingInputManager().CurrentState, OsuAction.LeftButton)); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs index 1fdcd73dde..575523b168 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs @@ -4,6 +4,7 @@ using System; using NUnit.Framework; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Osu.Objects; @@ -97,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Tests private void scheduleHit() => AddStep("schedule action", () => { var delay = hitCircle.StartTime - hitCircle.HitWindows.WindowFor(HitResult.Great) - Time.Current; - Scheduler.AddDelayed(() => hitAreaReceptor.OnPressed(OsuAction.LeftButton), delay); + Scheduler.AddDelayed(() => hitAreaReceptor.OnPressed(new KeyBindingPressEvent(GetContainingInputManager().CurrentState, OsuAction.LeftButton)), delay); }); } } From edb1230111ef1cc1680ee1a032dc1ca951e8fcef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 16 Sep 2021 22:48:09 +0900 Subject: [PATCH 082/161] Fix potential nullref throw on failed startup --- osu.Game/Database/DatabaseContextFactory.cs | 7 +++++-- osu.Game/OsuGameBase.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs index 1cceb59b11..d402195f29 100644 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ b/osu.Game/Database/DatabaseContextFactory.cs @@ -163,8 +163,11 @@ namespace osu.Game.Database public void FlushConnections() { - foreach (var context in threadContexts.Values) - context.Dispose(); + if (threadContexts != null) + { + foreach (var context in threadContexts.Values) + context.Dispose(); + } recycleThreadContexts(); } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 59a05aec4f..7aa460981a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -527,7 +527,7 @@ namespace osu.Game BeatmapManager?.Dispose(); LocalConfig?.Dispose(); - contextFactory.FlushConnections(); + contextFactory?.FlushConnections(); } } } From 414735b8d083117491ff8cbca9d078b62c5fe0ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 00:18:08 +0900 Subject: [PATCH 083/161] Bump mobile project props realm references --- 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 7707b717e9..0e60a5a99e 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -56,6 +56,6 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 6e852c4321..2158772b83 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -99,6 +99,6 @@ - + From 2983d5468247a5d7db672eaa7db1f6868103370c Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 16 Sep 2021 17:32:23 -0700 Subject: [PATCH 084/161] Fix wiki main page blurb overflowing at higher ui scale --- osu.Game/Overlays/Wiki/WikiMainPage.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 3fb0aa450e..c9ee2cbfd5 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Containers; using HtmlAgilityPack; using osu.Framework.Allocation; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Wiki { @@ -56,12 +56,12 @@ namespace osu.Game.Overlays.Wiki { Vertical = 30, }, - Child = new OsuSpriteText + Child = new OsuTextFlowContainer(t => t.Font = OsuFont.GetFont(Typeface.Inter, size: 12, weight: FontWeight.Light)) { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Text = blurbNode.InnerText, - Font = OsuFont.GetFont(Typeface.Inter, size: 12, weight: FontWeight.Light), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, + TextAnchor = Anchor.TopCentre, } }; } From 55feb47e61878ef97cf890de0e58f731150908cb Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 16 Sep 2021 20:17:21 -0700 Subject: [PATCH 085/161] Disallow track adjustments on playlists / multi lounge --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 08bdd0487a..9481ffc3e4 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -37,6 +37,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { public override string Title => "Lounge"; + public override bool? AllowTrackAdjustments => false; + protected override BackgroundScreen CreateBackground() => new LoungeBackgroundScreen { SelectedRoom = { BindTarget = SelectedRoom } From cd4ba71a6b012f0dd106a099df0ecffdb97d0fbb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 13:22:39 +0900 Subject: [PATCH 086/161] Revert "Merge pull request #14772 from Joehuu/lounge-disallow-track-adj" This reverts commit 06ff4838fb55f3362019ac0e173f10b64ec372b2, reversing changes made to 5453ea0ce99bea69a9f87163a500140b1d7b318a. --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 9481ffc3e4..08bdd0487a 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -37,8 +37,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { public override string Title => "Lounge"; - public override bool? AllowTrackAdjustments => false; - protected override BackgroundScreen CreateBackground() => new LoungeBackgroundScreen { SelectedRoom = { BindTarget = SelectedRoom } From f524e913e1e456fa342f75d6d90b0174ae451940 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 13:23:02 +0900 Subject: [PATCH 087/161] Move `AllowTrackAdjustments` specification to `RoomSubScreen` --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 2 ++ osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 9095b78eb4..bcb793062b 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -29,6 +29,8 @@ namespace osu.Game.Screens.OnlinePlay.Match [Cached(typeof(IBindable))] protected readonly Bindable SelectedItem = new Bindable(); + public override bool? AllowTrackAdjustments => true; + protected override BackgroundScreen CreateBackground() => new RoomBackgroundScreen(Room.Playlist.FirstOrDefault()) { SelectedItem = { BindTarget = SelectedItem } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index 8c4f0c1394..3411c4afb1 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -11,8 +11,6 @@ namespace osu.Game.Screens.OnlinePlay { public override bool DisallowExternalBeatmapRulesetChanges => false; - public override bool? AllowTrackAdjustments => true; - public virtual string ShortTitle => Title; [Resolved(CanBeNull = true)] From 1b13b74740eb42050effc28b0da2f951a0468426 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 13:48:19 +0900 Subject: [PATCH 088/161] Fix skin editor potentially leaving game-wide masking in the wrong state Just going with the simplest way to solve this. Closes https://github.com/ppy/osu/issues/14769. --- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 396852365f..a892ec1ca3 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -82,7 +82,7 @@ namespace osu.Game.Skinning.Editor { if (visibility.NewValue == Visibility.Visible) { - target.Masking = true; + updateMasking(); target.AllowScaling = false; target.RelativePositionAxes = Axes.Both; @@ -93,11 +93,14 @@ namespace osu.Game.Skinning.Editor { target.AllowScaling = true; - target.ScaleTo(1, SkinEditor.TRANSITION_DURATION, Easing.OutQuint).OnComplete(_ => target.Masking = false); + target.ScaleTo(1, SkinEditor.TRANSITION_DURATION, Easing.OutQuint).OnComplete(_ => updateMasking()); target.MoveToX(0f, SkinEditor.TRANSITION_DURATION, Easing.OutQuint); } } + private void updateMasking() => + target.Masking = skinEditor.State.Value == Visibility.Visible; + public void OnReleased(KeyBindingReleaseEvent e) { } From e0bbc677d26cec949720200038a09fd6e0c0331d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 16:23:09 +0900 Subject: [PATCH 089/161] Fix `TestRollbackOnFailure` not cleaning up after itself --- osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs index 5dc25d6643..b2bd60d342 100644 --- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs +++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs @@ -424,14 +424,14 @@ namespace osu.Game.Tests.Beatmaps.IO checkBeatmapCount(osu, 12); checkSingleReferencedFileCount(osu, 18); - var breakTemp = TestResources.GetTestBeatmapForImport(); + var brokenTempFilename = TestResources.GetTestBeatmapForImport(); MemoryStream brokenOsu = new MemoryStream(); - MemoryStream brokenOsz = new MemoryStream(await File.ReadAllBytesAsync(breakTemp)); + MemoryStream brokenOsz = new MemoryStream(await File.ReadAllBytesAsync(brokenTempFilename)); - File.Delete(breakTemp); + File.Delete(brokenTempFilename); - using (var outStream = File.Open(breakTemp, FileMode.CreateNew)) + using (var outStream = File.Open(brokenTempFilename, FileMode.CreateNew)) using (var zip = ZipArchive.Open(brokenOsz)) { zip.AddEntry("broken.osu", brokenOsu, false); @@ -441,7 +441,7 @@ namespace osu.Game.Tests.Beatmaps.IO // this will trigger purging of the existing beatmap (online set id match) but should rollback due to broken osu. try { - await manager.Import(new ImportTask(breakTemp)); + await manager.Import(new ImportTask(brokenTempFilename)); } catch { @@ -456,6 +456,8 @@ namespace osu.Game.Tests.Beatmaps.IO checkSingleReferencedFileCount(osu, 18); Assert.AreEqual(1, loggedExceptionCount); + + File.Delete(brokenTempFilename); } finally { From 2ab235ebe72956b34844f1966b7fca7fa1a5861d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 16:24:21 +0900 Subject: [PATCH 090/161] Use new temporary folder storage for beatmap import tests --- osu.Game.Tests/Resources/TestResources.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index 7170a76b8b..839366d98e 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.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 System; using System.IO; using NUnit.Framework; using osu.Framework.IO.Stores; +using osu.Framework.Testing; namespace osu.Game.Tests.Resources { @@ -11,6 +13,8 @@ namespace osu.Game.Tests.Resources { public const double QUICK_BEATMAP_LENGTH = 10000; + private static readonly TemporaryNativeStorage temp_storage = new TemporaryNativeStorage("TestResources"); + public static DllResourceStore GetStore() => new DllResourceStore(typeof(TestResources).Assembly); public static Stream OpenResource(string name) => GetStore().GetStream($"Resources/{name}"); @@ -25,7 +29,7 @@ namespace osu.Game.Tests.Resources /// A path to a copy of a beatmap archive (osz). Should be deleted after use. public static string GetQuickTestBeatmapForImport() { - var tempPath = Path.GetTempFileName() + ".osz"; + var tempPath = getTempFilename(); using (var stream = OpenResource("Archives/241526 Soleily - Renatus_virtual_quick.osz")) using (var newFile = File.Create(tempPath)) stream.CopyTo(newFile); @@ -41,7 +45,7 @@ namespace osu.Game.Tests.Resources /// A path to a copy of a beatmap archive (osz). Should be deleted after use. public static string GetTestBeatmapForImport(bool virtualTrack = false) { - var tempPath = Path.GetTempFileName() + ".osz"; + var tempPath = getTempFilename(); using (var stream = GetTestBeatmapStream(virtualTrack)) using (var newFile = File.Create(tempPath)) @@ -50,5 +54,7 @@ namespace osu.Game.Tests.Resources Assert.IsTrue(File.Exists(tempPath)); return tempPath; } + + private static string getTempFilename() => temp_storage.GetFullPath(Guid.NewGuid() + ".osz"); } } From c9e76783e64630cd1b9d9b08bebe108d41511886 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Sep 2021 17:14:56 +0900 Subject: [PATCH 091/161] Fix taiko HD not calculating pre-empt correctly --- .../Mods/TaikoModHidden.cs | 29 +++++++------------ .../UI/DrawableTaikoRuleset.cs | 10 +++++++ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index a6b3fe1cd9..5104fd9cff 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -2,43 +2,41 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; +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 TaikoModHidden : ModHidden + public class TaikoModHidden : ModHidden, IApplicableToDrawableRuleset { public override string Description => @"Beats fade out before you hit them!"; public override double ScoreMultiplier => 1.06; - private ControlPointInfo controlPointInfo; + private DrawableTaikoRuleset drawableRuleset; + + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + this.drawableRuleset = (DrawableTaikoRuleset)drawableRuleset; + } protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) { ApplyNormalVisibilityState(hitObject, state); } - protected double MultiplierAt(double position) - { - double beatLength = controlPointInfo.TimingPointAt(position).BeatLength; - double speedMultiplier = controlPointInfo.DifficultyPointAt(position).SpeedMultiplier; - - return speedMultiplier * TimingControlPoint.DEFAULT_BEAT_LENGTH / beatLength; - } - protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) { switch (hitObject) { case DrawableDrumRollTick _: case DrawableHit _: - double preempt = 10000 / MultiplierAt(hitObject.HitObject.StartTime); + double preempt = drawableRuleset.TimeRange.Value / drawableRuleset.ControlPointAt(hitObject.HitObject.StartTime).Multiplier; double start = hitObject.HitObject.StartTime - preempt * 0.6; double duration = preempt * 0.3; @@ -56,10 +54,5 @@ namespace osu.Game.Rulesets.Taiko.Mods break; } } - - public override void ApplyToBeatmap(IBeatmap beatmap) - { - controlPointInfo = beatmap.ControlPointInfo; - } } } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 6ddbf3c16b..824b95639b 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -16,6 +17,7 @@ using osu.Game.Input.Handlers; using osu.Game.Replays; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Timing; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Scoring; using osu.Game.Skinning; @@ -60,6 +62,14 @@ namespace osu.Game.Rulesets.Taiko.UI scroller.Height = ToLocalSpace(playfieldScreen.TopLeft + new Vector2(0, playfieldScreen.Height / 20)).Y; } + public MultiplierControlPoint ControlPointAt(double time) + { + int result = ControlPoints.BinarySearch(new MultiplierControlPoint(time)); + if (result < 0) + result = Math.Clamp(~result - 1, 0, ControlPoints.Count); + return ControlPoints[result]; + } + public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new TaikoPlayfieldAdjustmentContainer(); protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo); From ea68be08cb3fa6badd2f5df51f3fc5bc8a1901e8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Sep 2021 17:27:54 +0900 Subject: [PATCH 092/161] Split magic values into named constants --- osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index 5104fd9cff..b3a54521d8 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -18,6 +18,18 @@ namespace osu.Game.Rulesets.Taiko.Mods public override string Description => @"Beats fade out before you hit them!"; public override double ScoreMultiplier => 1.06; + /// + /// How far away from the hit target should hitobjects start to fade out. + /// Range: [0, 1] + /// + private const float fade_out_start_time = 0.6f; + + /// + /// How long hitobjects take to fade out, in terms of the scrolling length. + /// Range: [0, 1] + /// + private const float fade_out_duration = 0.3f; + private DrawableTaikoRuleset drawableRuleset; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) @@ -37,8 +49,8 @@ namespace osu.Game.Rulesets.Taiko.Mods case DrawableDrumRollTick _: case DrawableHit _: double preempt = drawableRuleset.TimeRange.Value / drawableRuleset.ControlPointAt(hitObject.HitObject.StartTime).Multiplier; - double start = hitObject.HitObject.StartTime - preempt * 0.6; - double duration = preempt * 0.3; + double start = hitObject.HitObject.StartTime - preempt * fade_out_start_time; + double duration = preempt * fade_out_duration; using (hitObject.BeginAbsoluteSequence(start)) { From 5dd0e0d961dacbd71a27d0e340c71a62a7bd3e35 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Sep 2021 17:33:32 +0900 Subject: [PATCH 093/161] Don't apply normal visibility to increased visibility state --- 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 b3a54521d8..baad65297c 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -39,7 +39,6 @@ namespace osu.Game.Rulesets.Taiko.Mods protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) { - ApplyNormalVisibilityState(hitObject, state); } protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) From a4238e49a70b30a6f3a97f61c7731b29d91b2afb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Sep 2021 17:39:34 +0900 Subject: [PATCH 094/161] Revert "Don't apply normal visibility to increased visibility state" This reverts commit 5dd0e0d961dacbd71a27d0e340c71a62a7bd3e35. --- osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index baad65297c..b3a54521d8 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -39,6 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Mods protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) { + ApplyNormalVisibilityState(hitObject, state); } protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) From f584d6593acbd028287049eed49f335832480a16 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Sep 2021 18:10:53 +0900 Subject: [PATCH 095/161] Fix flashlight alignment --- 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 1253b7c8ae..3578e3a734 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.Mods if (!flashlightProperties.IsValid) { - FlashlightPosition = taikoPlayfield.HitTarget.ToSpaceOfOtherDrawable(taikoPlayfield.HitTarget.OriginPosition, this); + FlashlightPosition = ToLocalSpace(taikoPlayfield.HitTarget.ScreenSpaceDrawQuad.Centre); flashlightProperties.Validate(); } } From 1c8e17cf11158720af08f0cda6e5999b68879815 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 18:14:39 +0900 Subject: [PATCH 096/161] Fix the default background parallax being set incorrectly when no screen is present --- osu.Game/Screens/OsuScreenStack.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OsuScreenStack.cs b/osu.Game/Screens/OsuScreenStack.cs index e2a0414df7..ebbcbd7650 100644 --- a/osu.Game/Screens/OsuScreenStack.cs +++ b/osu.Game/Screens/OsuScreenStack.cs @@ -51,6 +51,6 @@ namespace osu.Game.Screens } private void setParallax(IScreen next) => - parallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * ((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f; + parallaxContainer.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * (((IOsuScreen)next)?.BackgroundParallaxAmount ?? 1.0f); } } From a1f587f2c54436e5eff098dcf054085beeea928d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 18:25:23 +0900 Subject: [PATCH 097/161] Add failing test coverage of password entry textbox not regaining focus --- .../TestSceneMultiplayerLoungeSubScreen.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs index 4e2a91af78..b7da31a2b5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs @@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - public void TestJoinRoomWithIncorrectPassword() + public void TestJoinRoomWithIncorrectPasswordViaButton() { DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null; @@ -96,6 +96,24 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("room not joined", () => loungeScreen.IsCurrentScreen()); AddUntilStep("password prompt still visible", () => passwordEntryPopover.State.Value == Visibility.Visible); + AddAssert("textbox still focused", () => InputManager.FocusedDrawable is OsuPasswordTextBox); + } + + [Test] + public void TestJoinRoomWithIncorrectPasswordViaEnter() + { + DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null; + + AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true)); + AddStep("select room", () => InputManager.Key(Key.Down)); + AddStep("attempt join room", () => InputManager.Key(Key.Enter)); + AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType().FirstOrDefault()) != null); + AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "wrong"); + AddStep("press enter", () => InputManager.Key(Key.Enter)); + + AddAssert("room not joined", () => loungeScreen.IsCurrentScreen()); + AddUntilStep("password prompt still visible", () => passwordEntryPopover.State.Value == Visibility.Visible); + AddAssert("textbox still focused", () => InputManager.FocusedDrawable is OsuPasswordTextBox); } [Test] From 027912d4f666db7b7439d76f14294fb11d635a60 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 18:23:36 +0900 Subject: [PATCH 098/161] Refocus the multiplayer password entry textbox on failed join --- osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index d55cccd414..a823db282c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -234,6 +234,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { passwordTextbox.Text = string.Empty; + GetContainingInputManager().ChangeFocus(passwordTextbox); + errorText.Text = error; errorText .FadeIn() From 50f155e4b936e9858fde9d51054330804e94c6c7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 18:30:38 +0900 Subject: [PATCH 099/161] Move login panel related files to own namespace and tidy up class nesting --- osu.Game/Overlays/Login/LoginForm.cs | 108 +++++ osu.Game/Overlays/Login/LoginPanel.cs | 199 +++++++++ osu.Game/Overlays/Login/UserAction.cs | 18 + osu.Game/Overlays/Login/UserDropdown.cs | 121 +++++ osu.Game/Overlays/LoginOverlay.cs | 12 +- .../Sections/General/LoginSettings.cs | 421 ------------------ 6 files changed, 452 insertions(+), 427 deletions(-) create mode 100644 osu.Game/Overlays/Login/LoginForm.cs create mode 100644 osu.Game/Overlays/Login/LoginPanel.cs create mode 100644 osu.Game/Overlays/Login/UserAction.cs create mode 100644 osu.Game/Overlays/Login/UserDropdown.cs delete mode 100644 osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs diff --git a/osu.Game/Overlays/Login/LoginForm.cs b/osu.Game/Overlays/Login/LoginForm.cs new file mode 100644 index 0000000000..9d229c2b3e --- /dev/null +++ b/osu.Game/Overlays/Login/LoginForm.cs @@ -0,0 +1,108 @@ +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Game.Configuration; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Overlays.Settings; +using osuTK; + +namespace osu.Game.Overlays.Login +{ + public class LoginForm : FillFlowContainer + { + private TextBox username; + private TextBox password; + private ShakeContainer shakeSignIn; + + [Resolved(CanBeNull = true)] + private IAPIProvider api { get; set; } + + public Action RequestHide; + + private void performLogin() + { + if (!string.IsNullOrEmpty(username.Text) && !string.IsNullOrEmpty(password.Text)) + api?.Login(username.Text, password.Text); + else + shakeSignIn.Shake(); + } + + [BackgroundDependencyLoader(permitNulls: true)] + private void load(OsuConfigManager config, AccountCreationOverlay accountCreation) + { + Direction = FillDirection.Vertical; + Spacing = new Vector2(0, 5); + AutoSizeAxes = Axes.Y; + RelativeSizeAxes = Axes.X; + Children = new Drawable[] + { + username = new OsuTextBox + { + PlaceholderText = "username", + RelativeSizeAxes = Axes.X, + Text = api?.ProvidedUsername ?? string.Empty, + TabbableContentContainer = this + }, + password = new OsuPasswordTextBox + { + PlaceholderText = "password", + RelativeSizeAxes = Axes.X, + TabbableContentContainer = this, + }, + new SettingsCheckbox + { + LabelText = "Remember username", + Current = config.GetBindable(OsuSetting.SaveUsername), + }, + new SettingsCheckbox + { + LabelText = "Stay signed in", + Current = config.GetBindable(OsuSetting.SavePassword), + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + shakeSignIn = new ShakeContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new SettingsButton + { + Text = "Sign in", + Action = performLogin + }, + } + } + }, + new SettingsButton + { + Text = "Register", + Action = () => + { + RequestHide(); + accountCreation.Show(); + } + } + }; + + password.OnCommit += (sender, newText) => performLogin(); + } + + public override bool AcceptsFocus => true; + + protected override bool OnClick(ClickEvent e) => true; + + protected override void OnFocus(FocusEvent e) + { + Schedule(() => { GetContainingInputManager().ChangeFocus(string.IsNullOrEmpty(username.Text) ? username : password); }); + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Login/LoginPanel.cs b/osu.Game/Overlays/Login/LoginPanel.cs new file mode 100644 index 0000000000..d1e5bfe809 --- /dev/null +++ b/osu.Game/Overlays/Login/LoginPanel.cs @@ -0,0 +1,199 @@ +// 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.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.Users; +using osuTK; +using RectangleF = osu.Framework.Graphics.Primitives.RectangleF; +using Container = osu.Framework.Graphics.Containers.Container; + +namespace osu.Game.Overlays.Login +{ + public class LoginPanel : FillFlowContainer + { + private bool bounding = true; + private LoginForm form; + + [Resolved] + private OsuColour colours { get; set; } + + private UserGridPanel panel; + private UserDropdown dropdown; + + /// + /// Called to request a hide of a parent displaying this container. + /// + public Action RequestHide; + + private readonly IBindable apiState = new Bindable(); + + [Resolved] + private IAPIProvider api { get; set; } + + public override RectangleF BoundingBox => bounding ? base.BoundingBox : RectangleF.Empty; + + public bool Bounding + { + get => bounding; + set + { + bounding = value; + Invalidate(Invalidation.MiscGeometry); + } + } + + public LoginPanel() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + Spacing = new Vector2(0f, 5f); + } + + [BackgroundDependencyLoader] + private void load() + { + apiState.BindTo(api.State); + apiState.BindValueChanged(onlineStateChanged, true); + } + + private void onlineStateChanged(ValueChangedEvent state) => Schedule(() => + { + form = null; + + switch (state.NewValue) + { + case APIState.Offline: + Children = new Drawable[] + { + new OsuSpriteText + { + Text = "ACCOUNT", + Margin = new MarginPadding { Bottom = 5 }, + Font = OsuFont.GetFont(weight: FontWeight.Bold), + }, + form = new LoginForm + { + RequestHide = RequestHide + } + }; + break; + + case APIState.Failing: + case APIState.Connecting: + LinkFlowContainer linkFlow; + + Children = new Drawable[] + { + new LoadingSpinner + { + State = { Value = Visibility.Visible }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + linkFlow = new LinkFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + TextAnchor = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Text = state.NewValue == APIState.Failing ? "Connection is failing, will attempt to reconnect... " : "Attempting to connect... ", + Margin = new MarginPadding { Top = 10, Bottom = 10 }, + }, + }; + + linkFlow.AddLink("cancel", api.Logout, string.Empty); + break; + + case APIState.Online: + Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = 20, Right = 20 }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0f, 10f), + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new[] + { + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Signed in", + Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold), + Margin = new MarginPadding { Top = 5, Bottom = 5 }, + }, + }, + }, + panel = new UserGridPanel(api.LocalUser.Value) + { + RelativeSizeAxes = Axes.X, + Action = RequestHide + }, + dropdown = new UserDropdown { RelativeSizeAxes = Axes.X }, + }, + }, + }; + + panel.Status.BindTo(api.LocalUser.Value.Status); + panel.Activity.BindTo(api.LocalUser.Value.Activity); + + dropdown.Current.BindValueChanged(action => + { + switch (action.NewValue) + { + case UserAction.Online: + api.LocalUser.Value.Status.Value = new UserStatusOnline(); + dropdown.StatusColour = colours.Green; + break; + + case UserAction.DoNotDisturb: + api.LocalUser.Value.Status.Value = new UserStatusDoNotDisturb(); + dropdown.StatusColour = colours.Red; + break; + + case UserAction.AppearOffline: + api.LocalUser.Value.Status.Value = new UserStatusOffline(); + dropdown.StatusColour = colours.Gray7; + break; + + case UserAction.SignOut: + api.Logout(); + break; + } + }, true); + break; + } + + if (form != null) GetContainingInputManager()?.ChangeFocus(form); + }); + + public override bool AcceptsFocus => true; + + protected override bool OnClick(ClickEvent e) => true; + + protected override void OnFocus(FocusEvent e) + { + if (form != null) GetContainingInputManager().ChangeFocus(form); + base.OnFocus(e); + } + } +} diff --git a/osu.Game/Overlays/Login/UserAction.cs b/osu.Game/Overlays/Login/UserAction.cs new file mode 100644 index 0000000000..440d6ea456 --- /dev/null +++ b/osu.Game/Overlays/Login/UserAction.cs @@ -0,0 +1,18 @@ +using System.ComponentModel; + +namespace osu.Game.Overlays.Login +{ + public enum UserAction + { + Online, + + [Description(@"Do not disturb")] + DoNotDisturb, + + [Description(@"Appear offline")] + AppearOffline, + + [Description(@"Sign out")] + SignOut, + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Login/UserDropdown.cs b/osu.Game/Overlays/Login/UserDropdown.cs new file mode 100644 index 0000000000..80f6c7113b --- /dev/null +++ b/osu.Game/Overlays/Login/UserDropdown.cs @@ -0,0 +1,121 @@ +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Login +{ + public class UserDropdown : OsuEnumDropdown + { + protected override DropdownHeader CreateHeader() => new UserDropdownHeader(); + + protected override DropdownMenu CreateMenu() => new UserDropdownMenu(); + + public Color4 StatusColour + { + set + { + if (Header is UserDropdownHeader h) + h.StatusColour = value; + } + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + AccentColour = colours.Gray5; + } + + protected class UserDropdownMenu : OsuDropdownMenu + { + public UserDropdownMenu() + { + Masking = true; + CornerRadius = 5; + + Margin = new MarginPadding { Bottom = 5 }; + + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.25f), + Radius = 4, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Gray3; + } + + protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableUserDropdownMenuItem(item); + + private class DrawableUserDropdownMenuItem : DrawableOsuDropdownMenuItem + { + public DrawableUserDropdownMenuItem(MenuItem item) + : base(item) + { + Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 }; + CornerRadius = 5; + } + + protected override Drawable CreateContent() => new Content + { + Label = { Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 } } + }; + } + } + + private class UserDropdownHeader : OsuDropdownHeader + { + public const float LABEL_LEFT_MARGIN = 20; + + private readonly SpriteIcon statusIcon; + + public Color4 StatusColour + { + set => statusIcon.FadeColour(value, 500, Easing.OutQuint); + } + + public UserDropdownHeader() + { + Foreground.Padding = new MarginPadding { Left = 10, Right = 10 }; + Margin = new MarginPadding { Bottom = 5 }; + Masking = true; + CornerRadius = 5; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.25f), + Radius = 4, + }; + + Icon.Size = new Vector2(14); + Icon.Margin = new MarginPadding(0); + + Foreground.Add(statusIcon = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Regular.Circle, + Size = new Vector2(14), + }); + + Text.Margin = new MarginPadding { Left = LABEL_LEFT_MARGIN }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Gray3; + } + } + } +} diff --git a/osu.Game/Overlays/LoginOverlay.cs b/osu.Game/Overlays/LoginOverlay.cs index e7caaa3aca..f3562aa6d9 100644 --- a/osu.Game/Overlays/LoginOverlay.cs +++ b/osu.Game/Overlays/LoginOverlay.cs @@ -5,17 +5,17 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Overlays.Settings.Sections.General; using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; +using osu.Game.Overlays.Login; namespace osu.Game.Overlays { public class LoginOverlay : OsuFocusedOverlayContainer { - private LoginSettings settingsSection; + private LoginPanel panel; private const float transition_time = 400; @@ -50,7 +50,7 @@ namespace osu.Game.Overlays AutoSizeEasing = Easing.OutQuint, Children = new Drawable[] { - settingsSection = new LoginSettings + panel = new LoginPanel { Padding = new MarginPadding(10), RequestHide = Hide, @@ -75,17 +75,17 @@ namespace osu.Game.Overlays { base.PopIn(); - settingsSection.Bounding = true; + panel.Bounding = true; this.FadeIn(transition_time, Easing.OutQuint); - GetContainingInputManager().ChangeFocus(settingsSection); + GetContainingInputManager().ChangeFocus(panel); } protected override void PopOut() { base.PopOut(); - settingsSection.Bounding = false; + panel.Bounding = false; this.FadeOut(transition_time); } } diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs deleted file mode 100644 index 8f757f7a36..0000000000 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ /dev/null @@ -1,421 +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.UserInterface; -using osu.Game.Configuration; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osuTK; -using osu.Game.Users; -using System.ComponentModel; -using osu.Framework.Bindables; -using osu.Game.Graphics; -using osuTK.Graphics; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Events; -using osu.Game.Graphics.Containers; -using RectangleF = osu.Framework.Graphics.Primitives.RectangleF; -using Container = osu.Framework.Graphics.Containers.Container; - -namespace osu.Game.Overlays.Settings.Sections.General -{ - public class LoginSettings : FillFlowContainer - { - private bool bounding = true; - private LoginForm form; - - [Resolved] - private OsuColour colours { get; set; } - - private UserGridPanel panel; - private UserDropdown dropdown; - - /// - /// Called to request a hide of a parent displaying this container. - /// - public Action RequestHide; - - private readonly IBindable apiState = new Bindable(); - - [Resolved] - private IAPIProvider api { get; set; } - - public override RectangleF BoundingBox => bounding ? base.BoundingBox : RectangleF.Empty; - - public bool Bounding - { - get => bounding; - set - { - bounding = value; - Invalidate(Invalidation.MiscGeometry); - } - } - - public LoginSettings() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Direction = FillDirection.Vertical; - Spacing = new Vector2(0f, 5f); - } - - [BackgroundDependencyLoader] - private void load() - { - apiState.BindTo(api.State); - apiState.BindValueChanged(onlineStateChanged, true); - } - - private void onlineStateChanged(ValueChangedEvent state) => Schedule(() => - { - form = null; - - switch (state.NewValue) - { - case APIState.Offline: - Children = new Drawable[] - { - new OsuSpriteText - { - Text = "ACCOUNT", - Margin = new MarginPadding { Bottom = 5 }, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - }, - form = new LoginForm - { - RequestHide = RequestHide - } - }; - break; - - case APIState.Failing: - case APIState.Connecting: - LinkFlowContainer linkFlow; - - Children = new Drawable[] - { - new LoadingSpinner - { - State = { Value = Visibility.Visible }, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }, - linkFlow = new LinkFlowContainer - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - TextAnchor = Anchor.TopCentre, - AutoSizeAxes = Axes.Both, - Text = state.NewValue == APIState.Failing ? "Connection is failing, will attempt to reconnect... " : "Attempting to connect... ", - Margin = new MarginPadding { Top = 10, Bottom = 10 }, - }, - }; - - linkFlow.AddLink("cancel", api.Logout, string.Empty); - break; - - case APIState.Online: - Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = 20, Right = 20 }, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0f, 10f), - Children = new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new[] - { - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "Signed in", - Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold), - Margin = new MarginPadding { Top = 5, Bottom = 5 }, - }, - }, - }, - panel = new UserGridPanel(api.LocalUser.Value) - { - RelativeSizeAxes = Axes.X, - Action = RequestHide - }, - dropdown = new UserDropdown { RelativeSizeAxes = Axes.X }, - }, - }, - }; - - panel.Status.BindTo(api.LocalUser.Value.Status); - panel.Activity.BindTo(api.LocalUser.Value.Activity); - - dropdown.Current.BindValueChanged(action => - { - switch (action.NewValue) - { - case UserAction.Online: - api.LocalUser.Value.Status.Value = new UserStatusOnline(); - dropdown.StatusColour = colours.Green; - break; - - case UserAction.DoNotDisturb: - api.LocalUser.Value.Status.Value = new UserStatusDoNotDisturb(); - dropdown.StatusColour = colours.Red; - break; - - case UserAction.AppearOffline: - api.LocalUser.Value.Status.Value = new UserStatusOffline(); - dropdown.StatusColour = colours.Gray7; - break; - - case UserAction.SignOut: - api.Logout(); - break; - } - }, true); - break; - } - - if (form != null) GetContainingInputManager()?.ChangeFocus(form); - }); - - public override bool AcceptsFocus => true; - - protected override bool OnClick(ClickEvent e) => true; - - protected override void OnFocus(FocusEvent e) - { - if (form != null) GetContainingInputManager().ChangeFocus(form); - base.OnFocus(e); - } - - private class LoginForm : FillFlowContainer - { - private TextBox username; - private TextBox password; - private ShakeContainer shakeSignIn; - - [Resolved(CanBeNull = true)] - private IAPIProvider api { get; set; } - - public Action RequestHide; - - private void performLogin() - { - if (!string.IsNullOrEmpty(username.Text) && !string.IsNullOrEmpty(password.Text)) - api?.Login(username.Text, password.Text); - else - shakeSignIn.Shake(); - } - - [BackgroundDependencyLoader(permitNulls: true)] - private void load(OsuConfigManager config, AccountCreationOverlay accountCreation) - { - Direction = FillDirection.Vertical; - Spacing = new Vector2(0, 5); - AutoSizeAxes = Axes.Y; - RelativeSizeAxes = Axes.X; - Children = new Drawable[] - { - username = new OsuTextBox - { - PlaceholderText = "username", - RelativeSizeAxes = Axes.X, - Text = api?.ProvidedUsername ?? string.Empty, - TabbableContentContainer = this - }, - password = new OsuPasswordTextBox - { - PlaceholderText = "password", - RelativeSizeAxes = Axes.X, - TabbableContentContainer = this, - }, - new SettingsCheckbox - { - LabelText = "Remember username", - Current = config.GetBindable(OsuSetting.SaveUsername), - }, - new SettingsCheckbox - { - LabelText = "Stay signed in", - Current = config.GetBindable(OsuSetting.SavePassword), - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - shakeSignIn = new ShakeContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = new SettingsButton - { - Text = "Sign in", - Action = performLogin - }, - } - } - }, - new SettingsButton - { - Text = "Register", - Action = () => - { - RequestHide(); - accountCreation.Show(); - } - } - }; - - password.OnCommit += (sender, newText) => performLogin(); - } - - public override bool AcceptsFocus => true; - - protected override bool OnClick(ClickEvent e) => true; - - protected override void OnFocus(FocusEvent e) - { - Schedule(() => { GetContainingInputManager().ChangeFocus(string.IsNullOrEmpty(username.Text) ? username : password); }); - } - } - - private class UserDropdown : OsuEnumDropdown - { - protected override DropdownHeader CreateHeader() => new UserDropdownHeader(); - - protected override DropdownMenu CreateMenu() => new UserDropdownMenu(); - - public Color4 StatusColour - { - set - { - if (Header is UserDropdownHeader h) - h.StatusColour = value; - } - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - AccentColour = colours.Gray5; - } - - private class UserDropdownMenu : OsuDropdownMenu - { - public UserDropdownMenu() - { - Masking = true; - CornerRadius = 5; - - Margin = new MarginPadding { Bottom = 5 }; - - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.25f), - Radius = 4, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - BackgroundColour = colours.Gray3; - } - - protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableUserDropdownMenuItem(item); - - private class DrawableUserDropdownMenuItem : DrawableOsuDropdownMenuItem - { - public DrawableUserDropdownMenuItem(MenuItem item) - : base(item) - { - Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 }; - CornerRadius = 5; - } - - protected override Drawable CreateContent() => new Content - { - Label = { Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 } } - }; - } - } - - private class UserDropdownHeader : OsuDropdownHeader - { - public const float LABEL_LEFT_MARGIN = 20; - - private readonly SpriteIcon statusIcon; - - public Color4 StatusColour - { - set => statusIcon.FadeColour(value, 500, Easing.OutQuint); - } - - public UserDropdownHeader() - { - Foreground.Padding = new MarginPadding { Left = 10, Right = 10 }; - Margin = new MarginPadding { Bottom = 5 }; - Masking = true; - CornerRadius = 5; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.25f), - Radius = 4, - }; - - Icon.Size = new Vector2(14); - Icon.Margin = new MarginPadding(0); - - Foreground.Add(statusIcon = new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Icon = FontAwesome.Regular.Circle, - Size = new Vector2(14), - }); - - Text.Margin = new MarginPadding { Left = LABEL_LEFT_MARGIN }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - BackgroundColour = colours.Gray3; - } - } - } - - private enum UserAction - { - Online, - - [Description(@"Do not disturb")] - DoNotDisturb, - - [Description(@"Appear offline")] - AppearOffline, - - [Description(@"Sign out")] - SignOut, - } - } -} From e49d8d0878c9efc5faebad745171cf02e43a6152 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 17:36:17 +0900 Subject: [PATCH 100/161] Add test coverage of login dialog --- .../Visual/Menus/TestSceneLoginPanel.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs new file mode 100644 index 0000000000..5fdadfc2fb --- /dev/null +++ b/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.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 System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Login; + +namespace osu.Game.Tests.Visual.Menus +{ + [TestFixture] + public class TestSceneLoginPanel : OsuManualInputManagerTestScene + { + private LoginPanel loginPanel; + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create login dialog", () => + { + Add(loginPanel = new LoginPanel + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + }); + }); + } + + [Test] + public void TestBasicLogin() + { + AddStep("logout", () => API.Logout()); + + AddStep("enter password", () => loginPanel.ChildrenOfType().First().Text = "password"); + AddStep("submit", () => loginPanel.ChildrenOfType().First(b => b.Text.ToString() == "Sign in").TriggerClick()); + } + } +} From 2d3913120259fdb34311c423bc691828d2d99c58 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Sep 2021 18:41:03 +0900 Subject: [PATCH 101/161] Refactor taiko flashlight a bit --- .../Mods/TaikoModFlashlight.cs | 17 +++++++++-------- osu.Game/Rulesets/Mods/ModFlashlight.cs | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 3578e3a734..19ba99586b 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -36,24 +36,25 @@ namespace osu.Game.Rulesets.Taiko.Mods public TaikoFlashlight(TaikoPlayfield taikoPlayfield) { this.taikoPlayfield = taikoPlayfield; - FlashlightSize = new Vector2(0, getSizeFor(0)); + FlashlightSize = getSizeFor(0); AddLayout(flashlightProperties); } - private float getSizeFor(int combo) + private Vector2 getSizeFor(int combo) { if (combo > 200) - return default_flashlight_size * 0.8f; - else if (combo > 100) - return default_flashlight_size * 0.9f; - else - return default_flashlight_size; + return new Vector2(0, default_flashlight_size * 0.8f); + + if (combo > 100) + return new Vector2(0, default_flashlight_size * 0.9f); + + return new Vector2(0, default_flashlight_size); } protected override void OnComboChange(ValueChangedEvent e) { - this.TransformTo(nameof(FlashlightSize), new Vector2(0, getSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION); + this.TransformTo(nameof(FlashlightSize), getSizeFor(e.NewValue), FLASHLIGHT_FADE_DURATION); } protected override string FragmentShader => "CircularFlashlight"; diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 7abae71273..f96f8a3c1b 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Mods public abstract class Flashlight : Drawable { - internal BindableInt Combo; + protected internal BindableInt Combo { get; internal set; } private IShader shader; protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(this); From 35c3d75cb8d720583e7b010ff026fdd7885b773c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Sep 2021 18:51:43 +0900 Subject: [PATCH 102/161] Preserve flashlight size through aspect adjustment --- .../Mods/TaikoModFlashlight.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 19ba99586b..12f19a0086 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -43,13 +43,17 @@ namespace osu.Game.Rulesets.Taiko.Mods private Vector2 getSizeFor(int combo) { + Vector2 size; + if (combo > 200) - return new Vector2(0, default_flashlight_size * 0.8f); + size = new Vector2(0, default_flashlight_size * 0.8f); + else if (combo > 100) + size = new Vector2(0, default_flashlight_size * 0.9f); + else + size = new Vector2(0, default_flashlight_size); - if (combo > 100) - return new Vector2(0, default_flashlight_size * 0.9f); - - return new Vector2(0, default_flashlight_size); + // Preserve flashlight size through the playfield's aspect adjustment. + return size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT; } protected override void OnComboChange(ValueChangedEvent e) @@ -66,6 +70,10 @@ namespace osu.Game.Rulesets.Taiko.Mods if (!flashlightProperties.IsValid) { FlashlightPosition = ToLocalSpace(taikoPlayfield.HitTarget.ScreenSpaceDrawQuad.Centre); + + ClearTransforms(targetMember: nameof(FlashlightSize)); + FlashlightSize = getSizeFor(Combo.Value); + flashlightProperties.Validate(); } } From a743a3f3067e375516a0d1bd7c8a37b93400c7cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 19:15:14 +0900 Subject: [PATCH 103/161] Change combo bind logic to be non-weird --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index f96f8a3c1b..a77a83b36c 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -69,9 +69,11 @@ namespace osu.Game.Rulesets.Mods public virtual void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { var flashlight = CreateFlashlight(); - flashlight.Combo = Combo; + flashlight.RelativeSizeAxes = Axes.Both; flashlight.Colour = Color4.Black; + + flashlight.Combo.BindTo(Combo); drawableRuleset.KeyBindingInputManager.Add(flashlight); flashlight.Breaks = drawableRuleset.Beatmap.Breaks; @@ -81,7 +83,8 @@ namespace osu.Game.Rulesets.Mods public abstract class Flashlight : Drawable { - protected internal BindableInt Combo { get; internal set; } + public readonly BindableInt Combo = new BindableInt(); + private IShader shader; protected override DrawNode CreateDrawNode() => new FlashlightDrawNode(this); From be7346d0b76febd7e741e0fe6f97518d3140d2c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 17 Sep 2021 19:18:37 +0900 Subject: [PATCH 104/161] Refactor `getSizeFor` to read a touch better --- osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 12f19a0086..0a325f174e 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -43,17 +43,15 @@ namespace osu.Game.Rulesets.Taiko.Mods private Vector2 getSizeFor(int combo) { - Vector2 size; + float size = default_flashlight_size; if (combo > 200) - size = new Vector2(0, default_flashlight_size * 0.8f); + size *= 0.8f; else if (combo > 100) - size = new Vector2(0, default_flashlight_size * 0.9f); - else - size = new Vector2(0, default_flashlight_size); + size *= 0.9f; // Preserve flashlight size through the playfield's aspect adjustment. - return size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT; + return new Vector2(0, size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT); } protected override void OnComboChange(ValueChangedEvent e) From 9485323a13755b5b9736525bb3a0d90a74f8d2c3 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 17 Sep 2021 20:52:13 +0900 Subject: [PATCH 105/161] Add audio feedback for incorrect MP room password --- osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index a823db282c..70dc14951c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -189,9 +189,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private OsuPasswordTextBox passwordTextbox; private TriangleButton joinButton; private OsuSpriteText errorText; + private Sample sampleJoinFail; [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, AudioManager audio) { Child = new FillFlowContainer { @@ -227,6 +228,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge } }; + sampleJoinFail = audio.Samples.Get(@"UI/password-fail"); + joinButton.Action = () => lounge?.Join(room, passwordTextbox.Text, null, joinFailed); } @@ -244,6 +247,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge .FadeOutFromOne(1000, Easing.In); Body.Shake(); + + Schedule(() => { sampleJoinFail?.Play(); }); } protected override void LoadComplete() From f868feae44044af55106fc9789fb4de637b427f8 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 17 Sep 2021 21:12:39 +0900 Subject: [PATCH 106/161] Remove unnecessary Schedule --- osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 70dc14951c..fe7c7cc364 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -248,7 +248,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge Body.Shake(); - Schedule(() => { sampleJoinFail?.Play(); }); + sampleJoinFail?.Play(); } protected override void LoadComplete() From cc11532d9b48421b5dbbd6915134ef75115f597e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Sep 2021 03:08:42 +0900 Subject: [PATCH 107/161] 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 0e60a5a99e..4859510e6c 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 390b026497..0460de6d72 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 2158772b83..51ca381b63 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From b2b3108afa84f7c156c00876ee75390f8933a2b2 Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Fri, 17 Sep 2021 16:19:41 -0400 Subject: [PATCH 108/161] Resolve addressed issues + Stopped using testing methods in non-testing classes + Resolve Player and add OnSeek event + Take bindings away from BarHitErrorMeter + Add support for ColourHitErrorMeter --- .idea/.idea.osu.Desktop/.idea/discord.xml | 7 +++++ .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 31 ++----------------- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 2 ++ .../Play/HUD/HitErrorMeters/HitErrorMeter.cs | 8 +++++ osu.Game/Screens/Play/Player.cs | 8 ++++- 5 files changed, 26 insertions(+), 30 deletions(-) create mode 100644 .idea/.idea.osu.Desktop/.idea/discord.xml diff --git a/.idea/.idea.osu.Desktop/.idea/discord.xml b/.idea/.idea.osu.Desktop/.idea/discord.xml new file mode 100644 index 0000000000..30bab2abb1 --- /dev/null +++ b/.idea/.idea.osu.Desktop/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 2854fabbae..2b5228cab0 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -10,10 +10,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; -using osu.Framework.Input.Bindings; -using osu.Framework.Testing; using osu.Game.Graphics; -using osu.Game.Input.Bindings; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; @@ -21,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { - public class BarHitErrorMeter : HitErrorMeter, IKeyBindingHandler + public class BarHitErrorMeter : HitErrorMeter { private const int arrow_move_duration = 400; @@ -144,10 +141,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters arrow.Alpha = 0; arrow.Delay(200).FadeInFromZero(600); - - var progressBar = Parent.ChildrenOfType().FirstOrDefault(); - if (progressBar != null) - progressBar.Bar.OnSeek += _ => handleSeek(); } private void createColourBars(OsuColour colours) @@ -287,26 +280,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - private void handleSeek() - { - judgementsContainer.Clear(true); - } - - public bool OnPressed(GlobalAction action) - { - switch (action) - { - case GlobalAction.SeekReplayBackward: - case GlobalAction.SeekReplayForward: - handleSeek(); - return false; - } - - return false; - } - - public void OnReleased(GlobalAction action) - { - } + public override void Clear() => judgementsContainer.Clear(true); } } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index dda2a6da95..ea64d1f4d9 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -33,6 +33,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters judgementsFlow.Push(GetColourForHitResult(judgement.Type)); } + public override void Clear() => judgementsFlow.Clear(true); + private class JudgementFlow : FillFlowContainer { private const int max_available_judgements = 20; diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index 788ba5be8c..22ae3900d6 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -22,6 +22,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [Resolved] private OsuColour colours { get; set; } + [Resolved(canBeNull: true)] + private Player player { get; set; } + public bool UsesFixedAnchor { get; set; } [BackgroundDependencyLoader(true)] @@ -34,6 +37,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { base.LoadComplete(); + if (player != null) + player.OnSeek += Clear; + processor.NewJudgement += OnNewJudgement; } @@ -67,6 +73,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } + public abstract void Clear(); + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e8a2790c94..f0544d5fcd 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -69,6 +69,8 @@ namespace osu.Game.Screens.Play public Action RestartRequested; + public Action OnSeek; + public bool HasFailed { get; private set; } private Bindable mouseWheelDisabled; @@ -584,7 +586,11 @@ namespace osu.Game.Screens.Play /// Seek to a specific time in gameplay. /// /// The destination time to seek to. - public void Seek(double time) => GameplayClockContainer.Seek(time); + public void Seek(double time) + { + GameplayClockContainer.Seek(time); + OnSeek.Invoke(); + } private ScheduledDelegate frameStablePlaybackResetDelegate; From 79438c19a45eecb5c0983e6a14efb98539e3686c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 18 Sep 2021 16:27:30 +0200 Subject: [PATCH 109/161] Fix slider parts not reproxying after first hitobject freed --- .../Objects/Drawables/DrawableSlider.cs | 2 +- .../Skinning/Legacy/LegacyReverseArrow.cs | 29 +++++++++++++++++-- .../Legacy/LegacySliderHeadHitCircle.cs | 27 +++++++++++++++-- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 0e1d1043e3..3acec4498d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -187,7 +187,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables repeatContainer.Clear(false); tickContainer.Clear(false); - OverlayElementContainer.Clear(); + OverlayElementContainer.Clear(false); } protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index b6956693b6..9e4bd258bd 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.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.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -17,12 +18,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy [Resolved(canBeNull: true)] private DrawableHitObject drawableHitObject { get; set; } + private Drawable proxy; + public LegacyReverseArrow(ISkin skin) { this.skin = skin; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load() { AutoSizeAxes = Axes.Both; @@ -36,9 +39,29 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { base.LoadComplete(); + proxy = CreateProxy(); + + if (drawableHitObject != null) + { + drawableHitObject.HitObjectApplied += onHitObjectApplied; + onHitObjectApplied(drawableHitObject); + } + } + + private void onHitObjectApplied(DrawableHitObject drawableObject) + { + Debug.Assert(proxy.Parent == null); + // see logic in LegacySliderHeadHitCircle. - (drawableHitObject as DrawableSliderRepeat)?.DrawableSlider - .OverlayElementContainer.Add(CreateProxy()); + (drawableObject as DrawableSliderRepeat)?.DrawableSlider + .OverlayElementContainer.Add(proxy); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + if (drawableHitObject != null) + drawableHitObject.HitObjectApplied -= onHitObjectApplied; } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs index 83ebdafa50..13ba42ba50 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.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.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Rulesets.Objects.Drawables; @@ -13,6 +14,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy [Resolved(canBeNull: true)] private DrawableHitObject drawableHitObject { get; set; } + private Drawable proxiedHitCircleOverlay; + public LegacySliderHeadHitCircle() : base("sliderstartcircle") { @@ -21,10 +24,30 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected override void LoadComplete() { base.LoadComplete(); + proxiedHitCircleOverlay = HitCircleOverlay.CreateProxy(); + + if (drawableHitObject != null) + { + drawableHitObject.HitObjectApplied += onHitObjectApplied; + onHitObjectApplied(drawableHitObject); + } + } + + private void onHitObjectApplied(DrawableHitObject drawableObject) + { + Debug.Assert(proxiedHitCircleOverlay.Parent == null); // see logic in LegacyReverseArrow. - (drawableHitObject as DrawableSliderHead)?.DrawableSlider - .OverlayElementContainer.Add(HitCircleOverlay.CreateProxy().With(d => d.Depth = float.MinValue)); + (drawableObject as DrawableSliderHead)?.DrawableSlider + .OverlayElementContainer.Add(proxiedHitCircleOverlay.With(d => d.Depth = float.MinValue)); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (drawableHitObject != null) + drawableHitObject.HitObjectApplied -= onHitObjectApplied; } } } From 59657aca9a5e42bef22d93ceb8053557f8bbf8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 18 Sep 2021 16:28:25 +0200 Subject: [PATCH 110/161] Remove redundant qualifier --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 9e4bd258bd..298079fa6c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy string lookupName = new OsuSkinComponent(OsuSkinComponents.ReverseArrow).LookupName; - InternalChild = skin.GetAnimation(lookupName, true, true) ?? Drawable.Empty(); + InternalChild = skin.GetAnimation(lookupName, true, true) ?? Empty(); } protected override void LoadComplete() From c23354bb67fc63d54e490d195436d5adfa1441a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 18 Sep 2021 16:28:44 +0200 Subject: [PATCH 111/161] Remove unused setter --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 298079fa6c..ab774a2b67 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacyReverseArrow : CompositeDrawable { - private ISkin skin { get; set; } + private ISkin skin { get; } [Resolved(canBeNull: true)] private DrawableHitObject drawableHitObject { get; set; } From 680484bb165361ef1b6ea81562266d190937268d Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Sat, 18 Sep 2021 12:04:25 -0400 Subject: [PATCH 112/161] Remove discord.xml Not sure how that slipped in there, but it's gone now! --- .idea/.idea.osu.Desktop/.idea/discord.xml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .idea/.idea.osu.Desktop/.idea/discord.xml diff --git a/.idea/.idea.osu.Desktop/.idea/discord.xml b/.idea/.idea.osu.Desktop/.idea/discord.xml deleted file mode 100644 index 30bab2abb1..0000000000 --- a/.idea/.idea.osu.Desktop/.idea/discord.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file From 12cc16c598f4bab59c0ab0e805ada327c4ca4c18 Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Sat, 18 Sep 2021 12:05:06 -0400 Subject: [PATCH 113/161] Remove unused property in `SongProgress` --- osu.Game/Screens/Play/SongProgress.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index dff2dcc86b..b27a9c5f5d 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -35,8 +35,6 @@ namespace osu.Game.Screens.Play private readonly SongProgressGraph graph; private readonly SongProgressInfo info; - public SongProgressBar Bar => bar; - public Action RequestSeek; /// From f6e279baa1764a876884341a66f3af6ab05afd5d Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Sat, 18 Sep 2021 12:18:11 -0400 Subject: [PATCH 114/161] Add xmldoc to HitErrorMeter.Clear Explains how the method is called and what inheritors should do when implementing it. --- osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index 22ae3900d6..1871519ab5 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -73,6 +73,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } + /// + /// Invoked by when the active seeks through the current beatmap. + /// Any inheritors of should have this method clear their container that displays the hit error results. + /// public abstract void Clear(); protected override void Dispose(bool isDisposing) From 04715a54719766a519287f1bf58538f3d0414d0c Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Sat, 18 Sep 2021 12:20:36 -0400 Subject: [PATCH 115/161] Add null-check when invoking OnSeek --- 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 f0544d5fcd..e982d02baf 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -589,7 +589,7 @@ namespace osu.Game.Screens.Play public void Seek(double time) { GameplayClockContainer.Seek(time); - OnSeek.Invoke(); + OnSeek?.Invoke(); } private ScheduledDelegate frameStablePlaybackResetDelegate; From 36237398fa307f6939306df065e897b4683cf740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 18 Sep 2021 18:24:36 +0200 Subject: [PATCH 116/161] Remove accidental leftover nullable BDL spec --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index ab774a2b67..fd7bfe7e60 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy this.skin = skin; } - [BackgroundDependencyLoader(true)] + [BackgroundDependencyLoader] private void load() { AutoSizeAxes = Axes.Both; From 846cde53b3dd7c2dd79034cb0ef2e214228c976a Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sat, 18 Sep 2021 22:54:12 +0200 Subject: [PATCH 117/161] Add `RelativePositionAxes` support --- .../Gameplay/TestSceneParticleSpewer.cs | 25 +++++++++----- osu.Game/Graphics/ParticleSpewer.cs | 33 ++++++++++++++----- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index c259718a7a..31cc505a0d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -28,8 +28,12 @@ namespace osu.Game.Tests.Visual.Gameplay Child = spewer = createSpewer(); AddToggleStep("toggle spawning", value => spewer.Active.Value = value); - AddSliderStep("particle gravity", 0f, 250f, 0f, value => spewer.Gravity = value); - AddSliderStep("particle velocity", 0f, 500f, 250f, value => spewer.MaxVelocity = value); + AddSliderStep("particle gravity", 0f, 1f, 0f, value => spewer.Gravity = value); + AddSliderStep("particle velocity", 0f, 1f, 0.25f, value => spewer.MaxVelocity = value); + AddStep("move to new location", () => + { + spewer.TransformTo(nameof(spewer.SpawnPosition), new Vector2(RNG.NextSingle(), RNG.NextSingle()), 1000, Easing.Out); + }); } [SetUpSteps] @@ -51,14 +55,15 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("is not present", () => !spewer.IsPresent); } - private TestParticleSpewer createSpewer() - { - return new TestParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2")) + private TestParticleSpewer createSpewer() => + new TestParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2")) { - Anchor = Anchor.Centre, Origin = Anchor.Centre, + RelativePositionAxes = Axes.Both, + RelativeSizeAxes = Axes.Both, + Position = new Vector2(0.5f), + Size = new Vector2(0.5f), }; - } private class TestParticleSpewer : ParticleSpewer { @@ -66,7 +71,10 @@ namespace osu.Game.Tests.Visual.Gameplay private const int rate = 250; public float Gravity; - public float MaxVelocity = 250; + + public float MaxVelocity = 0.25f; + + public Vector2 SpawnPosition { get; set; } = new Vector2(0.5f); protected override float ParticleGravity => Gravity; @@ -82,6 +90,7 @@ namespace osu.Game.Tests.Visual.Gameplay RNG.NextSingle(-MaxVelocity, MaxVelocity), RNG.NextSingle(-MaxVelocity, MaxVelocity) ), + StartPosition = SpawnPosition, Duration = RNG.NextSingle(lifetime), StartAngle = RNG.NextSingle(MathF.PI * 2), EndAngle = RNG.NextSingle(MathF.PI * 2), diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index c022fd4598..6bf9bff05a 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -3,6 +3,7 @@ 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; @@ -83,6 +84,8 @@ namespace osu.Game.Graphics private float currentTime; private float gravity; + private Axes relativePositionAxes; + private Vector2 sourceSize; public ParticleSpewerDrawNode(Sprite source) : base(source) @@ -98,6 +101,8 @@ namespace osu.Game.Graphics currentTime = (float)Source.Time.Current; gravity = Source.ParticleGravity; + relativePositionAxes = Source.RelativePositionAxes; + sourceSize = Source.DrawSize; } protected override void Blit(Action vertexAction) @@ -116,18 +121,11 @@ namespace osu.Game.Graphics var alpha = p.AlphaAtTime(timeSinceStart); if (alpha <= 0) continue; - var scale = p.ScaleAtTime(timeSinceStart); var pos = p.PositionAtTime(timeSinceStart, gravity); + var scale = p.ScaleAtTime(timeSinceStart); var angle = p.AngleAtTime(timeSinceStart); - var width = Texture.DisplayWidth * scale; - var height = Texture.DisplayHeight * scale; - - var rect = new RectangleF( - pos.X - width / 2, - pos.Y - height / 2, - width, - height); + var rect = createDrawRect(pos, scale); var quad = new Quad( transformPosition(rect.TopLeft, rect.Centre, angle), @@ -142,6 +140,23 @@ namespace osu.Game.Graphics } } + private RectangleF createDrawRect(Vector2 position, float scale) + { + var width = Texture.DisplayWidth * scale; + var height = Texture.DisplayHeight * scale; + + if (relativePositionAxes.HasFlagFast(Axes.X)) + position.X *= sourceSize.X; + if (relativePositionAxes.HasFlagFast(Axes.Y)) + position.Y *= sourceSize.Y; + + return new RectangleF( + position.X - width / 2, + position.Y - height / 2, + width, + height); + } + private Vector2 transformPosition(Vector2 pos, Vector2 centre, float angle) { float cos = MathF.Cos(angle); From ef530ed87cc984d2d0b23e8f78ae3c464d04c984 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sat, 18 Sep 2021 23:45:58 +0200 Subject: [PATCH 118/161] Normalize particle velocity based on max duration --- .../Visual/Gameplay/TestSceneParticleSpewer.cs | 2 +- osu.Game/Graphics/ParticleSpewer.cs | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index 31cc505a0d..086b1c2ac2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddToggleStep("toggle spawning", value => spewer.Active.Value = value); AddSliderStep("particle gravity", 0f, 1f, 0f, value => spewer.Gravity = value); - AddSliderStep("particle velocity", 0f, 1f, 0.25f, value => spewer.MaxVelocity = value); + AddSliderStep("particle velocity", 0f, 1f, 0.5f, value => spewer.MaxVelocity = value); AddStep("move to new location", () => { spewer.TransformTo(nameof(spewer.SpawnPosition), new Vector2(RNG.NextSingle(), RNG.NextSingle()), 1000, Easing.Out); diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 6bf9bff05a..1ad4672238 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -82,6 +82,8 @@ namespace osu.Game.Graphics protected new ParticleSpewer Source => (ParticleSpewer)base.Source; + private readonly float maxLifetime; + private float currentTime; private float gravity; private Axes relativePositionAxes; @@ -91,6 +93,7 @@ namespace osu.Game.Graphics : base(source) { particles = new FallingParticle[Source.particles.Length]; + maxLifetime = (float)Source.maxLifetime; } public override void ApplyState() @@ -121,7 +124,7 @@ namespace osu.Game.Graphics var alpha = p.AlphaAtTime(timeSinceStart); if (alpha <= 0) continue; - var pos = p.PositionAtTime(timeSinceStart, gravity); + var pos = p.PositionAtTime(timeSinceStart, gravity, maxLifetime); var scale = p.ScaleAtTime(timeSinceStart); var angle = p.AngleAtTime(timeSinceStart); @@ -187,12 +190,12 @@ namespace osu.Game.Graphics public float AngleAtTime(float timeSinceStart) => StartAngle + (EndAngle - StartAngle) * progressAtTime(timeSinceStart); - public Vector2 PositionAtTime(float timeSinceStart, float gravity) + public Vector2 PositionAtTime(float timeSinceStart, float gravity, float maxDuration) { var progress = progressAtTime(timeSinceStart); - var currentGravity = new Vector2(0, gravity * Duration / 1000 * progress); + var currentGravity = new Vector2(0, gravity * Duration / maxDuration * progress); - return StartPosition + (Velocity + currentGravity) * timeSinceStart / 1000; + return StartPosition + (Velocity + currentGravity) * timeSinceStart / maxDuration; } private float progressAtTime(float timeSinceStart) => Math.Clamp(timeSinceStart / Duration, 0, 1); From 3f8454cb76cc5f2d0c52f8270a27a843bab366eb Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 19 Sep 2021 03:19:16 +0200 Subject: [PATCH 119/161] Remove abstract from `ParticleSpewer` --- .../Skinning/Legacy/LegacyCursorParticles.cs | 218 ++++++++---------- .../Gameplay/TestSceneParticleSpewer.cs | 62 ++--- osu.Game/Graphics/ParticleSpewer.cs | 48 ++-- 3 files changed, 144 insertions(+), 184 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 858ba98b86..d4e5bdd46f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.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; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; @@ -20,12 +20,17 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler + public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler, IRequireHighFrequencyMousePosition { + private const int particle_lifetime_min = 300; + private const int particle_lifetime_max = 1000; + private const float particle_gravity = 240; + public bool Active => breakSpewer?.Active.Value == true || kiaiSpewer?.Active.Value == true; - private LegacyCursorParticleSpewer breakSpewer; - private LegacyCursorParticleSpewer kiaiSpewer; + private Vector2 cursorVelocity; + private ParticleSpewer breakSpewer; + private ParticleSpewer kiaiSpewer; [Resolved(canBeNull: true)] private Player player { get; set; } @@ -45,21 +50,25 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy texture.ScaleAdjust *= 1.6f; } + RelativeSizeAxes = Axes.Both; + Anchor = Anchor.Centre; InternalChildren = new[] { - breakSpewer = new LegacyCursorParticleSpewer(texture, 20) + breakSpewer = new ParticleSpewer(texture, 20, particle_lifetime_max) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = Vector2.One, Colour = starBreakAdditive, - Direction = SpewDirection.None, + ParticleGravity = particle_gravity, + CreateParticle = createBreakParticle, }, - kiaiSpewer = new LegacyCursorParticleSpewer(texture, 60) + kiaiSpewer = new ParticleSpewer(texture, 60, particle_lifetime_max) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = Vector2.One, Colour = starBreakAdditive, - Direction = SpewDirection.None, + ParticleGravity = particle_gravity, + CreateParticle = createParticle, }, }; @@ -85,6 +94,39 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy kiaiSpewer.Active.Value = kiaiHitObject != null; } + private Vector2? cursorScreenPosition; + + private const double max_velocity_frame_length = 15; + private double velocityFrameLength; + private Vector2 totalPosDifference; + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + + protected override bool OnMouseMove(MouseMoveEvent e) + { + if (cursorScreenPosition == null) + { + cursorScreenPosition = e.ScreenSpaceMousePosition; + return base.OnMouseMove(e); + } + + // calculate cursor velocity. + totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value; + cursorScreenPosition = e.ScreenSpaceMousePosition; + + velocityFrameLength += Math.Abs(Clock.ElapsedFrameTime); + + if (velocityFrameLength > max_velocity_frame_length) + { + cursorVelocity = totalPosDifference / (float)velocityFrameLength; + + totalPosDifference = Vector2.Zero; + velocityFrameLength = 0; + } + + return base.OnMouseMove(e); + } + public bool OnPressed(OsuAction action) { handleInput(action, true); @@ -111,125 +153,53 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy rightPressed = pressed; break; } + } + + private ParticleSpewer.FallingParticle? createParticle() + { + if (!cursorScreenPosition.HasValue) return null; + + return new ParticleSpewer.FallingParticle + { + StartPosition = ToLocalSpace(cursorScreenPosition.Value), + Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max), + StartAngle = (float)(RNG.NextDouble() * 4 - 2), + EndAngle = RNG.NextSingle(-2f, 2f), + EndScale = RNG.NextSingle(2f), + Velocity = cursorVelocity * 40, + }; + } + + private ParticleSpewer.FallingParticle? createBreakParticle() + { + var baseParticle = createParticle(); + if (!baseParticle.HasValue) return null; + + var p = baseParticle.Value; if (leftPressed && rightPressed) - breakSpewer.Direction = SpewDirection.Omni; + { + p.Velocity += new Vector2( + RNG.NextSingle(-460f, 460f), + RNG.NextSingle(-160f, 160f) + ); + } else if (leftPressed) - breakSpewer.Direction = SpewDirection.Left; + { + p.Velocity += new Vector2( + RNG.NextSingle(-460f, 0), + RNG.NextSingle(-40f, 40f) + ); + } else if (rightPressed) - breakSpewer.Direction = SpewDirection.Right; - else - breakSpewer.Direction = SpewDirection.None; - } - - private class LegacyCursorParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition - { - private const int particle_lifetime_min = 300; - private const int particle_lifetime_max = 1000; - - public SpewDirection Direction { get; set; } - - protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue; - protected override float ParticleGravity => 240; - - public LegacyCursorParticleSpewer(Texture texture, int perSecond) - : base(texture, perSecond, particle_lifetime_max) { - Active.BindValueChanged(_ => resetVelocityCalculation()); + p.Velocity += new Vector2( + RNG.NextSingle(0, 460f), + RNG.NextSingle(-40f, 40f) + ); } - private Vector2? cursorScreenPosition; - private Vector2 cursorVelocity; - - private const double max_velocity_frame_length = 15; - private double velocityFrameLength; - private Vector2 totalPosDifference; - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (cursorScreenPosition == null) - { - cursorScreenPosition = e.ScreenSpaceMousePosition; - return base.OnMouseMove(e); - } - - // calculate cursor velocity. - totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value; - cursorScreenPosition = e.ScreenSpaceMousePosition; - - velocityFrameLength += Clock.ElapsedFrameTime; - - if (velocityFrameLength > max_velocity_frame_length) - { - cursorVelocity = totalPosDifference / (float)velocityFrameLength; - - totalPosDifference = Vector2.Zero; - velocityFrameLength = 0; - } - - return base.OnMouseMove(e); - } - - private void resetVelocityCalculation() - { - cursorScreenPosition = null; - totalPosDifference = Vector2.Zero; - velocityFrameLength = 0; - } - - protected override FallingParticle CreateParticle() => - new FallingParticle - { - StartPosition = ToLocalSpace(cursorScreenPosition ?? Vector2.Zero), - Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max), - StartAngle = (float)(RNG.NextDouble() * 4 - 2), - EndAngle = RNG.NextSingle(-2f, 2f), - EndScale = RNG.NextSingle(2f), - Velocity = getVelocity(), - }; - - private Vector2 getVelocity() - { - Vector2 velocity = Vector2.Zero; - - switch (Direction) - { - case SpewDirection.Left: - velocity = new Vector2( - RNG.NextSingle(-460f, 0), - RNG.NextSingle(-40f, 40f) - ); - break; - - case SpewDirection.Right: - velocity = new Vector2( - RNG.NextSingle(0, 460f), - RNG.NextSingle(-40f, 40f) - ); - break; - - case SpewDirection.Omni: - velocity = new Vector2( - RNG.NextSingle(-460f, 460f), - RNG.NextSingle(-160f, 160f) - ); - break; - } - - velocity += cursorVelocity * 40; - - return velocity; - } - } - - private enum SpewDirection - { - None, - Left, - Right, - Omni, + return p; } } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index 086b1c2ac2..390534745d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -5,7 +5,6 @@ using System; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Graphics; @@ -17,7 +16,12 @@ namespace osu.Game.Tests.Visual.Gameplay [TestFixture] public class TestSceneParticleSpewer : OsuTestScene { - private TestParticleSpewer spewer; + private const int max_particle_duration = 1500; + + private float particleMaxVelocity = 0.5f; + private Vector2 particleSpawnPosition = new Vector2(0.5f); + + private ParticleSpewer spewer; [Resolved] private SkinManager skinManager { get; set; } @@ -28,11 +32,11 @@ namespace osu.Game.Tests.Visual.Gameplay Child = spewer = createSpewer(); AddToggleStep("toggle spawning", value => spewer.Active.Value = value); - AddSliderStep("particle gravity", 0f, 1f, 0f, value => spewer.Gravity = value); - AddSliderStep("particle velocity", 0f, 1f, 0.5f, value => spewer.MaxVelocity = value); + AddSliderStep("particle velocity", 0f, 1f, 0.5f, value => particleMaxVelocity = value); + AddSliderStep("particle gravity", 0f, 1f, 0f, value => spewer.ParticleGravity = value); AddStep("move to new location", () => { - spewer.TransformTo(nameof(spewer.SpawnPosition), new Vector2(RNG.NextSingle(), RNG.NextSingle()), 1000, Easing.Out); + this.TransformTo(nameof(particleSpawnPosition), new Vector2(RNG.NextSingle(), RNG.NextSingle()), 1000, Easing.Out); }); } @@ -55,47 +59,29 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("is not present", () => !spewer.IsPresent); } - private TestParticleSpewer createSpewer() => - new TestParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2")) + private ParticleSpewer createSpewer() => + new ParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2"), 1500, max_particle_duration) { Origin = Anchor.Centre, RelativePositionAxes = Axes.Both, RelativeSizeAxes = Axes.Both, Position = new Vector2(0.5f), Size = new Vector2(0.5f), + CreateParticle = createParticle, }; - private class TestParticleSpewer : ParticleSpewer - { - private const int lifetime = 1500; - private const int rate = 250; - - public float Gravity; - - public float MaxVelocity = 0.25f; - - public Vector2 SpawnPosition { get; set; } = new Vector2(0.5f); - - protected override float ParticleGravity => Gravity; - - public TestParticleSpewer(Texture texture) - : base(texture, rate, lifetime) + private ParticleSpewer.FallingParticle? createParticle() => + new ParticleSpewer.FallingParticle { - } - - protected override FallingParticle CreateParticle() => - new FallingParticle - { - Velocity = new Vector2( - RNG.NextSingle(-MaxVelocity, MaxVelocity), - RNG.NextSingle(-MaxVelocity, MaxVelocity) - ), - StartPosition = SpawnPosition, - Duration = RNG.NextSingle(lifetime), - StartAngle = RNG.NextSingle(MathF.PI * 2), - EndAngle = RNG.NextSingle(MathF.PI * 2), - EndScale = RNG.NextSingle(0.5f, 1.5f) - }; - } + Velocity = new Vector2( + RNG.NextSingle(-particleMaxVelocity, particleMaxVelocity), + RNG.NextSingle(-particleMaxVelocity, particleMaxVelocity) + ), + StartPosition = particleSpawnPosition, + Duration = RNG.NextSingle(max_particle_duration), + StartAngle = RNG.NextSingle(MathF.PI * 2), + EndAngle = RNG.NextSingle(MathF.PI * 2), + EndScale = RNG.NextSingle(0.5f, 1.5f) + }; } } diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 1ad4672238..911f5894e7 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -13,14 +13,14 @@ using osuTK; namespace osu.Game.Graphics { - public abstract class ParticleSpewer : Sprite + public class ParticleSpewer : Sprite { private readonly FallingParticle[] particles; private int currentIndex; private double lastParticleAdded; private readonly double cooldown; - private readonly double maxLifetime; + private readonly double maxDuration; /// /// Determines whether particles are being spawned. @@ -29,20 +29,24 @@ namespace osu.Game.Graphics public override bool IsPresent => base.IsPresent && hasActiveParticles; - protected virtual bool CanSpawnParticles => true; - protected virtual float ParticleGravity => 0; + /// + /// Called each time a new particle should be spawned. + /// + public Func CreateParticle = () => new FallingParticle(); - private bool hasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current; + public float ParticleGravity; - protected ParticleSpewer(Texture texture, int perSecond, double maxLifetime) + private bool hasActiveParticles => Active.Value || (lastParticleAdded + maxDuration) > Time.Current; + + public ParticleSpewer(Texture texture, int perSecond, double maxDuration) { Texture = texture; Blending = BlendingParameters.Additive; - particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxLifetime / 1000)]; + particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxDuration / 1000)]; cooldown = 1000f / perSecond; - this.maxLifetime = maxLifetime; + this.maxDuration = maxDuration; } protected override void Update() @@ -53,25 +57,25 @@ namespace osu.Game.Graphics // this can happen when seeking in replays. if (lastParticleAdded > Time.Current) lastParticleAdded = 0; - if (Active.Value && CanSpawnParticles && Time.Current > lastParticleAdded + cooldown) + if (Active.Value && Time.Current > lastParticleAdded + cooldown) { var newParticle = CreateParticle(); - newParticle.StartTime = (float)Time.Current; - particles[currentIndex] = newParticle; + if (newParticle.HasValue) + { + var particle = newParticle.Value; + particle.StartTime = (float)Time.Current; - currentIndex = (currentIndex + 1) % particles.Length; - lastParticleAdded = Time.Current; + particles[currentIndex] = particle; + + currentIndex = (currentIndex + 1) % particles.Length; + lastParticleAdded = Time.Current; + } } Invalidate(Invalidation.DrawNode); } - /// - /// Called each time a new particle should be spawned. - /// - protected virtual FallingParticle CreateParticle() => new FallingParticle(); - protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this); # region DrawNode @@ -82,7 +86,7 @@ namespace osu.Game.Graphics protected new ParticleSpewer Source => (ParticleSpewer)base.Source; - private readonly float maxLifetime; + private readonly float maxDuration; private float currentTime; private float gravity; @@ -93,7 +97,7 @@ namespace osu.Game.Graphics : base(source) { particles = new FallingParticle[Source.particles.Length]; - maxLifetime = (float)Source.maxLifetime; + maxDuration = (float)Source.maxDuration; } public override void ApplyState() @@ -124,7 +128,7 @@ namespace osu.Game.Graphics var alpha = p.AlphaAtTime(timeSinceStart); if (alpha <= 0) continue; - var pos = p.PositionAtTime(timeSinceStart, gravity, maxLifetime); + var pos = p.PositionAtTime(timeSinceStart, gravity, maxDuration); var scale = p.ScaleAtTime(timeSinceStart); var angle = p.AngleAtTime(timeSinceStart); @@ -174,7 +178,7 @@ namespace osu.Game.Graphics #endregion - protected struct FallingParticle + public struct FallingParticle { public float StartTime; public Vector2 StartPosition; From af4c3727d77a16e2534df9bbf452336b5c544342 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 19 Sep 2021 04:39:35 +0200 Subject: [PATCH 120/161] Fix build errors --- .../Skinning/Legacy/LegacyCursorParticles.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index d4e5bdd46f..ba5a03c1f1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -127,15 +127,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return base.OnMouseMove(e); } - public bool OnPressed(OsuAction action) + public bool OnPressed(KeyBindingPressEvent e) { - handleInput(action, true); + handleInput(e.Action, true); return false; } - public void OnReleased(OsuAction action) + public void OnReleased(KeyBindingReleaseEvent e) { - handleInput(action, false); + handleInput(e.Action, false); } private bool leftPressed; From 761da45f6a41b30d90931819e168ea1204571d99 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 19 Sep 2021 14:00:56 +0200 Subject: [PATCH 121/161] Revert `af4c3727d77a16e2534df9bbf452336b5c544342` --- .idea/.idea.osu/.idea/indexLayout.xml | 2 +- .../Skinning/Legacy/LegacyCursorParticles.cs | 217 ++++++++++-------- .../Gameplay/TestSceneParticleSpewer.cs | 62 +++-- osu.Game/Graphics/ParticleSpewer.cs | 34 ++- 4 files changed, 178 insertions(+), 137 deletions(-) diff --git a/.idea/.idea.osu/.idea/indexLayout.xml b/.idea/.idea.osu/.idea/indexLayout.xml index 27ba142e96..7b08163ceb 100644 --- a/.idea/.idea.osu/.idea/indexLayout.xml +++ b/.idea/.idea.osu/.idea/indexLayout.xml @@ -1,6 +1,6 @@ - + diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index ba5a03c1f1..e1b7dbc3e3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -6,6 +6,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; @@ -20,17 +21,12 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler, IRequireHighFrequencyMousePosition + public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler { - private const int particle_lifetime_min = 300; - private const int particle_lifetime_max = 1000; - private const float particle_gravity = 240; - public bool Active => breakSpewer?.Active.Value == true || kiaiSpewer?.Active.Value == true; - private Vector2 cursorVelocity; - private ParticleSpewer breakSpewer; - private ParticleSpewer kiaiSpewer; + private LegacyCursorParticleSpewer breakSpewer; + private LegacyCursorParticleSpewer kiaiSpewer; [Resolved(canBeNull: true)] private Player player { get; set; } @@ -50,25 +46,21 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy texture.ScaleAdjust *= 1.6f; } - RelativeSizeAxes = Axes.Both; - Anchor = Anchor.Centre; InternalChildren = new[] { - breakSpewer = new ParticleSpewer(texture, 20, particle_lifetime_max) + breakSpewer = new LegacyCursorParticleSpewer(texture, 20) { - RelativeSizeAxes = Axes.Both, - Size = Vector2.One, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Colour = starBreakAdditive, - ParticleGravity = particle_gravity, - CreateParticle = createBreakParticle, + Direction = SpewDirection.None, }, - kiaiSpewer = new ParticleSpewer(texture, 60, particle_lifetime_max) + kiaiSpewer = new LegacyCursorParticleSpewer(texture, 60) { - RelativeSizeAxes = Axes.Both, - Size = Vector2.One, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Colour = starBreakAdditive, - ParticleGravity = particle_gravity, - CreateParticle = createParticle, + Direction = SpewDirection.None, }, }; @@ -94,39 +86,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy kiaiSpewer.Active.Value = kiaiHitObject != null; } - private Vector2? cursorScreenPosition; - - private const double max_velocity_frame_length = 15; - private double velocityFrameLength; - private Vector2 totalPosDifference; - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (cursorScreenPosition == null) - { - cursorScreenPosition = e.ScreenSpaceMousePosition; - return base.OnMouseMove(e); - } - - // calculate cursor velocity. - totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value; - cursorScreenPosition = e.ScreenSpaceMousePosition; - - velocityFrameLength += Math.Abs(Clock.ElapsedFrameTime); - - if (velocityFrameLength > max_velocity_frame_length) - { - cursorVelocity = totalPosDifference / (float)velocityFrameLength; - - totalPosDifference = Vector2.Zero; - velocityFrameLength = 0; - } - - return base.OnMouseMove(e); - } - public bool OnPressed(KeyBindingPressEvent e) { handleInput(e.Action, true); @@ -153,53 +112,125 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy rightPressed = pressed; break; } - } - - private ParticleSpewer.FallingParticle? createParticle() - { - if (!cursorScreenPosition.HasValue) return null; - - return new ParticleSpewer.FallingParticle - { - StartPosition = ToLocalSpace(cursorScreenPosition.Value), - Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max), - StartAngle = (float)(RNG.NextDouble() * 4 - 2), - EndAngle = RNG.NextSingle(-2f, 2f), - EndScale = RNG.NextSingle(2f), - Velocity = cursorVelocity * 40, - }; - } - - private ParticleSpewer.FallingParticle? createBreakParticle() - { - var baseParticle = createParticle(); - if (!baseParticle.HasValue) return null; - - var p = baseParticle.Value; if (leftPressed && rightPressed) - { - p.Velocity += new Vector2( - RNG.NextSingle(-460f, 460f), - RNG.NextSingle(-160f, 160f) - ); - } + breakSpewer.Direction = SpewDirection.Omni; else if (leftPressed) - { - p.Velocity += new Vector2( - RNG.NextSingle(-460f, 0), - RNG.NextSingle(-40f, 40f) - ); - } + breakSpewer.Direction = SpewDirection.Left; else if (rightPressed) + breakSpewer.Direction = SpewDirection.Right; + else + breakSpewer.Direction = SpewDirection.None; + } + + private class LegacyCursorParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition + { + private const int particle_duration_min = 300; + private const int particle_duration_max = 1000; + + public SpewDirection Direction { get; set; } + + protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue; + protected override float ParticleGravity => 240; + + public LegacyCursorParticleSpewer(Texture texture, int perSecond) + : base(texture, perSecond, particle_duration_max) { - p.Velocity += new Vector2( - RNG.NextSingle(0, 460f), - RNG.NextSingle(-40f, 40f) - ); + Active.BindValueChanged(_ => resetVelocityCalculation()); } - return p; + private Vector2? cursorScreenPosition; + private Vector2 cursorVelocity; + + private const double max_velocity_frame_length = 15; + private double velocityFrameLength; + private Vector2 totalPosDifference; + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; + + protected override bool OnMouseMove(MouseMoveEvent e) + { + if (cursorScreenPosition == null) + { + cursorScreenPosition = e.ScreenSpaceMousePosition; + return base.OnMouseMove(e); + } + + // calculate cursor velocity. + totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value; + cursorScreenPosition = e.ScreenSpaceMousePosition; + + velocityFrameLength += Math.Abs(Clock.ElapsedFrameTime); + + if (velocityFrameLength > max_velocity_frame_length) + { + cursorVelocity = totalPosDifference / (float)velocityFrameLength; + + totalPosDifference = Vector2.Zero; + velocityFrameLength = 0; + } + + return base.OnMouseMove(e); + } + + private void resetVelocityCalculation() + { + cursorScreenPosition = null; + totalPosDifference = Vector2.Zero; + velocityFrameLength = 0; + } + + protected override FallingParticle CreateParticle() => + new FallingParticle + { + StartPosition = ToLocalSpace(cursorScreenPosition ?? Vector2.Zero), + Duration = RNG.NextSingle(particle_duration_min, particle_duration_max), + StartAngle = (float)(RNG.NextDouble() * 4 - 2), + EndAngle = RNG.NextSingle(-2f, 2f), + EndScale = RNG.NextSingle(2f), + Velocity = getVelocity(), + }; + + private Vector2 getVelocity() + { + Vector2 velocity = Vector2.Zero; + + switch (Direction) + { + case SpewDirection.Left: + velocity = new Vector2( + RNG.NextSingle(-460f, 0), + RNG.NextSingle(-40f, 40f) + ); + break; + + case SpewDirection.Right: + velocity = new Vector2( + RNG.NextSingle(0, 460f), + RNG.NextSingle(-40f, 40f) + ); + break; + + case SpewDirection.Omni: + velocity = new Vector2( + RNG.NextSingle(-460f, 460f), + RNG.NextSingle(-160f, 160f) + ); + break; + } + + velocity += cursorVelocity * 40; + + return velocity; + } + } + + private enum SpewDirection + { + None, + Left, + Right, + Omni, } } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index 390534745d..2f107c8300 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -5,6 +5,7 @@ using System; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Graphics; @@ -16,12 +17,7 @@ namespace osu.Game.Tests.Visual.Gameplay [TestFixture] public class TestSceneParticleSpewer : OsuTestScene { - private const int max_particle_duration = 1500; - - private float particleMaxVelocity = 0.5f; - private Vector2 particleSpawnPosition = new Vector2(0.5f); - - private ParticleSpewer spewer; + private TestParticleSpewer spewer; [Resolved] private SkinManager skinManager { get; set; } @@ -32,11 +28,11 @@ namespace osu.Game.Tests.Visual.Gameplay Child = spewer = createSpewer(); AddToggleStep("toggle spawning", value => spewer.Active.Value = value); - AddSliderStep("particle velocity", 0f, 1f, 0.5f, value => particleMaxVelocity = value); - AddSliderStep("particle gravity", 0f, 1f, 0f, value => spewer.ParticleGravity = value); + AddSliderStep("particle gravity", 0f, 1f, 0f, value => spewer.Gravity = value); + AddSliderStep("particle velocity", 0f, 1f, 0.5f, value => spewer.MaxVelocity = value); AddStep("move to new location", () => { - this.TransformTo(nameof(particleSpawnPosition), new Vector2(RNG.NextSingle(), RNG.NextSingle()), 1000, Easing.Out); + spewer.TransformTo(nameof(spewer.SpawnPosition), new Vector2(RNG.NextSingle(), RNG.NextSingle()), 1000, Easing.Out); }); } @@ -59,29 +55,47 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("is not present", () => !spewer.IsPresent); } - private ParticleSpewer createSpewer() => - new ParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2"), 1500, max_particle_duration) + private TestParticleSpewer createSpewer() => + new TestParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2")) { Origin = Anchor.Centre, RelativePositionAxes = Axes.Both, RelativeSizeAxes = Axes.Both, Position = new Vector2(0.5f), Size = new Vector2(0.5f), - CreateParticle = createParticle, }; - private ParticleSpewer.FallingParticle? createParticle() => - new ParticleSpewer.FallingParticle + private class TestParticleSpewer : ParticleSpewer + { + private const int max_duration = 1500; + private const int rate = 250; + + public float Gravity; + + public float MaxVelocity = 0.25f; + + public Vector2 SpawnPosition { get; set; } = new Vector2(0.5f); + + protected override float ParticleGravity => Gravity; + + public TestParticleSpewer(Texture texture) + : base(texture, rate, max_duration) { - Velocity = new Vector2( - RNG.NextSingle(-particleMaxVelocity, particleMaxVelocity), - RNG.NextSingle(-particleMaxVelocity, particleMaxVelocity) - ), - StartPosition = particleSpawnPosition, - Duration = RNG.NextSingle(max_particle_duration), - StartAngle = RNG.NextSingle(MathF.PI * 2), - EndAngle = RNG.NextSingle(MathF.PI * 2), - EndScale = RNG.NextSingle(0.5f, 1.5f) - }; + } + + protected override FallingParticle CreateParticle() => + new FallingParticle + { + Velocity = new Vector2( + RNG.NextSingle(-MaxVelocity, MaxVelocity), + RNG.NextSingle(-MaxVelocity, MaxVelocity) + ), + StartPosition = SpawnPosition, + Duration = RNG.NextSingle(max_duration), + StartAngle = RNG.NextSingle(MathF.PI * 2), + EndAngle = RNG.NextSingle(MathF.PI * 2), + EndScale = RNG.NextSingle(0.5f, 1.5f) + }; + } } } diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 911f5894e7..492e439352 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Graphics { - public class ParticleSpewer : Sprite + public abstract class ParticleSpewer : Sprite { private readonly FallingParticle[] particles; private int currentIndex; @@ -29,16 +29,12 @@ namespace osu.Game.Graphics public override bool IsPresent => base.IsPresent && hasActiveParticles; - /// - /// Called each time a new particle should be spawned. - /// - public Func CreateParticle = () => new FallingParticle(); - - public float ParticleGravity; + protected virtual bool CanSpawnParticles => true; + protected virtual float ParticleGravity => 0; private bool hasActiveParticles => Active.Value || (lastParticleAdded + maxDuration) > Time.Current; - public ParticleSpewer(Texture texture, int perSecond, double maxDuration) + protected ParticleSpewer(Texture texture, int perSecond, double maxDuration) { Texture = texture; Blending = BlendingParameters.Additive; @@ -57,25 +53,25 @@ namespace osu.Game.Graphics // this can happen when seeking in replays. if (lastParticleAdded > Time.Current) lastParticleAdded = 0; - if (Active.Value && Time.Current > lastParticleAdded + cooldown) + if (Active.Value && CanSpawnParticles && Time.Current > lastParticleAdded + cooldown) { var newParticle = CreateParticle(); + newParticle.StartTime = (float)Time.Current; - if (newParticle.HasValue) - { - var particle = newParticle.Value; - particle.StartTime = (float)Time.Current; + particles[currentIndex] = newParticle; - particles[currentIndex] = particle; - - currentIndex = (currentIndex + 1) % particles.Length; - lastParticleAdded = Time.Current; - } + currentIndex = (currentIndex + 1) % particles.Length; + lastParticleAdded = Time.Current; } Invalidate(Invalidation.DrawNode); } + /// + /// Called each time a new particle should be spawned. + /// + protected virtual FallingParticle CreateParticle() => new FallingParticle(); + protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this); # region DrawNode @@ -178,7 +174,7 @@ namespace osu.Game.Graphics #endregion - public struct FallingParticle + protected struct FallingParticle { public float StartTime; public Vector2 StartPosition; From d5a10e922177f9cf7c7bc7f465f7c3e1d9a9807e Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 19 Sep 2021 14:47:20 +0200 Subject: [PATCH 122/161] Fix particles not spawning if `Time.Current` is negative --- osu.Game/Graphics/ParticleSpewer.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 492e439352..a52f749f4a 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -49,11 +49,7 @@ namespace osu.Game.Graphics { base.Update(); - // reset cooldown if the clock was rewound. - // this can happen when seeking in replays. - if (lastParticleAdded > Time.Current) lastParticleAdded = 0; - - if (Active.Value && CanSpawnParticles && Time.Current > lastParticleAdded + cooldown) + if (Active.Value && CanSpawnParticles && Math.Abs(Time.Current - lastParticleAdded) > cooldown) { var newParticle = CreateParticle(); newParticle.StartTime = (float)Time.Current; @@ -112,9 +108,6 @@ namespace osu.Game.Graphics { foreach (var p in particles) { - // ignore particles that weren't initialized. - if (p.StartTime <= 0) continue; - var timeSinceStart = currentTime - p.StartTime; // ignore particles from the future. From 0b593fac5c243438d2f0c9200f74eb7d2abdddf3 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 19 Sep 2021 14:49:09 +0200 Subject: [PATCH 123/161] Scope down DrawNode's `source` parameter --- osu.Game/Graphics/ParticleSpewer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index a52f749f4a..90216da85a 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -85,7 +85,7 @@ namespace osu.Game.Graphics private Axes relativePositionAxes; private Vector2 sourceSize; - public ParticleSpewerDrawNode(Sprite source) + public ParticleSpewerDrawNode(ParticleSpewer source) : base(source) { particles = new FallingParticle[Source.particles.Length]; From 9c90dd539f3e6842cc03027cad368da5a9bb5d57 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 19 Sep 2021 15:06:15 +0200 Subject: [PATCH 124/161] Use `Interpolation.Lerp` --- osu.Game/Graphics/ParticleSpewer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 90216da85a..466bf04369 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Framework.Utils; using osuTK; namespace osu.Game.Graphics @@ -179,9 +180,9 @@ namespace osu.Game.Graphics public float AlphaAtTime(float timeSinceStart) => 1 - progressAtTime(timeSinceStart); - public float ScaleAtTime(float timeSinceStart) => 1 + (EndScale - 1) * progressAtTime(timeSinceStart); + public float ScaleAtTime(float timeSinceStart) => (float)Interpolation.Lerp(1, EndScale, progressAtTime(timeSinceStart)); - public float AngleAtTime(float timeSinceStart) => StartAngle + (EndAngle - StartAngle) * progressAtTime(timeSinceStart); + public float AngleAtTime(float timeSinceStart) => (float)Interpolation.Lerp(StartAngle, EndAngle, progressAtTime(timeSinceStart)); public Vector2 PositionAtTime(float timeSinceStart, float gravity, float maxDuration) { From 366dbf5c3dbae9993b78f1f55c2ac73dd7806944 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 19 Sep 2021 15:35:03 +0200 Subject: [PATCH 125/161] Add test for time jumps --- .../Gameplay/TestSceneParticleSpewer.cs | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index 2f107c8300..ce5cd629e0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; +using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Skinning; @@ -55,6 +56,26 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("is not present", () => !spewer.IsPresent); } + [Test] + public void TestTimeJumps() + { + ManualClock testClock = new ManualClock(); + + AddStep("prepare clock", () => + { + testClock.CurrentTime = TestParticleSpewer.MAX_DURATION * -3; + spewer.Clock = new FramedClock(testClock); + }); + AddStep("start spewer", () => spewer.Active.Value = true); + AddAssert("spawned first particle", () => spewer.TotalCreatedParticles == 1); + + AddStep("move clock forward", () => testClock.CurrentTime = TestParticleSpewer.MAX_DURATION * 3); + AddAssert("spawned second particle", () => spewer.TotalCreatedParticles == 2); + + AddStep("move clock backwards", () => testClock.CurrentTime = TestParticleSpewer.MAX_DURATION * -1); + AddAssert("spawned third particle", () => spewer.TotalCreatedParticles == 3); + } + private TestParticleSpewer createSpewer() => new TestParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2")) { @@ -67,9 +88,11 @@ namespace osu.Game.Tests.Visual.Gameplay private class TestParticleSpewer : ParticleSpewer { - private const int max_duration = 1500; + public const int MAX_DURATION = 1500; private const int rate = 250; + public int TotalCreatedParticles { get; private set; } + public float Gravity; public float MaxVelocity = 0.25f; @@ -79,23 +102,27 @@ namespace osu.Game.Tests.Visual.Gameplay protected override float ParticleGravity => Gravity; public TestParticleSpewer(Texture texture) - : base(texture, rate, max_duration) + : base(texture, rate, MAX_DURATION) { } - protected override FallingParticle CreateParticle() => - new FallingParticle + protected override FallingParticle CreateParticle() + { + TotalCreatedParticles++; + + return new FallingParticle { Velocity = new Vector2( RNG.NextSingle(-MaxVelocity, MaxVelocity), RNG.NextSingle(-MaxVelocity, MaxVelocity) ), StartPosition = SpawnPosition, - Duration = RNG.NextSingle(max_duration), + Duration = RNG.NextSingle(MAX_DURATION), StartAngle = RNG.NextSingle(MathF.PI * 2), EndAngle = RNG.NextSingle(MathF.PI * 2), EndScale = RNG.NextSingle(0.5f, 1.5f) }; + } } } } From 93ca615c022f4d00a972d97ae947426447b14333 Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Sun, 19 Sep 2021 14:15:22 -0400 Subject: [PATCH 126/161] Add tests for clearing `HitErrorMeter` Works with both `BarHitErrorMeter` and `ColourHitErrorMeter` --- .../Visual/Gameplay/TestSceneHitErrorMeter.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index 7accaef818..1ba0965ceb 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; @@ -137,6 +138,23 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("no circle added", () => !this.ChildrenOfType().Any()); } + [Test] + public void TestClear() + { + AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1)); + + AddStep("hit", () => newJudgement(0.2D)); + AddAssert("bar added", () => this.ChildrenOfType().All( + meter => meter.ChildrenOfType().Count() == 1)); + AddAssert("circle added", () => this.ChildrenOfType().All( + 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()); + } + private void recreateDisplay(HitWindows hitWindows, float overallDifficulty) { hitWindows?.SetDifficulty(overallDifficulty); From ab213e20107da27a5b92f92f49dbd65d371ed97c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 19 Sep 2021 21:09:03 +0200 Subject: [PATCH 127/161] Add missing licence headers --- osu.Game/Overlays/Login/LoginForm.cs | 3 +++ osu.Game/Overlays/Login/UserAction.cs | 3 +++ osu.Game/Overlays/Login/UserDropdown.cs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/osu.Game/Overlays/Login/LoginForm.cs b/osu.Game/Overlays/Login/LoginForm.cs index 9d229c2b3e..e43b84d52a 100644 --- a/osu.Game/Overlays/Login/LoginForm.cs +++ b/osu.Game/Overlays/Login/LoginForm.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 osu.Framework.Allocation; using osu.Framework.Graphics; diff --git a/osu.Game/Overlays/Login/UserAction.cs b/osu.Game/Overlays/Login/UserAction.cs index 440d6ea456..07b6b4bf7e 100644 --- a/osu.Game/Overlays/Login/UserAction.cs +++ b/osu.Game/Overlays/Login/UserAction.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.ComponentModel; namespace osu.Game.Overlays.Login diff --git a/osu.Game/Overlays/Login/UserDropdown.cs b/osu.Game/Overlays/Login/UserDropdown.cs index 80f6c7113b..ac4e7f8eda 100644 --- a/osu.Game/Overlays/Login/UserDropdown.cs +++ b/osu.Game/Overlays/Login/UserDropdown.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 osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; From 20eeb36567c2c2afb232b7580729c4c52f4d2ec6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Sep 2021 18:35:47 +0900 Subject: [PATCH 128/161] Avoid `AliveObject` enumeration when not in kiai section --- .../Skinning/Legacy/LegacyCursorParticles.cs | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index e1b7dbc3e3..2b0dfba1dd 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -4,6 +4,7 @@ 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.Graphics.Textures; @@ -12,6 +13,7 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Graphics; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; using osu.Game.Screens.Play; @@ -32,7 +34,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private Player player { get; set; } [Resolved(canBeNull: true)] - private OsuPlayfield osuPlayfield { get; set; } + private OsuPlayfield playfield { get; set; } + + [Resolved(canBeNull: true)] + private GameplayBeatmap gameplayBeatmap { get; set; } + + [Resolved(canBeNull: true)] + private GameplayClock gameplayClock { get; set; } [BackgroundDependencyLoader] private void load(ISkinSource skin, OsuColour colours) @@ -65,27 +73,39 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy }; if (player != null) - { - breakSpewer.Active.BindTarget = player.IsBreakTime; - } + ((IBindable)breakSpewer.Active).BindTo(player.IsBreakTime); } protected override void Update() { - if (osuPlayfield == null) return; + if (playfield == null || gameplayBeatmap == null) return; - // find active kiai slider or spinner. - var kiaiHitObject = osuPlayfield.HitObjectContainer.AliveObjects.FirstOrDefault(h => - h.HitObject.Kiai && - ( - (h is DrawableSlider slider && slider.Tracking.Value) || - (h is DrawableSpinner spinner && spinner.RotationTracker.Tracking) - ) - ); + 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 (gameplayBeatmap.ControlPointInfo.EffectPointAt(gameplayBeatmap.Time.Current).KiaiMode) + kiaiHitObject = playfield.HitObjectContainer.AliveObjects.FirstOrDefault(isTracking); kiaiSpewer.Active.Value = kiaiHitObject != null; } + private bool isTracking(DrawableHitObject h) + { + if (!h.HitObject.Kiai) + return false; + + switch (h) + { + case DrawableSlider slider: + return slider.Tracking.Value; + + case DrawableSpinner spinner: + return spinner.RotationTracker.Tracking; + } + + return false; + } + public bool OnPressed(KeyBindingPressEvent e) { handleInput(e.Action, true); From 10fe2382b08abf113d0ca020f11307284041cb9e Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Mon, 20 Sep 2021 10:07:42 -0400 Subject: [PATCH 129/161] Address most issues --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 +- .../Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 2 +- osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs | 5 ++++- osu.Game/Screens/Play/Player.cs | 5 ++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 2b5228cab0..604df0b774 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -280,6 +280,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - public override void Clear() => judgementsContainer.Clear(true); + protected override void Clear() => judgementsContainer.Clear(); } } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index ea64d1f4d9..19ba1910e6 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters judgementsFlow.Push(GetColourForHitResult(judgement.Type)); } - public override void Clear() => judgementsFlow.Clear(true); + protected override void Clear() => judgementsFlow.Clear(); private class JudgementFlow : FillFlowContainer { diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index 1871519ab5..f9d4d89d1b 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters /// Invoked by when the active seeks through the current beatmap. /// Any inheritors of should have this method clear their container that displays the hit error results. /// - public abstract void Clear(); + protected abstract void Clear(); protected override void Dispose(bool isDisposing) { @@ -85,6 +85,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters if (processor != null) processor.NewJudgement -= OnNewJudgement; + + if (player != null) + player.OnSeek -= Clear; } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e982d02baf..cde3cda369 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -69,7 +69,10 @@ namespace osu.Game.Screens.Play public Action RestartRequested; - public Action OnSeek; + /// + /// Invoked when a seek has been performed via + /// + public event Action OnSeek; public bool HasFailed { get; private set; } From 36a20ab0b365d77878a76c0fbf4444bd6b67380f Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Mon, 20 Sep 2021 10:22:36 -0400 Subject: [PATCH 130/161] Resolve failed test compilation --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 +- .../Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 2 +- osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 604df0b774..39dafaffad 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -280,6 +280,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - protected override void Clear() => judgementsContainer.Clear(); + public override void Clear() => judgementsContainer.Clear(); } } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 19ba1910e6..5012be7249 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters judgementsFlow.Push(GetColourForHitResult(judgement.Type)); } - protected override void Clear() => judgementsFlow.Clear(); + public override void Clear() => judgementsFlow.Clear(); private class JudgementFlow : FillFlowContainer { diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index f9d4d89d1b..a864753b0c 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.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.Allocation; @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters /// Invoked by when the active seeks through the current beatmap. /// Any inheritors of should have this method clear their container that displays the hit error results. /// - protected abstract void Clear(); + public abstract void Clear(); protected override void Dispose(bool isDisposing) { From 9a1db04920ea9034980d70bd9f0d26ad45862ca2 Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Mon, 20 Sep 2021 10:28:58 -0400 Subject: [PATCH 131/161] Resolve `GameplayClockContainer` instead of `Player` --- osu.Game/Screens/Play/GameplayClockContainer.cs | 8 ++++++++ .../Play/HUD/HitErrorMeters/HitErrorMeter.cs | 14 +++++++------- osu.Game/Screens/Play/Player.cs | 6 ------ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index f791da80c8..0c9b827a41 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -13,6 +13,7 @@ namespace osu.Game.Screens.Play /// /// Encapsulates gameplay timing logic and provides a via DI for gameplay components to use. /// + [Cached] public abstract class GameplayClockContainer : Container, IAdjustableClock { /// @@ -35,6 +36,11 @@ namespace osu.Game.Screens.Play /// protected IClock SourceClock { get; private set; } + /// + /// Invoked when a seek has been performed via + /// + public event Action OnSeek; + /// /// Creates a new . /// @@ -88,6 +94,8 @@ namespace osu.Game.Screens.Play // Manually process to make sure the gameplay clock is correctly updated after a seek. GameplayClock.UnderlyingClock.ProcessFrame(); + + OnSeek?.Invoke(); } /// diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index a864753b0c..c7b06a3a2c 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.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.Allocation; @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private OsuColour colours { get; set; } [Resolved(canBeNull: true)] - private Player player { get; set; } + private GameplayClockContainer gameplayClockContainer { get; set; } public bool UsesFixedAnchor { get; set; } @@ -37,8 +37,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { base.LoadComplete(); - if (player != null) - player.OnSeek += Clear; + if (gameplayClockContainer != null) + gameplayClockContainer.OnSeek += Clear; processor.NewJudgement += OnNewJudgement; } @@ -74,7 +74,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } /// - /// Invoked by when the active seeks through the current beatmap. + /// Invoked by . /// Any inheritors of should have this method clear their container that displays the hit error results. /// public abstract void Clear(); @@ -86,8 +86,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters if (processor != null) processor.NewJudgement -= OnNewJudgement; - if (player != null) - player.OnSeek -= Clear; + if (gameplayClockContainer != null) + gameplayClockContainer.OnSeek -= Clear; } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index cde3cda369..a9a74d30d4 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -69,11 +69,6 @@ namespace osu.Game.Screens.Play public Action RestartRequested; - /// - /// Invoked when a seek has been performed via - /// - public event Action OnSeek; - public bool HasFailed { get; private set; } private Bindable mouseWheelDisabled; @@ -592,7 +587,6 @@ namespace osu.Game.Screens.Play public void Seek(double time) { GameplayClockContainer.Seek(time); - OnSeek?.Invoke(); } private ScheduledDelegate frameStablePlaybackResetDelegate; From a3464c98a7b11826694eddf3587399a9ec7ce648 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Sep 2021 23:51:58 +0900 Subject: [PATCH 132/161] Fix `KeyCounterDisplay` potentially getting stuck invisible due to autosize masking Closes #14793. --- osu.Game/Screens/Play/KeyCounterDisplay.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs index 2ed4afafd3..66a44e5314 100644 --- a/osu.Game/Screens/Play/KeyCounterDisplay.cs +++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs @@ -33,8 +33,6 @@ namespace osu.Game.Screens.Play public KeyCounterDisplay() { - AutoSizeAxes = Axes.Both; - InternalChild = KeyFlow = new FillFlowContainer { Direction = FillDirection.Horizontal, @@ -42,6 +40,15 @@ namespace osu.Game.Screens.Play }; } + protected override void Update() + { + base.Update(); + + // Don't use autosize as it will shrink to zero when KeyFlow is hidden. + // In turn this can cause the display to be masked off screen and never become visible again. + Size = KeyFlow.Size; + } + public override void Add(KeyCounter key) { if (key == null) throw new ArgumentNullException(nameof(key)); From fb416c79e906c7fd95c031f3f6de00778ac36f7f Mon Sep 17 00:00:00 2001 From: sh0ckR6 Date: Mon, 20 Sep 2021 15:01:03 -0400 Subject: [PATCH 133/161] Fully revert `Player` --- osu.Game/Screens/Play/Player.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index a9a74d30d4..e8a2790c94 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -584,10 +584,7 @@ namespace osu.Game.Screens.Play /// Seek to a specific time in gameplay. /// /// The destination time to seek to. - public void Seek(double time) - { - GameplayClockContainer.Seek(time); - } + public void Seek(double time) => GameplayClockContainer.Seek(time); private ScheduledDelegate frameStablePlaybackResetDelegate; From b715b89edc3c2c4ea82db029effca7cda912f6d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Sep 2021 19:54:05 +0000 Subject: [PATCH 134/161] Bump SharpCompress from 0.28.3 to 0.29.0 in /osu.Game Bumps [SharpCompress](https://github.com/adamhathcock/sharpcompress) from 0.28.3 to 0.29.0. - [Release notes](https://github.com/adamhathcock/sharpcompress/releases) - [Commits](https://github.com/adamhathcock/sharpcompress/compare/0.28.3...0.29) --- updated-dependencies: - dependency-name: SharpCompress 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 0460de6d72..e6afbe383a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -39,7 +39,7 @@ - + From 9ea9fa5f20db5b48dcf453aa92854285929324e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 11:38:04 +0900 Subject: [PATCH 135/161] Remove issue template to avoid the average use submitting issues --- .github/ISSUE_TEMPLATE/01-bug-issues.md | 30 ------------------------- .github/ISSUE_TEMPLATE/config.yml | 8 +++---- 2 files changed, 4 insertions(+), 34 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/01-bug-issues.md diff --git a/.github/ISSUE_TEMPLATE/01-bug-issues.md b/.github/ISSUE_TEMPLATE/01-bug-issues.md deleted file mode 100644 index 7026179259..0000000000 --- a/.github/ISSUE_TEMPLATE/01-bug-issues.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -name: Bug Report -about: Report a bug or crash to desktop ---- - - - - -**Describe the bug:** - -**Screenshots or videos showing encountered issue:** - -**osu!lazer version:** - -**Logs:** - - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index c62231e8e0..47a6a4c3d3 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,12 +1,12 @@ blank_issues_enabled: false contact_links: - - name: Suggestions or feature request - url: https://github.com/ppy/osu/discussions/categories/ideas - about: Got something you think should change or be added? Search for or start a new discussion! - name: Help url: https://github.com/ppy/osu/discussions/categories/q-a about: osu! not working as you'd expect? Not sure it's a bug? Check the Q&A section! + - name: Suggestions or feature request + url: https://github.com/ppy/osu/discussions/categories/ideas + about: Got something you think should change or be added? Search for or start a new discussion! - name: osu!stable issues url: https://github.com/ppy/osu-stable-issues - about: For osu!stable bugs (not osu!lazer), check out the dedicated repository. Note that we only accept serious bug reports. + about: For osu!(stable) - ie. the current "live" game version, check out the dedicated repository. Note that this is for serious bug reports only, not tech support. From e3542878045a16a72d0cc0a091c96c42eef8df9c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 9 Sep 2021 14:36:49 +0900 Subject: [PATCH 136/161] Fix incorrect ruleset name --- .github/workflows/test-diffcalc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 4274d01bab..92ca1e1a8b 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -33,7 +33,7 @@ jobs: ruleset: - { name: osu, id: 0 } - { name: taiko, id: 1 } - - { name: catch, id: 2 } + - { name: fruits, id: 2 } - { name: mania, id: 3 } services: From fa374e67e7cc001e77d7c2ff6fd49d1f25167b17 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 9 Sep 2021 14:42:39 +0900 Subject: [PATCH 137/161] Single line condition --- .github/workflows/test-diffcalc.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 92ca1e1a8b..bfa4a3a8a0 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -22,10 +22,7 @@ jobs: runs-on: ubuntu-latest continue-on-error: true - if: | - github.event.issue.pull_request && - contains(github.event.comment.body, '!pp check') && - (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') + if: github.event.issue.pull_request && contains(github.event.comment.body, '!pp check') && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') strategy: fail-fast: false From 0f8e570b845f9266e03defc486c6fa2557ac3dd0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 Sep 2021 12:18:19 +0900 Subject: [PATCH 138/161] Use top 1000 data --- .github/workflows/test-diffcalc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index bfa4a3a8a0..0e53bd2c88 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -102,7 +102,7 @@ jobs: # Initial data imports - name: Download + import data run: | - PERFORMANCE_DATA_NAME=$(curl https://data.ppy.sh/ | grep performance_${{ matrix.ruleset.name }}_top | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g') + PERFORMANCE_DATA_NAME=$(curl https://data.ppy.sh/ | grep performance_${{ matrix.ruleset.name }}_top_1000 | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g') BEATMAPS_DATA_NAME=$(curl https://data.ppy.sh/ | grep osu_files | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g') # Set env variable for further steps. From fc5fd203d60c75bcc1ec0df3296a23d35e5d6aa3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 Sep 2021 12:46:27 +0900 Subject: [PATCH 139/161] Output sql import process --- .github/workflows/test-diffcalc.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 0e53bd2c88..6a8ecbbae5 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -120,8 +120,9 @@ jobs: mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_master" mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_pr" - cat *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_master - cat *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_pr + echo "Importing SQL..." + { pv -f *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_master; } 2>&1 | stdbuf -oL tr '\r' '\n' + { pv -f *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_pr; } 2>&1 | stdbuf -oL tr '\r' '\n' # Run diffcalc - name: Run diffcalc (master) From 6bfb31a63559358013447a6ec54609ebb6418112 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 14 Sep 2021 12:55:33 +0900 Subject: [PATCH 140/161] Install pv --- .github/workflows/test-diffcalc.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 6a8ecbbae5..54365ed5f6 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -49,6 +49,9 @@ jobs: echo "${{ github.event.comment.body }} doesn't contain ${{ matrix.ruleset.id }}" exit 1 + - name: Install dependencies + run: sudo apt-get install -y pv + - name: Verify MySQL connection from host run: | sudo apt-get install -y mysql-client From 9d4c5e9cb6bbf12efcc3a866621bbdfe778df1d3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 16 Sep 2021 14:24:30 +0900 Subject: [PATCH 141/161] Add filename to output rows --- .github/workflows/test-diffcalc.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 54365ed5f6..79c1497dca 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -148,6 +148,7 @@ jobs: SELECT m.beatmap_id, m.mods, + b.filename, m.diff_unified as 'sr_master', p.diff_unified as 'sr_pr', (p.diff_unified - m.diff_unified) as 'diff' @@ -156,6 +157,8 @@ jobs: ON m.beatmap_id = p.beatmap_id AND m.mode = p.mode AND m.mods = p.mods + JOIN osu_pr.osu_beatmaps b + ON b.beatmap_id = p.beatmap_id WHERE abs(m.diff_unified - p.diff_unified) > 0.1 ORDER BY abs(m.diff_unified - p.diff_unified) DESC From 06e11484721f9cfa5c58003e9198008bab7387d0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 17 Sep 2021 19:47:41 +0900 Subject: [PATCH 142/161] Run on self-hosted runner --- .github/workflows/test-diffcalc.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 79c1497dca..9c633a597d 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -12,6 +12,7 @@ on: env: DB_USER: root DB_HOST: 127.0.0.1 + DB_PORT: 33306:3306 CONCURRENCY: 4 ALLOW_DOWNLOAD: 1 SAVE_DOWNLOADED: 1 @@ -19,7 +20,7 @@ env: jobs: diffcalc: name: Diffcalc - runs-on: ubuntu-latest + runs-on: self-hosted continue-on-error: true if: github.event.issue.pull_request && contains(github.event.comment.body, '!pp check') && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') @@ -39,7 +40,7 @@ jobs: env: MYSQL_ALLOW_EMPTY_PASSWORD: yes ports: - - 3306:3306 + - 33306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: @@ -54,8 +55,7 @@ jobs: - name: Verify MySQL connection from host run: | - sudo apt-get install -y mysql-client - mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "SHOW DATABASES" + mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "SHOW DATABASES" - name: Create directory structure run: | @@ -120,12 +120,12 @@ jobs: cd $GITHUB_WORKSPACE/$PERFORMANCE_DATA_NAME - mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_master" - mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_pr" + mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_master" + mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_pr" echo "Importing SQL..." - { pv -f *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_master; } 2>&1 | stdbuf -oL tr '\r' '\n' - { pv -f *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_pr; } 2>&1 | stdbuf -oL tr '\r' '\n' + { pv -f *.sql | mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} --database=osu_master; } 2>&1 | stdbuf -oL tr '\r' '\n' + { pv -f *.sql | mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} --database=osu_pr; } 2>&1 | stdbuf -oL tr '\r' '\n' # Run diffcalc - name: Run diffcalc (master) @@ -144,7 +144,7 @@ jobs: # Print diffs - name: Print diffs run: | - mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e " + mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e " SELECT m.beatmap_id, m.mods, From 6b3a37e262b1da27a58570178946609bbced85c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Sep 2021 03:49:30 +0900 Subject: [PATCH 143/161] Remove deps step --- .github/workflows/test-diffcalc.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 9c633a597d..565af6ad3c 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -50,9 +50,6 @@ jobs: echo "${{ github.event.comment.body }} doesn't contain ${{ matrix.ruleset.id }}" exit 1 - - name: Install dependencies - run: sudo apt-get install -y pv - - name: Verify MySQL connection from host run: | mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "SHOW DATABASES" @@ -164,4 +161,4 @@ jobs: DESC LIMIT 10000;" - # Todo: Run ppcalc \ No newline at end of file + # Todo: Run ppcalc From 1d560ed1226e648d05bc003c6939273f21112b67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 20 Sep 2021 23:18:31 +0900 Subject: [PATCH 144/161] Use optimisation branch for now --- .github/workflows/test-diffcalc.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 565af6ad3c..db1fa7a088 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -63,7 +63,8 @@ jobs: - name: Checkout osu (master) uses: actions/checkout@v2 with: - repository: ppy/osu + repository: peppy/osu + ref: 'diffcalc-optimisations' path: 'master/osu' - name: Checkout osu (pr) uses: actions/checkout@v2 From 7d5e4ae0a2386e82748219bf57d767610d0403de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 18 Sep 2021 03:57:25 +0900 Subject: [PATCH 145/161] Drop service based mysql usage (use host instead) --- .github/workflows/test-diffcalc.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index db1fa7a088..188e074e07 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -12,7 +12,7 @@ on: env: DB_USER: root DB_HOST: 127.0.0.1 - DB_PORT: 33306:3306 + DB_PORT: 3306 CONCURRENCY: 4 ALLOW_DOWNLOAD: 1 SAVE_DOWNLOADED: 1 @@ -34,15 +34,6 @@ jobs: - { name: fruits, id: 2 } - { name: mania, id: 3 } - services: - mysql: - image: mysql:8.0 - env: - MYSQL_ALLOW_EMPTY_PASSWORD: yes - ports: - - 33306:3306 - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 - steps: - name: Verify ruleset if: contains(github.event.comment.body, matrix.ruleset.id) == false @@ -54,6 +45,11 @@ jobs: run: | mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "SHOW DATABASES" + - name: Drop previous databases + run: | + mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "DROP DATABASE IF EXISTS osu_master" + mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "DROP DATABASE IF EXISTS osu_pr" + - name: Create directory structure run: | mkdir -p $GITHUB_WORKSPACE/master/ From 7c2b8fc650f02c25509d8cdf2ebf3db42b6777f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 00:37:12 +0900 Subject: [PATCH 146/161] Apply new skip insert rule --- .github/workflows/test-diffcalc.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 188e074e07..23b5c8bd2c 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -16,6 +16,7 @@ env: CONCURRENCY: 4 ALLOW_DOWNLOAD: 1 SAVE_DOWNLOADED: 1 + SKIP_INSERT_ATTRIBUTES: 1 jobs: diffcalc: @@ -71,12 +72,14 @@ jobs: - name: Checkout osu-difficulty-calculator (master) uses: actions/checkout@v2 with: - repository: ppy/osu-difficulty-calculator + repository: peppy/osu-difficulty-calculator + ref: 'bypass-attrib-row-insert' path: 'master/osu-difficulty-calculator' - name: Checkout osu-difficulty-calculator (pr) uses: actions/checkout@v2 with: - repository: ppy/osu-difficulty-calculator + repository: peppy/osu-difficulty-calculator + ref: 'bypass-attrib-row-insert' path: 'pr/osu-difficulty-calculator' - name: Install .NET 5.0.x From a46fe5da75793867394fe1072268dc44b4a4a49c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 01:14:33 +0900 Subject: [PATCH 147/161] Simplify action --- .github/workflows/test-diffcalc.yml | 44 ++++++++++++++++++----------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 23b5c8bd2c..b5937c1378 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -10,9 +10,6 @@ on: types: [ created ] env: - DB_USER: root - DB_HOST: 127.0.0.1 - DB_PORT: 3306 CONCURRENCY: 4 ALLOW_DOWNLOAD: 1 SAVE_DOWNLOADED: 1 @@ -44,12 +41,14 @@ jobs: - name: Verify MySQL connection from host run: | - mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "SHOW DATABASES" + mysql -e "SHOW DATABASES" - name: Drop previous databases run: | - mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "DROP DATABASE IF EXISTS osu_master" - mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "DROP DATABASE IF EXISTS osu_pr" + for db in osu_master osu_pr + do + mysql -e "DROP DATABASE IF EXISTS $db" + done - name: Create directory structure run: | @@ -68,7 +67,6 @@ jobs: with: path: 'pr/osu' - # Checkout osu-difficulty-calculator - name: Checkout osu-difficulty-calculator (master) uses: actions/checkout@v2 with: @@ -99,7 +97,6 @@ jobs: ./UseLocalOsu.sh dotnet build - # Initial data imports - name: Download + import data run: | PERFORMANCE_DATA_NAME=$(curl https://data.ppy.sh/ | grep performance_${{ matrix.ruleset.name }}_top_1000 | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g') @@ -112,19 +109,33 @@ jobs: wget https://data.ppy.sh/$PERFORMANCE_DATA_NAME.tar.bz2 wget https://data.ppy.sh/$BEATMAPS_DATA_NAME.tar.bz2 + tar -xf $PERFORMANCE_DATA_NAME.tar.bz2 tar -xf $BEATMAPS_DATA_NAME.tar.bz2 - cd $GITHUB_WORKSPACE/$PERFORMANCE_DATA_NAME + cd $PERFORMANCE_DATA_NAME - mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_master" - mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_pr" + for db in osu_master osu_pr + do + echo "Setting up database $db.." - echo "Importing SQL..." - { pv -f *.sql | mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} --database=osu_master; } 2>&1 | stdbuf -oL tr '\r' '\n' - { pv -f *.sql | mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} --database=osu_pr; } 2>&1 | stdbuf -oL tr '\r' '\n' + mysql -e "CREATE DATABASE $db" + + echo "Importing beatmaps..." + cat osu_beatmaps.sql | mysql $db + cat osu_beatmapsets.sql | mysql $db + + mysql $db -e "CREATE TABLE `osu_beatmap_difficulty` ( + `beatmap_id` int unsigned NOT NULL, + `mode` tinyint NOT NULL DEFAULT '0', + `mods` int unsigned NOT NULL, + `diff_unified` float NOT NULL, + `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`beatmap_id`,`mode`,`mods`), + KEY `diff_sort` (`mode`,`mods`,`diff_unified`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;" + done - # Run diffcalc - name: Run diffcalc (master) env: DB_NAME: osu_master @@ -138,10 +149,9 @@ jobs: cd $GITHUB_WORKSPACE/pr/osu-difficulty-calculator/osu.Server.DifficultyCalculator dotnet run -c:Release -- all -m ${{ matrix.ruleset.id }} -ac -c ${{ env.CONCURRENCY }} - # Print diffs - name: Print diffs run: | - mysql --host ${{ env.DB_HOST }} --port ${{ env.DB_PORT }} -u${{ env.DB_USER }} -e " + mysql -e " SELECT m.beatmap_id, m.mods, From 5b9cab8b1fca1054a4eebea5af8613853b831cd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 01:44:07 +0900 Subject: [PATCH 148/161] Add more log output and quiet `wget` --- .github/workflows/test-diffcalc.yml | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index b5937c1378..e9fd624168 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -107,10 +107,14 @@ jobs: cd $GITHUB_WORKSPACE - wget https://data.ppy.sh/$PERFORMANCE_DATA_NAME.tar.bz2 - wget https://data.ppy.sh/$BEATMAPS_DATA_NAME.tar.bz2 - + echo "Downloading database dump $PERFORMANCE_DATA_NAME.." + wget -q -nc https://data.ppy.sh/$PERFORMANCE_DATA_NAME.tar.bz2 + echo "Extracting.." tar -xf $PERFORMANCE_DATA_NAME.tar.bz2 + + echo "Downloading beatmap dump $BEATMAPS_DATA_NAME.." + wget -q https://data.ppy.sh/$BEATMAPS_DATA_NAME.tar.bz2 + echo "Extracting.." tar -xf $BEATMAPS_DATA_NAME.tar.bz2 cd $PERFORMANCE_DATA_NAME @@ -121,19 +125,21 @@ jobs: mysql -e "CREATE DATABASE $db" - echo "Importing beatmaps..." + echo "Importing beatmaps.." cat osu_beatmaps.sql | mysql $db + echo "Importing beatmapsets.." cat osu_beatmapsets.sql | mysql $db - mysql $db -e "CREATE TABLE `osu_beatmap_difficulty` ( + echo "Creating table structure.." + mysql $db -e 'CREATE TABLE `osu_beatmap_difficulty` ( `beatmap_id` int unsigned NOT NULL, - `mode` tinyint NOT NULL DEFAULT '0', + `mode` tinyint NOT NULL DEFAULT 0, `mods` int unsigned NOT NULL, `diff_unified` float NOT NULL, `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`beatmap_id`,`mode`,`mods`), KEY `diff_sort` (`mode`,`mods`,`diff_unified`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;" + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;' done - name: Run diffcalc (master) From f73ebfcea188b19de4b9f7f804229d15b6de4bbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 01:44:54 +0900 Subject: [PATCH 149/161] Don't redownload if file already exists --- .github/workflows/test-diffcalc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index e9fd624168..dd623f59ce 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -113,7 +113,7 @@ jobs: tar -xf $PERFORMANCE_DATA_NAME.tar.bz2 echo "Downloading beatmap dump $BEATMAPS_DATA_NAME.." - wget -q https://data.ppy.sh/$BEATMAPS_DATA_NAME.tar.bz2 + wget -q -nc https://data.ppy.sh/$BEATMAPS_DATA_NAME.tar.bz2 echo "Extracting.." tar -xf $BEATMAPS_DATA_NAME.tar.bz2 From afcf3edec99d76c7937683abd249d9efcc5b0a39 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 02:27:21 +0900 Subject: [PATCH 150/161] Build build matrix dynamically --- .github/workflows/test-diffcalc.yml | 51 ++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index dd623f59ce..75742f2bde 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -16,29 +16,50 @@ env: SKIP_INSERT_ATTRIBUTES: 1 jobs: + metadata: + runs-on: self-hosted + if: github.event.issue.pull_request && contains(github.event.comment.body, '!pp check') && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') + outputs: + matrix: ${{ steps.generate-matrix.outputs.matrix }} + continue: ${{ steps.generate-matrix.outputs.continue }} + steps: + - name: generate matrix + id: generate-matrix + run: | + if [[ "${{ github.event.comment.body }}" =~ "1" ]] ; then + MATRIX_PROJECTS_JSON+='{ "name": "osu", "id": 0 },' + fi + if [[ "${{ github.event.comment.body }}" =~ "2" ]] ; then + MATRIX_PROJECTS_JSON+='{ "name": "taiko", "id": 1 },' + fi + if [[ "${{ github.event.comment.body }}" =~ "3" ]] ; then + MATRIX_PROJECTS_JSON+='{ "name": "catch", "id": 2 },' + fi + if [[ "${{ github.event.comment.body }}" =~ "4" ]] ; then + MATRIX_PROJECTS_JSON+='{ "name": "mania", "id": 3 },' + fi + + if [[ "${MATRIX_PROJECTS_JSON}" != "" ]]; then + MATRIX_JSON="{ \"ruleset\": [ ${MATRIX_PROJECTS_JSON} ] }" + echo "${MATRIX_JSON}" + CONTINUE="yes" + else + CONTINUE="no" + fi + + echo "::set-output name=continue::${CONTINUE}" + echo "::set-output name=matrix::${MATRIX_JSON}" diffcalc: name: Diffcalc runs-on: self-hosted continue-on-error: true - - if: github.event.issue.pull_request && contains(github.event.comment.body, '!pp check') && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') + if: needs.metadata.outputs.continue == 'yes' + needs: metadata strategy: - fail-fast: false - matrix: - ruleset: - - { name: osu, id: 0 } - - { name: taiko, id: 1 } - - { name: fruits, id: 2 } - - { name: mania, id: 3 } + matrix: ${{ fromJson(needs.metadata.outputs.matrix) }} steps: - - name: Verify ruleset - if: contains(github.event.comment.body, matrix.ruleset.id) == false - run: | - echo "${{ github.event.comment.body }} doesn't contain ${{ matrix.ruleset.id }}" - exit 1 - - name: Verify MySQL connection from host run: | mysql -e "SHOW DATABASES" From f282bd6f42c758be1e111755ee33839e362f0638 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 02:47:27 +0900 Subject: [PATCH 151/161] Tidy up naming --- .github/workflows/test-diffcalc.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 75742f2bde..c83cbf5d61 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -4,7 +4,7 @@ # !pp check 0 2 | Runs only the osu! and catch rulesets. # -name: Diffcalc Consistency Checks +name: Difficulty Calculation on: issue_comment: types: [ created ] @@ -17,13 +17,14 @@ env: jobs: metadata: + name: Check for requests runs-on: self-hosted if: github.event.issue.pull_request && contains(github.event.comment.body, '!pp check') && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') outputs: matrix: ${{ steps.generate-matrix.outputs.matrix }} continue: ${{ steps.generate-matrix.outputs.continue }} steps: - - name: generate matrix + - name: Construct build matrix id: generate-matrix run: | if [[ "${{ github.event.comment.body }}" =~ "1" ]] ; then @@ -50,15 +51,13 @@ jobs: echo "::set-output name=continue::${CONTINUE}" echo "::set-output name=matrix::${MATRIX_JSON}" diffcalc: - name: Diffcalc + name: Run runs-on: self-hosted continue-on-error: true if: needs.metadata.outputs.continue == 'yes' needs: metadata - strategy: matrix: ${{ fromJson(needs.metadata.outputs.matrix) }} - steps: - name: Verify MySQL connection from host run: | From 192089db61398096d61494b3f77d66687de0d43d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 02:54:37 +0900 Subject: [PATCH 152/161] Use keywords instead of IDs --- .github/workflows/test-diffcalc.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index c83cbf5d61..edb9fbd323 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -27,16 +27,16 @@ jobs: - name: Construct build matrix id: generate-matrix run: | - if [[ "${{ github.event.comment.body }}" =~ "1" ]] ; then + if [[ "${{ github.event.comment.body }}" =~ "osu" ]] ; then MATRIX_PROJECTS_JSON+='{ "name": "osu", "id": 0 },' fi - if [[ "${{ github.event.comment.body }}" =~ "2" ]] ; then + if [[ "${{ github.event.comment.body }}" =~ "taiko" ]] ; then MATRIX_PROJECTS_JSON+='{ "name": "taiko", "id": 1 },' fi - if [[ "${{ github.event.comment.body }}" =~ "3" ]] ; then + if [[ "${{ github.event.comment.body }}" =~ "catch" ]] ; then MATRIX_PROJECTS_JSON+='{ "name": "catch", "id": 2 },' fi - if [[ "${{ github.event.comment.body }}" =~ "4" ]] ; then + if [[ "${{ github.event.comment.body }}" =~ "mania" ]] ; then MATRIX_PROJECTS_JSON+='{ "name": "mania", "id": 3 },' fi From a694d482ed1c2fee5d0a153f4b2009910a95e6cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 12:32:26 +0900 Subject: [PATCH 153/161] Rename file --- .github/workflows/{test-diffcalc.yml => diffcalc.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{test-diffcalc.yml => diffcalc.yml} (100%) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/diffcalc.yml similarity index 100% rename from .github/workflows/test-diffcalc.yml rename to .github/workflows/diffcalc.yml From b9c91111d2a855e6935b443a5871c6b2d990885e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Sep 2021 12:43:29 +0900 Subject: [PATCH 154/161] Add some whitespace --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 529f8b9672..cb3338126c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -39,14 +39,17 @@ namespace osu.Game.Rulesets.Osu.Difficulty 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; double baseFlashlightPerformance = 0.0; + if (mods.Any(h => h is OsuModFlashlight)) baseFlashlightPerformance = Math.Pow(flashlightRating, 2.0) * 25.0; + double basePerformance = Math.Pow( Math.Pow(baseAimPerformance, 1.1) + Math.Pow(baseSpeedPerformance, 1.1) + 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; HitWindows hitWindows = new OsuHitWindows(); From ea624489ca809327e37a9952b0d90cf96c168ec1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 21 Sep 2021 12:48:10 +0900 Subject: [PATCH 155/161] Remove continue-on-error --- .github/workflows/diffcalc.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/diffcalc.yml b/.github/workflows/diffcalc.yml index edb9fbd323..842522ae87 100644 --- a/.github/workflows/diffcalc.yml +++ b/.github/workflows/diffcalc.yml @@ -53,7 +53,6 @@ jobs: diffcalc: name: Run runs-on: self-hosted - continue-on-error: true if: needs.metadata.outputs.continue == 'yes' needs: metadata strategy: From bad3f0b1e9f0af33a45e4e3624605b51ab995f4d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Sep 2021 14:25:44 +0900 Subject: [PATCH 156/161] Disable FtB pass for particle spewer --- osu.Game/Graphics/ParticleSpewer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 466bf04369..54a2b1e890 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -164,6 +164,8 @@ namespace osu.Game.Graphics return Vector2Extensions.Transform(new Vector2(x, y), DrawInfo.Matrix); } + + protected override bool CanDrawOpaqueInterior => false; } #endregion From 6246bbc262eb789099b515a3dd2d20cf54607e14 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Sep 2021 14:37:09 +0900 Subject: [PATCH 157/161] Also add to ParticleExplosion --- osu.Game/Graphics/ParticleExplosion.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Graphics/ParticleExplosion.cs b/osu.Game/Graphics/ParticleExplosion.cs index e0d2b50c55..094cc87bbe 100644 --- a/osu.Game/Graphics/ParticleExplosion.cs +++ b/osu.Game/Graphics/ParticleExplosion.cs @@ -115,6 +115,8 @@ namespace osu.Game.Graphics null, TextureCoords); } } + + protected override bool CanDrawOpaqueInterior => false; } private readonly struct ParticlePart From f0971cb90c43a50fe3c5b2c1185e9e3eb56335f8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Sep 2021 14:40:33 +0900 Subject: [PATCH 158/161] Fix kiai spawner using wrong current time --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 2b0dfba1dd..9a7eb6835b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy 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 (gameplayBeatmap.ControlPointInfo.EffectPointAt(gameplayBeatmap.Time.Current).KiaiMode) + if (gameplayBeatmap.ControlPointInfo.EffectPointAt(Time.Current).KiaiMode) kiaiHitObject = playfield.HitObjectContainer.AliveObjects.FirstOrDefault(isTracking); kiaiSpewer.Active.Value = kiaiHitObject != null; From 69e28dc8a1bbd9edabd79dd1a69be7e1803f5124 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Sep 2021 14:44:22 +0900 Subject: [PATCH 159/161] Add failing test --- osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs index 11b1f5b2af..bd39dead34 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs @@ -98,6 +98,7 @@ namespace osu.Game.Rulesets.Osu.Tests { var controlPointInfo = new ControlPointInfo(); controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + controlPointInfo.Add(5000, new EffectControlPoint { KiaiMode = false }); return new Beatmap { From 6c91d39c15a0e6f4c563dac9e3b0a83537a187db Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Sep 2021 14:48:41 +0900 Subject: [PATCH 160/161] Remove GameplayClock dependency --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index 9a7eb6835b..c2db5f3f82 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -39,9 +39,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy [Resolved(canBeNull: true)] private GameplayBeatmap gameplayBeatmap { get; set; } - [Resolved(canBeNull: true)] - private GameplayClock gameplayClock { get; set; } - [BackgroundDependencyLoader] private void load(ISkinSource skin, OsuColour colours) { From 430ecc5409a903a1f871c3097a24c92beb3ff6f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 21 Sep 2021 15:20:04 +0900 Subject: [PATCH 161/161] Adjust to make HD slightly harder and not obsolete --- osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index b3a54521d8..7f565cb82d 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -22,13 +22,13 @@ namespace osu.Game.Rulesets.Taiko.Mods /// How far away from the hit target should hitobjects start to fade out. /// Range: [0, 1] /// - private const float fade_out_start_time = 0.6f; + private const float fade_out_start_time = 1f; /// /// How long hitobjects take to fade out, in terms of the scrolling length. /// Range: [0, 1] /// - private const float fade_out_duration = 0.3f; + private const float fade_out_duration = 0.375f; private DrawableTaikoRuleset drawableRuleset;