diff --git a/osu.Android.props b/osu.Android.props
index 1532d4ce23..ca4d88a8a7 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs
index dbfd170ea1..4acaf61cea 100644
--- a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs
+++ b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs
@@ -14,6 +14,7 @@ namespace osu.Desktop.Windows
{
private Bindable disableWinKey;
private IBindable localUserPlaying;
+ private IBindable isActive;
[Resolved]
private GameHost host { get; set; }
@@ -24,13 +25,16 @@ namespace osu.Desktop.Windows
localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy();
localUserPlaying.BindValueChanged(_ => updateBlocking());
+ isActive = host.IsActive.GetBoundCopy();
+ isActive.BindValueChanged(_ => updateBlocking());
+
disableWinKey = config.GetBindable(OsuSetting.GameplayDisableWinKey);
disableWinKey.BindValueChanged(_ => updateBlocking(), true);
}
private void updateBlocking()
{
- bool shouldDisable = disableWinKey.Value && localUserPlaying.Value;
+ bool shouldDisable = isActive.Value && disableWinKey.Value && localUserPlaying.Value;
if (shouldDisable)
host.InputThread.Scheduler.Add(WindowsKey.Disable);
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceAttributes.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceAttributes.cs
new file mode 100644
index 0000000000..1335fc2d23
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceAttributes.cs
@@ -0,0 +1,11 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Difficulty;
+
+namespace osu.Game.Rulesets.Catch.Difficulty
+{
+ public class CatchPerformanceAttributes : PerformanceAttributes
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs
index 439890dac2..8cdbe500f0 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
{
}
- public override double Calculate(Dictionary categoryDifficulty = null)
+ public override PerformanceAttributes Calculate()
{
mods = Score.Mods;
@@ -44,15 +44,11 @@ namespace osu.Game.Rulesets.Catch.Difficulty
// Longer maps are worth more. "Longer" means how many hits there are which can contribute to combo
int numTotalHits = totalComboHits();
- // Longer maps are worth more
double lengthBonus =
0.95 + 0.3 * Math.Min(1.0, numTotalHits / 2500.0) +
(numTotalHits > 2500 ? Math.Log10(numTotalHits / 2500.0) * 0.475 : 0.0);
-
- // Longer maps are worth more
value *= lengthBonus;
- // Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
value *= Math.Pow(0.97, misses);
// Combo scaling
@@ -80,17 +76,17 @@ namespace osu.Game.Rulesets.Catch.Difficulty
}
if (mods.Any(m => m is ModFlashlight))
- // Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
value *= 1.35 * lengthBonus;
- // Scale the aim value with accuracy _slightly_
value *= Math.Pow(accuracy(), 5.5);
- // Custom multipliers for NoFail. SpunOut is not applicable.
if (mods.Any(m => m is ModNoFail))
value *= 0.90;
- return value;
+ return new CatchPerformanceAttributes
+ {
+ Total = value
+ };
}
private double accuracy() => totalHits() == 0 ? 0 : Math.Clamp((double)totalSuccessfulHits() / totalHits(), 0, 1);
diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs
index bfdef893e9..979a04ddf8 100644
--- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs
+++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyAttributes.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
yield return v;
// Todo: osu!mania doesn't output MaxCombo attribute for some reason.
- yield return (ATTRIB_ID_STRAIN, StarRating);
+ yield return (ATTRIB_ID_DIFFICULTY, StarRating);
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
yield return (ATTRIB_ID_SCORE_MULTIPLIER, ScoreMultiplier);
}
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
{
base.FromDatabaseAttributes(values);
- StarRating = values[ATTRIB_ID_STRAIN];
+ StarRating = values[ATTRIB_ID_DIFFICULTY];
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
ScoreMultiplier = values[ATTRIB_ID_SCORE_MULTIPLIER];
}
diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceAttributes.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceAttributes.cs
new file mode 100644
index 0000000000..da9634ba47
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceAttributes.cs
@@ -0,0 +1,20 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Newtonsoft.Json;
+using osu.Game.Rulesets.Difficulty;
+
+namespace osu.Game.Rulesets.Mania.Difficulty
+{
+ public class ManiaPerformanceAttributes : PerformanceAttributes
+ {
+ [JsonProperty("difficulty")]
+ public double Difficulty { get; set; }
+
+ [JsonProperty("accuracy")]
+ public double Accuracy { get; set; }
+
+ [JsonProperty("scaled_score")]
+ public double ScaledScore { get; set; }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
index b04ff3548f..8a8c41bb8a 100644
--- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs
@@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
{
}
- public override double Calculate(Dictionary categoryDifficulty = null)
+ public override PerformanceAttributes Calculate()
{
mods = Score.Mods;
scaledScore = Score.TotalScore;
@@ -61,48 +61,46 @@ namespace osu.Game.Rulesets.Mania.Difficulty
if (mods.Any(m => m is ModEasy))
multiplier *= 0.5;
- double strainValue = computeStrainValue();
- double accValue = computeAccuracyValue(strainValue);
+ double difficultyValue = computeDifficultyValue();
+ double accValue = computeAccuracyValue(difficultyValue);
double totalValue =
Math.Pow(
- Math.Pow(strainValue, 1.1) +
+ Math.Pow(difficultyValue, 1.1) +
Math.Pow(accValue, 1.1), 1.0 / 1.1
) * multiplier;
- if (categoryDifficulty != null)
+ return new ManiaPerformanceAttributes
{
- categoryDifficulty["Strain"] = strainValue;
- categoryDifficulty["Accuracy"] = accValue;
- }
-
- return totalValue;
+ Difficulty = difficultyValue,
+ Accuracy = accValue,
+ ScaledScore = scaledScore,
+ Total = totalValue
+ };
}
- private double computeStrainValue()
+ private double computeDifficultyValue()
{
- // Obtain strain difficulty
- double strainValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0;
+ double difficultyValue = Math.Pow(5 * Math.Max(1, Attributes.StarRating / 0.2) - 4.0, 2.2) / 135.0;
- // Longer maps are worth more
- strainValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
+ difficultyValue *= 1.0 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
if (scaledScore <= 500000)
- strainValue = 0;
+ difficultyValue = 0;
else if (scaledScore <= 600000)
- strainValue *= (scaledScore - 500000) / 100000 * 0.3;
+ difficultyValue *= (scaledScore - 500000) / 100000 * 0.3;
else if (scaledScore <= 700000)
- strainValue *= 0.3 + (scaledScore - 600000) / 100000 * 0.25;
+ difficultyValue *= 0.3 + (scaledScore - 600000) / 100000 * 0.25;
else if (scaledScore <= 800000)
- strainValue *= 0.55 + (scaledScore - 700000) / 100000 * 0.20;
+ difficultyValue *= 0.55 + (scaledScore - 700000) / 100000 * 0.20;
else if (scaledScore <= 900000)
- strainValue *= 0.75 + (scaledScore - 800000) / 100000 * 0.15;
+ difficultyValue *= 0.75 + (scaledScore - 800000) / 100000 * 0.15;
else
- strainValue *= 0.90 + (scaledScore - 900000) / 100000 * 0.1;
+ difficultyValue *= 0.90 + (scaledScore - 900000) / 100000 * 0.1;
- return strainValue;
+ return difficultyValue;
}
- private double computeAccuracyValue(double strainValue)
+ private double computeAccuracyValue(double difficultyValue)
{
if (Attributes.GreatHitWindow <= 0)
return 0;
@@ -110,12 +108,9 @@ namespace osu.Game.Rulesets.Mania.Difficulty
// Lots of arbitrary values from testing.
// Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
double accuracyValue = Math.Max(0.0, 0.2 - (Attributes.GreatHitWindow - 34) * 0.006667)
- * strainValue
+ * difficultyValue
* Math.Pow(Math.Max(0.0, scaledScore - 960000) / 40000, 1.1);
- // Bonus for many hitcircles - it's harder to keep good accuracy up for longer
- // accuracyValue *= Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
-
return accuracyValue;
}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
index 4b2e54da17..128ff772fd 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs
@@ -12,14 +12,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{
public class OsuDifficultyAttributes : DifficultyAttributes
{
- [JsonProperty("aim_strain")]
- public double AimStrain { get; set; }
+ [JsonProperty("aim_difficulty")]
+ public double AimDifficulty { get; set; }
- [JsonProperty("speed_strain")]
- public double SpeedStrain { get; set; }
+ [JsonProperty("speed_difficulty")]
+ public double SpeedDifficulty { get; set; }
- [JsonProperty("flashlight_rating")]
- public double FlashlightRating { get; set; }
+ [JsonProperty("flashlight_difficulty")]
+ public double FlashlightDifficulty { get; set; }
[JsonProperty("slider_factor")]
public double SliderFactor { get; set; }
@@ -43,15 +43,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty
foreach (var v in base.ToDatabaseAttributes())
yield return v;
- yield return (ATTRIB_ID_AIM, AimStrain);
- yield return (ATTRIB_ID_SPEED, SpeedStrain);
+ yield return (ATTRIB_ID_AIM, AimDifficulty);
+ yield return (ATTRIB_ID_SPEED, SpeedDifficulty);
yield return (ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty);
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
- yield return (ATTRIB_ID_STRAIN, StarRating);
+ yield return (ATTRIB_ID_DIFFICULTY, StarRating);
if (ShouldSerializeFlashlightRating())
- yield return (ATTRIB_ID_FLASHLIGHT, FlashlightRating);
+ yield return (ATTRIB_ID_FLASHLIGHT, FlashlightDifficulty);
yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor);
}
@@ -60,13 +60,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{
base.FromDatabaseAttributes(values);
- AimStrain = values[ATTRIB_ID_AIM];
- SpeedStrain = values[ATTRIB_ID_SPEED];
+ AimDifficulty = values[ATTRIB_ID_AIM];
+ SpeedDifficulty = values[ATTRIB_ID_SPEED];
OverallDifficulty = values[ATTRIB_ID_OVERALL_DIFFICULTY];
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
- StarRating = values[ATTRIB_ID_STRAIN];
- FlashlightRating = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT);
+ StarRating = values[ATTRIB_ID_DIFFICULTY];
+ FlashlightDifficulty = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT);
SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR];
}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
index ed42f333c0..c5b1baaad1 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
@@ -74,9 +74,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{
StarRating = starRating,
Mods = mods,
- AimStrain = aimRating,
- SpeedStrain = speedRating,
- FlashlightRating = flashlightRating,
+ AimDifficulty = aimRating,
+ SpeedDifficulty = speedRating,
+ FlashlightDifficulty = flashlightRating,
SliderFactor = sliderFactor,
ApproachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5,
OverallDifficulty = (80 - hitWindowGreat) / 6,
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs
new file mode 100644
index 0000000000..6c7760d144
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs
@@ -0,0 +1,26 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Newtonsoft.Json;
+using osu.Game.Rulesets.Difficulty;
+
+namespace osu.Game.Rulesets.Osu.Difficulty
+{
+ public class OsuPerformanceAttributes : PerformanceAttributes
+ {
+ [JsonProperty("aim")]
+ public double Aim { get; set; }
+
+ [JsonProperty("speed")]
+ public double Speed { get; set; }
+
+ [JsonProperty("accuracy")]
+ public double Accuracy { get; set; }
+
+ [JsonProperty("flashlight")]
+ public double Flashlight { get; set; }
+
+ [JsonProperty("effective_miss_count")]
+ public double EffectiveMissCount { get; set; }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
index 8d45c7a8cc..d7d294df47 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
@@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
{
}
- public override double Calculate(Dictionary categoryRatings = null)
+ public override PerformanceAttributes Calculate()
{
mods = Score.Mods;
accuracy = Score.Accuracy;
@@ -45,7 +45,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double multiplier = 1.12; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things.
- // Custom multipliers for NoFail and SpunOut.
if (mods.Any(m => m is OsuModNoFail))
multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount);
@@ -72,42 +71,35 @@ namespace osu.Game.Rulesets.Osu.Difficulty
Math.Pow(flashlightValue, 1.1), 1.0 / 1.1
) * multiplier;
- if (categoryRatings != null)
+ return new OsuPerformanceAttributes
{
- 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);
- }
-
- return totalValue;
+ Aim = aimValue,
+ Speed = speedValue,
+ Accuracy = accuracyValue,
+ Flashlight = flashlightValue,
+ EffectiveMissCount = effectiveMissCount,
+ Total = totalValue
+ };
}
private double computeAimValue()
{
- double rawAim = Attributes.AimStrain;
+ double rawAim = Attributes.AimDifficulty;
if (mods.Any(m => m is OsuModTouchDevice))
rawAim = Math.Pow(rawAim, 0.8);
double aimValue = Math.Pow(5.0 * Math.Max(1.0, rawAim / 0.0675) - 4.0, 3.0) / 100000.0;
- // 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);
-
aimValue *= lengthBonus;
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
if (effectiveMissCount > 0)
aimValue *= 0.97 * Math.Pow(1 - Math.Pow((double)effectiveMissCount / totalHits, 0.775), effectiveMissCount);
- // Combo scaling.
- if (Attributes.MaxCombo > 0)
- aimValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
+ aimValue *= getComboScalingFactor();
double approachRateFactor = 0.0;
if (Attributes.ApproachRate > 10.33)
@@ -136,7 +128,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
}
aimValue *= accuracy;
- // It is important to also consider accuracy difficulty when doing that.
+ // It is important to consider accuracy difficulty when scaling with accuracy.
aimValue *= 0.98 + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
return aimValue;
@@ -144,9 +136,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty
private double computeSpeedValue()
{
- double speedValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.SpeedStrain / 0.0675) - 4.0, 3.0) / 100000.0;
+ double speedValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.SpeedDifficulty / 0.0675) - 4.0, 3.0) / 100000.0;
- // 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;
@@ -155,9 +146,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (effectiveMissCount > 0)
speedValue *= 0.97 * Math.Pow(1 - Math.Pow((double)effectiveMissCount / totalHits, 0.775), Math.Pow(effectiveMissCount, .875));
- // Combo scaling.
- if (Attributes.MaxCombo > 0)
- speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
+ speedValue *= getComboScalingFactor();
double approachRateFactor = 0.0;
if (Attributes.ApproachRate > 10.33)
@@ -227,14 +216,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (!mods.Any(h => h is OsuModFlashlight))
return 0.0;
- double rawFlashlight = Attributes.FlashlightRating;
+ double rawFlashlight = Attributes.FlashlightDifficulty;
if (mods.Any(m => m is OsuModTouchDevice))
rawFlashlight = Math.Pow(rawFlashlight, 0.8);
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;
@@ -242,9 +230,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (effectiveMissCount > 0)
flashlightValue *= 0.97 * Math.Pow(1 - Math.Pow((double)effectiveMissCount / totalHits, 0.775), Math.Pow(effectiveMissCount, .875));
- // Combo scaling.
- if (Attributes.MaxCombo > 0)
- flashlightValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
+ flashlightValue *= getComboScalingFactor();
// 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) +
@@ -276,6 +262,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
return Math.Max(countMiss, (int)Math.Floor(comboBasedMissCount));
}
+ private double getComboScalingFactor() => Attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(Attributes.MaxCombo, 0.8), 1.0);
private int totalHits => countGreat + countOk + countMeh + countMiss;
private int totalSuccessfulHits => countGreat + countOk + countMeh;
}
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs
index 44ba0e2057..03abba29ce 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
{
}
- private double skillMultiplier => 0.15;
+ private double skillMultiplier => 0.07;
private 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.
@@ -40,26 +40,31 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills
double result = 0.0;
+ OsuDifficultyHitObject lastObj = osuCurrent;
+
+ // This is iterating backwards in time from the current object.
for (int i = 0; i < Previous.Count; i++)
{
- var osuPrevious = (OsuDifficultyHitObject)Previous[i];
- var osuPreviousHitObject = (OsuHitObject)(osuPrevious.BaseObject);
+ var currentObj = (OsuDifficultyHitObject)Previous[i];
+ var currentHitObject = (OsuHitObject)(currentObj.BaseObject);
- if (!(osuPrevious.BaseObject is Spinner))
+ if (!(currentObj.BaseObject is Spinner))
{
- double jumpDistance = (osuHitObject.StackedPosition - osuPreviousHitObject.EndPosition).Length;
+ double jumpDistance = (osuHitObject.StackedPosition - currentHitObject.EndPosition).Length;
- cumulativeStrainTime += osuPrevious.StrainTime;
+ cumulativeStrainTime += lastObj.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 also want to nerf stacks so that only the first object of the stack is accounted for.
- double stackNerf = Math.Min(1.0, (osuPrevious.LazyJumpDistance / scalingFactor) / 25.0);
+ double stackNerf = Math.Min(1.0, (currentObj.LazyJumpDistance / scalingFactor) / 25.0);
- result += Math.Pow(0.8, i) * stackNerf * scalingFactor * jumpDistance / cumulativeStrainTime;
+ result += stackNerf * scalingFactor * jumpDistance / cumulativeStrainTime;
}
+
+ lastObj = currentObj;
}
return Math.Pow(smallDistNerf * result, 2.0);
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs
index b2b5d056c3..31f5a6f570 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs
@@ -9,14 +9,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
{
public class TaikoDifficultyAttributes : DifficultyAttributes
{
- [JsonProperty("stamina_strain")]
- public double StaminaStrain { get; set; }
+ [JsonProperty("stamina_difficulty")]
+ public double StaminaDifficulty { get; set; }
- [JsonProperty("rhythm_strain")]
- public double RhythmStrain { get; set; }
+ [JsonProperty("rhythm_difficulty")]
+ public double RhythmDifficulty { get; set; }
- [JsonProperty("colour_strain")]
- public double ColourStrain { get; set; }
+ [JsonProperty("colour_difficulty")]
+ public double ColourDifficulty { get; set; }
[JsonProperty("approach_rate")]
public double ApproachRate { get; set; }
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
yield return v;
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
- yield return (ATTRIB_ID_STRAIN, StarRating);
+ yield return (ATTRIB_ID_DIFFICULTY, StarRating);
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
}
@@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
base.FromDatabaseAttributes(values);
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
- StarRating = values[ATTRIB_ID_STRAIN];
+ StarRating = values[ATTRIB_ID_DIFFICULTY];
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
}
}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
index e84bee3d28..6afdef3f3c 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs
@@ -91,9 +91,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
{
StarRating = starRating,
Mods = mods,
- StaminaStrain = staminaRating,
- RhythmStrain = rhythmRating,
- ColourStrain = colourRating,
+ StaminaDifficulty = staminaRating,
+ RhythmDifficulty = rhythmRating,
+ ColourDifficulty = colourRating,
GreatHitWindow = hitWindows.WindowFor(HitResult.Great) / clockRate,
MaxCombo = beatmap.HitObjects.Count(h => h is Hit),
};
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs
new file mode 100644
index 0000000000..80552880ea
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs
@@ -0,0 +1,17 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Newtonsoft.Json;
+using osu.Game.Rulesets.Difficulty;
+
+namespace osu.Game.Rulesets.Taiko.Difficulty
+{
+ public class TaikoPerformanceAttributes : PerformanceAttributes
+ {
+ [JsonProperty("difficulty")]
+ public double Difficulty { get; set; }
+
+ [JsonProperty("accuracy")]
+ public double Accuracy { get; set; }
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
index 90dd733dfd..bcd55f8fae 100644
--- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
{
}
- public override double Calculate(Dictionary categoryDifficulty = null)
+ public override PerformanceAttributes Calculate()
{
mods = Score.Mods;
countGreat = Score.Statistics.GetValueOrDefault(HitResult.Great);
@@ -35,7 +35,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
countMeh = Score.Statistics.GetValueOrDefault(HitResult.Meh);
countMiss = Score.Statistics.GetValueOrDefault(HitResult.Miss);
- // Custom multipliers for NoFail and SpunOut.
double multiplier = 1.1; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things
if (mods.Any(m => m is ModNoFail))
@@ -44,43 +43,38 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
if (mods.Any(m => m is ModHidden))
multiplier *= 1.10;
- double strainValue = computeStrainValue();
+ double difficultyValue = computeDifficultyValue();
double accuracyValue = computeAccuracyValue();
double totalValue =
Math.Pow(
- Math.Pow(strainValue, 1.1) +
+ Math.Pow(difficultyValue, 1.1) +
Math.Pow(accuracyValue, 1.1), 1.0 / 1.1
) * multiplier;
- if (categoryDifficulty != null)
+ return new TaikoPerformanceAttributes
{
- categoryDifficulty["Strain"] = strainValue;
- categoryDifficulty["Accuracy"] = accuracyValue;
- }
-
- return totalValue;
+ Difficulty = difficultyValue,
+ Accuracy = accuracyValue,
+ Total = totalValue
+ };
}
- private double computeStrainValue()
+ private double computeDifficultyValue()
{
- double strainValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.StarRating / 0.0075) - 4.0, 2.0) / 100000.0;
+ double difficultyValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.StarRating / 0.0075) - 4.0, 2.0) / 100000.0;
- // Longer maps are worth more
double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0);
- strainValue *= lengthBonus;
+ difficultyValue *= lengthBonus;
- // Penalize misses exponentially. This mainly fixes tag4 maps and the likes until a per-hitobject solution is available
- strainValue *= Math.Pow(0.985, countMiss);
+ difficultyValue *= Math.Pow(0.985, countMiss);
if (mods.Any(m => m is ModHidden))
- strainValue *= 1.025;
+ difficultyValue *= 1.025;
if (mods.Any(m => m is ModFlashlight))
- // Apply length bonus again if flashlight is on simply because it becomes a lot harder on longer maps.
- strainValue *= 1.05 * lengthBonus;
+ difficultyValue *= 1.05 * lengthBonus;
- // Scale the speed value with accuracy _slightly_
- return strainValue * Score.Accuracy;
+ return difficultyValue * Score.Accuracy;
}
private double computeAccuracyValue()
@@ -88,11 +82,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
if (Attributes.GreatHitWindow <= 0)
return 0;
- // Lots of arbitrary values from testing.
- // Considering to use derivation from perfect accuracy in a probabilistic manner - assume normal distribution
double accValue = Math.Pow(150.0 / Attributes.GreatHitWindow, 1.1) * Math.Pow(Score.Accuracy, 15) * 22.0;
- // Bonus for many hitcircles - it's harder to keep good accuracy up for longer
+ // Bonus for many objects - it's harder to keep good accuracy up for longer
return accValue * Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
}
diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs
index d87ac29d75..686e053246 100644
--- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs
+++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs
@@ -128,7 +128,7 @@ namespace osu.Game.Tests.Collections.IO
[Test]
public async Task TestSaveAndReload()
{
- using (HeadlessGameHost host = new TestRunHeadlessGameHost("TestSaveAndReload", bypassCleanup: true))
+ using (HeadlessGameHost host = new CleanRunHeadlessGameHost(bypassCleanup: true))
{
try
{
@@ -149,7 +149,8 @@ namespace osu.Game.Tests.Collections.IO
}
}
- using (HeadlessGameHost host = new TestRunHeadlessGameHost("TestSaveAndReload"))
+ // Name matches the automatically chosen name from `CleanRunHeadlessGameHost` above, so we end up using the same storage location.
+ using (HeadlessGameHost host = new TestRunHeadlessGameHost(nameof(TestSaveAndReload)))
{
try
{
diff --git a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
index 8a063b3c6e..8d15be44fa 100644
--- a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
+++ b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
@@ -61,6 +61,7 @@ namespace osu.Game.Tests.NonVisual
finally
{
host.Exit();
+ cleanupPath(customPath);
}
}
}
@@ -94,6 +95,7 @@ namespace osu.Game.Tests.NonVisual
finally
{
host.Exit();
+ cleanupPath(customPath);
}
}
}
@@ -160,6 +162,7 @@ namespace osu.Game.Tests.NonVisual
finally
{
host.Exit();
+ cleanupPath(customPath);
}
}
}
@@ -168,7 +171,7 @@ namespace osu.Game.Tests.NonVisual
public void TestMigrationBetweenTwoTargets()
{
string customPath = prepareCustomPath();
- string customPath2 = prepareCustomPath("-2");
+ string customPath2 = prepareCustomPath();
using (var host = new CustomTestHeadlessGameHost())
{
@@ -185,7 +188,7 @@ namespace osu.Game.Tests.NonVisual
Assert.That(File.Exists(Path.Combine(customPath2, database_filename)));
// some files may have been left behind for whatever reason, but that's not what we're testing here.
- customPath = prepareCustomPath();
+ cleanupPath(customPath);
Assert.DoesNotThrow(() => osu.Migrate(customPath));
Assert.That(File.Exists(Path.Combine(customPath, database_filename)));
@@ -193,6 +196,8 @@ namespace osu.Game.Tests.NonVisual
finally
{
host.Exit();
+ cleanupPath(customPath);
+ cleanupPath(customPath2);
}
}
}
@@ -214,6 +219,7 @@ namespace osu.Game.Tests.NonVisual
finally
{
host.Exit();
+ cleanupPath(customPath);
}
}
}
@@ -243,6 +249,7 @@ namespace osu.Game.Tests.NonVisual
finally
{
host.Exit();
+ cleanupPath(customPath);
}
}
}
@@ -272,6 +279,7 @@ namespace osu.Game.Tests.NonVisual
finally
{
host.Exit();
+ cleanupPath(customPath);
}
}
}
@@ -286,14 +294,18 @@ namespace osu.Game.Tests.NonVisual
return path;
}
- private string prepareCustomPath(string suffix = "")
+ private static string prepareCustomPath() => Path.Combine(TestRunHeadlessGameHost.TemporaryTestDirectory, $"custom-path-{Guid.NewGuid()}");
+
+ private static void cleanupPath(string path)
{
- string path = Path.Combine(TestRunHeadlessGameHost.TemporaryTestDirectory, $"custom-path{suffix}");
-
- if (Directory.Exists(path))
- Directory.Delete(path, true);
-
- return path;
+ try
+ {
+ if (Directory.Exists(path))
+ Directory.Delete(path, true);
+ }
+ catch
+ {
+ }
}
public class CustomTestHeadlessGameHost : CleanRunHeadlessGameHost
diff --git a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs
index bc0041e2c2..0c49a18c8f 100644
--- a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs
+++ b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs
@@ -68,7 +68,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
public void TestPlayingUsersUpdatedOnJoin()
{
AddStep("leave room", () => Client.LeaveRoom());
- AddUntilStep("wait for room part", () => Client.Room == null);
+ AddUntilStep("wait for room part", () => !RoomJoined);
AddStep("create room initially in gameplay", () =>
{
diff --git a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs
index d5fd803986..cd02f15adf 100644
--- a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs
+++ b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs
@@ -1,9 +1,10 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using NUnit.Framework;
using osu.Game.Configuration;
-using osu.Game.Input;
+using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Tests.NonVisual
{
@@ -11,37 +12,32 @@ namespace osu.Game.Tests.NonVisual
public class SessionStaticsTest
{
private SessionStatics sessionStatics;
- private IdleTracker sessionIdleTracker;
- [SetUp]
- public void SetUp()
+ [Test]
+ public void TestSessionStaticsReset()
{
sessionStatics = new SessionStatics();
- sessionIdleTracker = new GameIdleTracker(1000);
sessionStatics.SetValue(Static.LoginOverlayDisplayed, true);
sessionStatics.SetValue(Static.MutedAudioNotificationShownOnce, true);
sessionStatics.SetValue(Static.LowBatteryNotificationShownOnce, true);
sessionStatics.SetValue(Static.LastHoverSoundPlaybackTime, (double?)1d);
+ sessionStatics.SetValue(Static.SeasonalBackgrounds, new APISeasonalBackgrounds { EndDate = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero) });
- sessionIdleTracker.IsIdle.BindValueChanged(e =>
- {
- if (e.NewValue)
- sessionStatics.ResetValues();
- });
- }
+ Assert.IsFalse(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault);
+ Assert.IsFalse(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault);
+ Assert.IsFalse(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault);
+ Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault);
+ Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault);
- [Test]
- [Timeout(2000)]
- public void TestSessionStaticsReset()
- {
- sessionIdleTracker.IsIdle.BindValueChanged(e =>
- {
- Assert.IsTrue(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault);
- Assert.IsTrue(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault);
- Assert.IsTrue(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault);
- Assert.IsTrue(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault);
- });
+ sessionStatics.ResetAfterInactivity();
+
+ Assert.IsTrue(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault);
+ Assert.IsTrue(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault);
+ Assert.IsTrue(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault);
+ // some statics should not reset despite inactivity.
+ Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault);
+ Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault);
}
}
}
diff --git a/osu.Game.Tests/OnlinePlay/PlaylistExtensionsTest.cs b/osu.Game.Tests/OnlinePlay/PlaylistExtensionsTest.cs
new file mode 100644
index 0000000000..d33081662d
--- /dev/null
+++ b/osu.Game.Tests/OnlinePlay/PlaylistExtensionsTest.cs
@@ -0,0 +1,100 @@
+// 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.Game.Online.Rooms;
+
+namespace osu.Game.Tests.OnlinePlay
+{
+ [TestFixture]
+ public class PlaylistExtensionsTest
+ {
+ [Test]
+ public void TestEmpty()
+ {
+ // mostly an extreme edge case, i.e. during room creation.
+ var items = Array.Empty();
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(items.GetHistoricalItems(), Is.Empty);
+ Assert.That(items.GetCurrentItem(), Is.Null);
+ Assert.That(items.GetUpcomingItems(), Is.Empty);
+ });
+ }
+
+ [Test]
+ public void TestPlaylistItemsInOrder()
+ {
+ var items = new[]
+ {
+ new PlaylistItem { ID = 1, BeatmapID = 1001, PlaylistOrder = 1 },
+ new PlaylistItem { ID = 2, BeatmapID = 1002, PlaylistOrder = 2 },
+ new PlaylistItem { ID = 3, BeatmapID = 1003, PlaylistOrder = 3 },
+ };
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(items.GetHistoricalItems(), Is.Empty);
+ Assert.That(items.GetCurrentItem(), Is.EqualTo(items[0]));
+ Assert.That(items.GetUpcomingItems(), Is.EquivalentTo(items));
+ });
+ }
+
+ [Test]
+ public void TestPlaylistItemsOutOfOrder()
+ {
+ var items = new[]
+ {
+ new PlaylistItem { ID = 2, BeatmapID = 1002, PlaylistOrder = 2 },
+ new PlaylistItem { ID = 1, BeatmapID = 1001, PlaylistOrder = 1 },
+ new PlaylistItem { ID = 3, BeatmapID = 1003, PlaylistOrder = 3 },
+ };
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(items.GetHistoricalItems(), Is.Empty);
+ Assert.That(items.GetCurrentItem(), Is.EqualTo(items[1]));
+ Assert.That(items.GetUpcomingItems(), Is.EquivalentTo(new[] { items[1], items[0], items[2] }));
+ });
+ }
+
+ [Test]
+ public void TestExpiredPlaylistItemsSkipped()
+ {
+ var items = new[]
+ {
+ new PlaylistItem { ID = 1, BeatmapID = 1001, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 55, 0, TimeSpan.Zero) },
+ new PlaylistItem { ID = 2, BeatmapID = 1002, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 53, 0, TimeSpan.Zero) },
+ new PlaylistItem { ID = 3, BeatmapID = 1003, PlaylistOrder = 3 },
+ };
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(items.GetHistoricalItems(), Is.EquivalentTo(new[] { items[1], items[0] }));
+ Assert.That(items.GetCurrentItem(), Is.EqualTo(items[2]));
+ Assert.That(items.GetUpcomingItems(), Is.EquivalentTo(new[] { items[2] }));
+ });
+ }
+
+ [Test]
+ public void TestAllItemsExpired()
+ {
+ var items = new[]
+ {
+ new PlaylistItem { ID = 1, BeatmapID = 1001, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 55, 0, TimeSpan.Zero) },
+ new PlaylistItem { ID = 2, BeatmapID = 1002, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 53, 0, TimeSpan.Zero) },
+ new PlaylistItem { ID = 3, BeatmapID = 1002, Expired = true, PlayedAt = new DateTimeOffset(2021, 12, 21, 7, 57, 0, TimeSpan.Zero) },
+ };
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(items.GetHistoricalItems(), Is.EquivalentTo(new[] { items[1], items[0], items[2] }));
+ // if all items are expired, the last-played item is expected to be returned.
+ Assert.That(items.GetCurrentItem(), Is.EqualTo(items[2]));
+ Assert.That(items.GetUpcomingItems(), Is.Empty);
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
index 0b9857486a..7b5e1f4ec7 100644
--- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
+++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs
@@ -96,6 +96,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
var longName = CreateAPIBeatmapSet(Ruleset.Value);
longName.Title = longName.TitleUnicode = "this track has an incredibly and implausibly long title";
longName.Artist = longName.ArtistUnicode = "and this artist! who would have thunk it. it's really such a long name.";
+ longName.Source = "wow. even the source field has an impossibly long string in it. this really takes the cake, doesn't it?";
longName.HasExplicitContent = true;
longName.TrackId = 444;
@@ -251,13 +252,19 @@ namespace osu.Game.Tests.Visual.Beatmaps
[Test]
public void TestNormal()
{
- createTestCase(beatmapSetInfo => new BeatmapCard(beatmapSetInfo));
+ createTestCase(beatmapSetInfo => new BeatmapCardNormal(beatmapSetInfo));
+ }
+
+ [Test]
+ public void TestExtra()
+ {
+ createTestCase(beatmapSetInfo => new BeatmapCardExtra(beatmapSetInfo));
}
[Test]
public void TestHoverState()
{
- AddStep("create cards", () => Child = createContent(OverlayColourScheme.Blue, s => new BeatmapCard(s)));
+ AddStep("create cards", () => Child = createContent(OverlayColourScheme.Blue, s => new BeatmapCardNormal(s)));
AddStep("Hover card", () => InputManager.MoveMouseTo(firstCard()));
AddWaitStep("wait for potential state change", 5);
@@ -274,10 +281,10 @@ namespace osu.Game.Tests.Visual.Beatmaps
AddWaitStep("wait for potential state change", 5);
AddAssert("card is still expanded", () => firstCard().Expanded.Value);
- AddStep("Hover away", () => InputManager.MoveMouseTo(this.ChildrenOfType().Last()));
+ AddStep("Hover away", () => InputManager.MoveMouseTo(this.ChildrenOfType().Last()));
AddUntilStep("card is not expanded", () => !firstCard().Expanded.Value);
- BeatmapCard firstCard() => this.ChildrenOfType().First();
+ BeatmapCardNormal firstCard() => this.ChildrenOfType().First();
}
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs
index a718a98aa6..95603b5c04 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs
@@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Gameplay
private void checkForFirstSamplePlayback()
{
- AddUntilStep("storyboard loaded", () => Player.Beatmap.Value.StoryboardLoaded);
+ AddAssert("storyboard loaded", () => Player.Beatmap.Value.Storyboard != null);
AddUntilStep("any storyboard samples playing", () => allStoryboardSamples.Any(sound => sound.IsPlaying));
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
index 5acb44ac45..88c54eb2bb 100644
--- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
@@ -5,7 +5,6 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
-using osu.Framework.Graphics.UserInterface;
using osu.Framework.Platform;
using osu.Framework.Screens;
using osu.Framework.Testing;
@@ -20,7 +19,6 @@ using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
using osu.Game.Screens.Play;
using osu.Game.Tests.Resources;
-using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -86,11 +84,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true);
AddWaitStep("wait for transition", 2);
- AddStep("create room", () =>
- {
- InputManager.MoveMouseTo(this.ChildrenOfType().Single());
- InputManager.Click(MouseButton.Left);
- });
+ ClickButtonWhenEnabled();
AddUntilStep("wait for join", () => Client.RoomJoined);
}
@@ -104,24 +98,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
protected void RunGameplay()
{
AddUntilStep("wait for idle", () => Client.LocalUser?.State == MultiplayerUserState.Idle);
- clickReadyButton();
+ ClickButtonWhenEnabled();
AddUntilStep("wait for ready", () => Client.LocalUser?.State == MultiplayerUserState.Ready);
- clickReadyButton();
+ ClickButtonWhenEnabled();
AddUntilStep("wait for player", () => multiplayerComponents.CurrentScreen is Player player && player.IsLoaded);
AddStep("exit player", () => multiplayerComponents.MultiplayerScreen.MakeCurrent());
}
-
- private void clickReadyButton()
- {
- AddUntilStep("wait for ready button to be enabled", () => this.ChildrenOfType().Single().ChildrenOfType
-
+
@@ -83,7 +83,7 @@
-
+