From 102576cd8c5baa9077e5b1b864b52c83c23c71ae Mon Sep 17 00:00:00 2001 From: Elvendir Date: Sat, 18 Mar 2023 17:53:41 +0100 Subject: [PATCH 001/223] adddede LastPlayed as filter option in beatmap carousel --- .../Select/Carousel/CarouselBeatmap.cs | 1 + osu.Game/Screens/Select/FilterCriteria.cs | 1 + osu.Game/Screens/Select/FilterQueryParser.cs | 53 ++++++++++++++++++- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 7e48bc5cdd..5088dfdc02 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -48,6 +48,7 @@ namespace osu.Game.Screens.Select.Carousel match &= !criteria.CircleSize.HasFilter || criteria.CircleSize.IsInRange(BeatmapInfo.Difficulty.CircleSize); match &= !criteria.OverallDifficulty.HasFilter || criteria.OverallDifficulty.IsInRange(BeatmapInfo.Difficulty.OverallDifficulty); match &= !criteria.Length.HasFilter || criteria.Length.IsInRange(BeatmapInfo.Length); + match &= !criteria.LastPlayed.HasFilter || criteria.LastPlayed.IsInRange(BeatmapInfo.LastPlayed); match &= !criteria.BPM.HasFilter || criteria.BPM.IsInRange(BeatmapInfo.BPM); match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor); diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs index 320bfb1b45..a2da98368d 100644 --- a/osu.Game/Screens/Select/FilterCriteria.cs +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -31,6 +31,7 @@ namespace osu.Game.Screens.Select public OptionalRange BPM; public OptionalRange BeatDivisor; public OptionalRange OnlineStatus; + public OptionalRange LastPlayed; public OptionalTextFilter Creator; public OptionalTextFilter Artist; diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index c86554ddbc..6b6b2f04a9 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -61,6 +61,10 @@ namespace osu.Game.Screens.Select case "length": return tryUpdateLengthRange(criteria, op, value); + case "played": + case "lastplayed": + return tryUpdateLastPlayedRange(criteria, op, value); + case "divisor": return TryUpdateCriteriaRange(ref criteria.BeatDivisor, op, value, tryParseInt); @@ -109,7 +113,8 @@ namespace osu.Game.Screens.Select value.EndsWith("ms", StringComparison.Ordinal) ? 1 : value.EndsWith('s') ? 1000 : value.EndsWith('m') ? 60000 : - value.EndsWith('h') ? 3600000 : 1000; + value.EndsWith('h') ? 3600000 : + value.EndsWith('d') ? 86400000 : 1000; private static bool tryParseFloatWithPoint(string value, out float result) => float.TryParse(value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out result); @@ -368,5 +373,51 @@ namespace osu.Game.Screens.Select return tryUpdateCriteriaRange(ref criteria.Length, op, totalLength, minScale / 2.0); } + + private static bool tryUpdateLastPlayedRange(FilterCriteria criteria, Operator op, string val) + { + List parts = new List(); + + GroupCollection? match = null; + + match ??= tryMatchRegex(val, @"^((?\d+):)?(?\d+):(?\d+)$"); + match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); + match ??= tryMatchRegex(val, @"^(?\d+(\.\d+)?)$"); + + if (match == null) + return false; + + if (match["seconds"].Success) + parts.Add(match["seconds"].Value + "s"); + if (match["minutes"].Success) + parts.Add(match["minutes"].Value + "m"); + if (match["hours"].Success) + parts.Add(match["hours"].Value + "h"); + if (match["days"].Success) + parts.Add(match["days"].Value + "d"); + + + double totalLength = 0; + int minScale = 86400000; + + for (int i = 0; i < parts.Count; i++) + { + string part = parts[i]; + string partNoUnit = part.TrimEnd('m', 's', 'h', 'd') ; + if (!tryParseDoubleWithPoint(partNoUnit, out double length)) + return false; + + if (i != parts.Count - 1 && length >= 60) + return false; + if (i != 0 && partNoUnit.Contains('.')) + return false; + + int scale = getLengthScale(part); + totalLength += length * scale; + minScale = Math.Min(minScale, scale); + } + + return tryUpdateCriteriaRange(ref criteria.LastPlayed, op, totalLength, minScale / 2.0); + } } } From 216a88e18d71f74ddccea1b70aff77305ec88920 Mon Sep 17 00:00:00 2001 From: Elvendir Date: Sat, 18 Mar 2023 21:35:10 +0100 Subject: [PATCH 002/223] limited max Date comparison --- .../Screens/Select/Carousel/CarouselBeatmap.cs | 2 +- osu.Game/Screens/Select/FilterQueryParser.cs | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 5088dfdc02..069d4f36d6 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Select.Carousel match &= !criteria.CircleSize.HasFilter || criteria.CircleSize.IsInRange(BeatmapInfo.Difficulty.CircleSize); match &= !criteria.OverallDifficulty.HasFilter || criteria.OverallDifficulty.IsInRange(BeatmapInfo.Difficulty.OverallDifficulty); match &= !criteria.Length.HasFilter || criteria.Length.IsInRange(BeatmapInfo.Length); - match &= !criteria.LastPlayed.HasFilter || criteria.LastPlayed.IsInRange(BeatmapInfo.LastPlayed); + match &= !criteria.LastPlayed.HasFilter || criteria.LastPlayed.IsInRange(BeatmapInfo.LastPlayed ?? DateTimeOffset.MinValue); match &= !criteria.BPM.HasFilter || criteria.BPM.IsInRange(BeatmapInfo.BPM); match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor); diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 6b6b2f04a9..38040c2f79 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -381,7 +381,7 @@ namespace osu.Game.Screens.Select GroupCollection? match = null; match ??= tryMatchRegex(val, @"^((?\d+):)?(?\d+):(?\d+)$"); - match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); + match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)d)?((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); match ??= tryMatchRegex(val, @"^(?\d+(\.\d+)?)$"); if (match == null) @@ -403,7 +403,7 @@ namespace osu.Game.Screens.Select for (int i = 0; i < parts.Count; i++) { string part = parts[i]; - string partNoUnit = part.TrimEnd('m', 's', 'h', 'd') ; + string partNoUnit = part.TrimEnd('m', 's', 'h', 'd'); if (!tryParseDoubleWithPoint(partNoUnit, out double length)) return false; @@ -417,7 +417,16 @@ namespace osu.Game.Screens.Select minScale = Math.Min(minScale, scale); } - return tryUpdateCriteriaRange(ref criteria.LastPlayed, op, totalLength, minScale / 2.0); + totalLength += minScale / 2; + + // Limits the date to ~2000 years compared to now + // Might want to do it differently before 4000 A.C. + double limit = 86400000; + limit *= 365 * 2000; + totalLength = Math.Min(totalLength, limit); + + DateTimeOffset dateTimeOffset = DateTimeOffset.Now; + return tryUpdateCriteriaRange(ref criteria.LastPlayed, op, dateTimeOffset.AddMilliseconds(-totalLength)); } } } From 6dead81d211a760e185ff0248a080454e6729197 Mon Sep 17 00:00:00 2001 From: Elvendir Date: Sun, 19 Mar 2023 18:43:17 +0100 Subject: [PATCH 003/223] Generalized tryUpdateLastPlayedRange to tryUpdateDateRange and Added tests --- .../Filtering/FilterQueryParserTest.cs | 82 ++++++++++++++ osu.Game/Screens/Select/FilterQueryParser.cs | 107 ++++++++++++------ 2 files changed, 152 insertions(+), 37 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index da32edb8fb..9460228644 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -316,5 +316,87 @@ namespace osu.Game.Tests.NonVisual.Filtering return false; } } + + //Date criteria testing + + private static readonly object[] correct_date_query_examples = + { + new object[] { "600" }, + new object[] { "120:120" }, + new object[] { "48:0:0" }, + new object[] { "0.5s" }, + new object[] { "120m" }, + new object[] { "48h120s" }, + new object[] { "10y24M" }, + new object[] { "10y60d120s" }, + new object[] { "0.1y0.1M2d" }, + new object[] { "0.99y0.99M2d" } + }; + + [Test] + [TestCaseSource(nameof(correct_date_query_examples))] + public void TestValidDateQueries(string dateQuery) + { + string query = $"played={dateQuery} time"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter); + } + + private static readonly object[] incorrect_date_query_examples = + { + new object[] { "7m27" }, + new object[] { "7m7m7m" }, + new object[] { "5s6m" }, + new object[] { "7d7y" }, + new object[] { ":0" }, + new object[] { "0:3:" }, + new object[] { "\"three days\"" } + }; + + [Test] + [TestCaseSource(nameof(incorrect_date_query_examples))] + public void TestInvalidDateQueries(string dateQuery) + { + string query = $"played={dateQuery} time"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual(false, filterCriteria.LastPlayed.HasFilter); + } + + private static readonly object[] list_operators = + { + new object[] { "=", false, false, true, true }, + new object[] { ":", false, false, true, true }, + new object[] { "<", false, true, false, false }, + new object[] { "<=", false, true, true, false }, + new object[] { "<:", false, true, true, false }, + new object[] { ">", true, false, false, false }, + new object[] { ">=", true, false, false, true }, + new object[] { ">:", true, false, false, true } + }; + + [Test] + [TestCaseSource(nameof(list_operators))] + public void TestComparisonDateQueries(string ope, bool minIsNull, bool maxIsNull, bool isLowerInclusive, bool isUpperInclusive) + { + string query = $"played{ope}50"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual(isLowerInclusive, filterCriteria.LastPlayed.IsLowerInclusive); + Assert.AreEqual(isUpperInclusive, filterCriteria.LastPlayed.IsUpperInclusive); + Assert.AreEqual(maxIsNull, filterCriteria.LastPlayed.Max == null); + Assert.AreEqual(minIsNull, filterCriteria.LastPlayed.Min == null); + } + + [Test] + public void TestOutofrangeDateQuery() + { + const string query = "played=10000y"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter); + Assert.AreEqual(DateTimeOffset.MinValue.AddMilliseconds(1), filterCriteria.LastPlayed.Min); + } } } diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 38040c2f79..f66f1bcd1d 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -63,7 +63,7 @@ namespace osu.Game.Screens.Select case "played": case "lastplayed": - return tryUpdateLastPlayedRange(criteria, op, value); + return tryUpdateDateRange(ref criteria.LastPlayed, op, value); case "divisor": return TryUpdateCriteriaRange(ref criteria.BeatDivisor, op, value, tryParseInt); @@ -374,59 +374,92 @@ namespace osu.Game.Screens.Select return tryUpdateCriteriaRange(ref criteria.Length, op, totalLength, minScale / 2.0); } - private static bool tryUpdateLastPlayedRange(FilterCriteria criteria, Operator op, string val) + private static bool tryUpdateDateRange(ref FilterCriteria.OptionalRange dateRange, Operator op, string val) { - List parts = new List(); - GroupCollection? match = null; match ??= tryMatchRegex(val, @"^((?\d+):)?(?\d+):(?\d+)$"); - match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)d)?((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); + match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)y)?((?\d+(\.\d+)?)M)?((?\d+(\.\d+)?)d)?((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); match ??= tryMatchRegex(val, @"^(?\d+(\.\d+)?)$"); if (match == null) return false; - if (match["seconds"].Success) - parts.Add(match["seconds"].Value + "s"); - if (match["minutes"].Success) - parts.Add(match["minutes"].Value + "m"); - if (match["hours"].Success) - parts.Add(match["hours"].Value + "h"); - if (match["days"].Success) - parts.Add(match["days"].Value + "d"); + DateTimeOffset dateTimeOffset = DateTimeOffset.Now; - - double totalLength = 0; - int minScale = 86400000; - - for (int i = 0; i < parts.Count; i++) + try { - string part = parts[i]; - string partNoUnit = part.TrimEnd('m', 's', 'h', 'd'); - if (!tryParseDoubleWithPoint(partNoUnit, out double length)) - return false; + List keys = new List { "seconds", "minutes", "hours", "days", "months", "years" }; - if (i != parts.Count - 1 && length >= 60) - return false; - if (i != 0 && partNoUnit.Contains('.')) - return false; + foreach (string key in keys) + { + if (match[key].Success) + { + if (!tryParseDoubleWithPoint(match[key].Value, out double length)) + return false; - int scale = getLengthScale(part); - totalLength += length * scale; - minScale = Math.Min(minScale, scale); + switch (key) + { + case "seconds": + dateTimeOffset = dateTimeOffset.AddSeconds(-length); + break; + + case "minutes": + dateTimeOffset = dateTimeOffset.AddMinutes(-length); + break; + + case "hours": + dateTimeOffset = dateTimeOffset.AddHours(-length); + break; + + case "days": + dateTimeOffset = dateTimeOffset.AddDays(-length); + break; + + case "months": + dateTimeOffset = dateTimeOffset.AddMonths(-(int)Math.Round(length)); + break; + + case "years": + dateTimeOffset = dateTimeOffset.AddYears(-(int)Math.Round(length)); + break; + } + } + } + } + // If DateTime to compare is out-scope put it to Min + catch (Exception) + { + dateTimeOffset = DateTimeOffset.MinValue; + dateTimeOffset = dateTimeOffset.AddMilliseconds(1); } - totalLength += minScale / 2; + return tryUpdateCriteriaRange(ref dateRange, invert(op), dateTimeOffset); + } - // Limits the date to ~2000 years compared to now - // Might want to do it differently before 4000 A.C. - double limit = 86400000; - limit *= 365 * 2000; - totalLength = Math.Min(totalLength, limit); + // Function to reverse an Operator + private static Operator invert(Operator ope) + { + switch (ope) + { + default: + return Operator.Equal; - DateTimeOffset dateTimeOffset = DateTimeOffset.Now; - return tryUpdateCriteriaRange(ref criteria.LastPlayed, op, dateTimeOffset.AddMilliseconds(-totalLength)); + case Operator.Equal: + return Operator.Equal; + + case Operator.Greater: + return Operator.Less; + + case Operator.GreaterOrEqual: + return Operator.LessOrEqual; + + case Operator.Less: + return Operator.Greater; + + case Operator.LessOrEqual: + return Operator.GreaterOrEqual; + } } } } From 4b053b47852ea46ad104156d81a84e3bdaaf3b04 Mon Sep 17 00:00:00 2001 From: Elvendir Date: Sat, 1 Apr 2023 22:58:25 +0200 Subject: [PATCH 004/223] changed regex match to be inline with standard --- .../NonVisual/Filtering/FilterQueryParserTest.cs | 3 +-- osu.Game/Screens/Select/FilterQueryParser.cs | 9 +++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 9460228644..b0cc9146d2 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -322,8 +322,6 @@ namespace osu.Game.Tests.NonVisual.Filtering private static readonly object[] correct_date_query_examples = { new object[] { "600" }, - new object[] { "120:120" }, - new object[] { "48:0:0" }, new object[] { "0.5s" }, new object[] { "120m" }, new object[] { "48h120s" }, @@ -350,6 +348,7 @@ namespace osu.Game.Tests.NonVisual.Filtering new object[] { "5s6m" }, new object[] { "7d7y" }, new object[] { ":0" }, + new object[] { "0:3:6" }, new object[] { "0:3:" }, new object[] { "\"three days\"" } }; diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index f66f1bcd1d..f66b8fd377 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -378,9 +378,8 @@ namespace osu.Game.Screens.Select { GroupCollection? match = null; - match ??= tryMatchRegex(val, @"^((?\d+):)?(?\d+):(?\d+)$"); match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)y)?((?\d+(\.\d+)?)M)?((?\d+(\.\d+)?)d)?((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); - match ??= tryMatchRegex(val, @"^(?\d+(\.\d+)?)$"); + match ??= tryMatchRegex(val, @"^(?\d+(\.\d+)?)$"); if (match == null) return false; @@ -417,11 +416,13 @@ namespace osu.Game.Screens.Select break; case "months": - dateTimeOffset = dateTimeOffset.AddMonths(-(int)Math.Round(length)); + dateTimeOffset = dateTimeOffset.AddMonths(-(int)Math.Floor(length)); + dateTimeOffset = dateTimeOffset.AddDays(-30 * (length - Math.Floor(length))); break; case "years": - dateTimeOffset = dateTimeOffset.AddYears(-(int)Math.Round(length)); + dateTimeOffset = dateTimeOffset.AddYears(-(int)Math.Floor(length)); + dateTimeOffset = dateTimeOffset.AddDays(-365 * (length - Math.Floor(length))); break; } } From 52adb99fe5fe4f7f7ea756f0723354f17904203e Mon Sep 17 00:00:00 2001 From: Elvendir <39671719+Elvendir@users.noreply.github.com> Date: Tue, 4 Apr 2023 19:29:37 +0200 Subject: [PATCH 005/223] Update osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index b0cc9146d2..627b44dcd7 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -317,7 +317,6 @@ namespace osu.Game.Tests.NonVisual.Filtering } } - //Date criteria testing private static readonly object[] correct_date_query_examples = { From d6c6507578a0fd3a7a8a502c15febd91b0123069 Mon Sep 17 00:00:00 2001 From: Elvendir <39671719+Elvendir@users.noreply.github.com> Date: Tue, 4 Apr 2023 19:30:13 +0200 Subject: [PATCH 006/223] Update osu.Game/Screens/Select/FilterQueryParser.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Screens/Select/FilterQueryParser.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index f66b8fd377..9582694248 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -428,8 +428,7 @@ namespace osu.Game.Screens.Select } } } - // If DateTime to compare is out-scope put it to Min - catch (Exception) + catch (ArgumentOutOfRangeException) { dateTimeOffset = DateTimeOffset.MinValue; dateTimeOffset = dateTimeOffset.AddMilliseconds(1); From 0c1d6eb89465066285668b619bc73a54c9fa964c Mon Sep 17 00:00:00 2001 From: Elvendir Date: Wed, 5 Apr 2023 11:42:39 +0200 Subject: [PATCH 007/223] - rewrote upper and lower bound tests - removed equality in tests --- .../Filtering/FilterQueryParserTest.cs | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 627b44dcd7..c1678f14a6 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -317,7 +317,6 @@ namespace osu.Game.Tests.NonVisual.Filtering } } - private static readonly object[] correct_date_query_examples = { new object[] { "600" }, @@ -334,7 +333,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [TestCaseSource(nameof(correct_date_query_examples))] public void TestValidDateQueries(string dateQuery) { - string query = $"played={dateQuery} time"; + string query = $"played<{dateQuery} time"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter); @@ -342,11 +341,11 @@ namespace osu.Game.Tests.NonVisual.Filtering private static readonly object[] incorrect_date_query_examples = { + new object[] { ".5s" }, new object[] { "7m27" }, new object[] { "7m7m7m" }, new object[] { "5s6m" }, new object[] { "7d7y" }, - new object[] { ":0" }, new object[] { "0:3:6" }, new object[] { "0:3:" }, new object[] { "\"three days\"" } @@ -356,41 +355,36 @@ namespace osu.Game.Tests.NonVisual.Filtering [TestCaseSource(nameof(incorrect_date_query_examples))] public void TestInvalidDateQueries(string dateQuery) { - string query = $"played={dateQuery} time"; + string query = $"played<{dateQuery} time"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual(false, filterCriteria.LastPlayed.HasFilter); } - private static readonly object[] list_operators = - { - new object[] { "=", false, false, true, true }, - new object[] { ":", false, false, true, true }, - new object[] { "<", false, true, false, false }, - new object[] { "<=", false, true, true, false }, - new object[] { "<:", false, true, true, false }, - new object[] { ">", true, false, false, false }, - new object[] { ">=", true, false, false, true }, - new object[] { ">:", true, false, false, true } - }; - [Test] - [TestCaseSource(nameof(list_operators))] - public void TestComparisonDateQueries(string ope, bool minIsNull, bool maxIsNull, bool isLowerInclusive, bool isUpperInclusive) + public void TestGreaterDateQuery() { - string query = $"played{ope}50"; + const string query = "played>50"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual(isLowerInclusive, filterCriteria.LastPlayed.IsLowerInclusive); - Assert.AreEqual(isUpperInclusive, filterCriteria.LastPlayed.IsUpperInclusive); - Assert.AreEqual(maxIsNull, filterCriteria.LastPlayed.Max == null); - Assert.AreEqual(minIsNull, filterCriteria.LastPlayed.Min == null); + Assert.AreEqual(false, filterCriteria.LastPlayed.Max == null); + Assert.AreEqual(true, filterCriteria.LastPlayed.Min == null); + } + + [Test] + public void TestLowerDateQuery() + { + const string query = "played<50"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual(true, filterCriteria.LastPlayed.Max == null); + Assert.AreEqual(false, filterCriteria.LastPlayed.Min == null); } [Test] public void TestOutofrangeDateQuery() { - const string query = "played=10000y"; + const string query = "played<10000y"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter); From df170517a85ea1949d20b6df1043143ac028ffec Mon Sep 17 00:00:00 2001 From: Elvendir Date: Wed, 5 Apr 2023 11:59:31 +0200 Subject: [PATCH 008/223] -renamed function inverse() to reverseInequalityOperator() for clarity -changed default case of reverseInequalityOperator() to out of range exception --- osu.Game/Screens/Select/FilterQueryParser.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 9582694248..bd4c29e457 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -434,16 +434,16 @@ namespace osu.Game.Screens.Select dateTimeOffset = dateTimeOffset.AddMilliseconds(1); } - return tryUpdateCriteriaRange(ref dateRange, invert(op), dateTimeOffset); + return tryUpdateCriteriaRange(ref dateRange, reverseInequalityOperator(op), dateTimeOffset); } // Function to reverse an Operator - private static Operator invert(Operator ope) + private static Operator reverseInequalityOperator(Operator ope) { switch (ope) { default: - return Operator.Equal; + throw new ArgumentOutOfRangeException(nameof(ope), $"Unsupported operator {ope}"); case Operator.Equal: return Operator.Equal; From c2f225f0253030ea03e710f1647da26f6b106377 Mon Sep 17 00:00:00 2001 From: Elvendir Date: Wed, 5 Apr 2023 21:25:58 +0200 Subject: [PATCH 009/223] Made Operator.Equal not parse for date filter and added corresponding test --- .../NonVisual/Filtering/FilterQueryParserTest.cs | 9 +++++++++ osu.Game/Screens/Select/FilterQueryParser.cs | 3 +++ 2 files changed, 12 insertions(+) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index c1678f14a6..450e6bdde7 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -381,6 +381,15 @@ namespace osu.Game.Tests.NonVisual.Filtering Assert.AreEqual(false, filterCriteria.LastPlayed.Min == null); } + [Test] + public void TestEqualDateQuery() + { + const string query = "played=50"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual(false, filterCriteria.LastPlayed.HasFilter); + } + [Test] public void TestOutofrangeDateQuery() { diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index bd4c29e457..70893c188d 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -376,6 +376,9 @@ namespace osu.Game.Screens.Select private static bool tryUpdateDateRange(ref FilterCriteria.OptionalRange dateRange, Operator op, string val) { + if (op == Operator.Equal) + return false; + GroupCollection? match = null; match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)y)?((?\d+(\.\d+)?)M)?((?\d+(\.\d+)?)d)?((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); From 928145cdeb3b523833ed6b5f3f85c830d91f4dc8 Mon Sep 17 00:00:00 2001 From: Elvendir Date: Wed, 5 Apr 2023 22:12:15 +0200 Subject: [PATCH 010/223] Enforce integer value before y and M Change impacted Tests --- .../NonVisual/Filtering/FilterQueryParserTest.cs | 8 +++++--- osu.Game/Screens/Select/FilterQueryParser.cs | 12 ++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 450e6bdde7..78b428e7c0 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -325,8 +325,8 @@ namespace osu.Game.Tests.NonVisual.Filtering new object[] { "48h120s" }, new object[] { "10y24M" }, new object[] { "10y60d120s" }, - new object[] { "0.1y0.1M2d" }, - new object[] { "0.99y0.99M2d" } + new object[] { "0y0M2d" }, + new object[] { "1y1M2d" } }; [Test] @@ -348,7 +348,9 @@ namespace osu.Game.Tests.NonVisual.Filtering new object[] { "7d7y" }, new object[] { "0:3:6" }, new object[] { "0:3:" }, - new object[] { "\"three days\"" } + new object[] { "\"three days\"" }, + new object[] { "0.1y0.1M2d" }, + new object[] { "0.99y0.99M2d" } }; [Test] diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 70893c188d..b49f0ba057 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -419,13 +419,17 @@ namespace osu.Game.Screens.Select break; case "months": - dateTimeOffset = dateTimeOffset.AddMonths(-(int)Math.Floor(length)); - dateTimeOffset = dateTimeOffset.AddDays(-30 * (length - Math.Floor(length))); + if (match[key].Value.Contains('.')) + return false; + + dateTimeOffset = dateTimeOffset.AddMonths(-(int)length); break; case "years": - dateTimeOffset = dateTimeOffset.AddYears(-(int)Math.Floor(length)); - dateTimeOffset = dateTimeOffset.AddDays(-365 * (length - Math.Floor(length))); + if (match[key].Value.Contains('.')) + return false; + + dateTimeOffset = dateTimeOffset.AddYears(-(int)length); break; } } From 8e156fdb5102af8cd71aaac32d3c36b3c018d382 Mon Sep 17 00:00:00 2001 From: Elvendir Date: Fri, 7 Apr 2023 00:29:46 +0200 Subject: [PATCH 011/223] Enforce integer through regex match instead --- osu.Game/Screens/Select/FilterQueryParser.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index b49f0ba057..348f663b8e 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -381,7 +381,7 @@ namespace osu.Game.Screens.Select GroupCollection? match = null; - match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)y)?((?\d+(\.\d+)?)M)?((?\d+(\.\d+)?)d)?((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); + match ??= tryMatchRegex(val, @"^((?\d+)y)?((?\d+)M)?((?\d+(\.\d+)?)d)?((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); match ??= tryMatchRegex(val, @"^(?\d+(\.\d+)?)$"); if (match == null) @@ -419,16 +419,10 @@ namespace osu.Game.Screens.Select break; case "months": - if (match[key].Value.Contains('.')) - return false; - dateTimeOffset = dateTimeOffset.AddMonths(-(int)length); break; case "years": - if (match[key].Value.Contains('.')) - return false; - dateTimeOffset = dateTimeOffset.AddYears(-(int)length); break; } From 3b58f6a7e78d8244a6e60bf8b27078c84845fb3c Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:07:12 -0500 Subject: [PATCH 012/223] Implement difficulty statistics --- global.json | 8 +- .../Drawables/DifficultyIconTooltip.cs | 100 +++++++++++++++++- 2 files changed, 103 insertions(+), 5 deletions(-) diff --git a/global.json b/global.json index 5dcd5f425a..7835999220 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { - "version": "6.0.100", - "rollForward": "latestFeature" + "version": "6.0.0", + "rollForward": "latestFeature", + "allowPrerelease": true } -} - +} \ No newline at end of file diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 3fa24bcc3e..7ea2c6a0a2 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -19,6 +20,13 @@ namespace osu.Game.Beatmaps.Drawables { private OsuSpriteText difficultyName; private StarRatingDisplay starRating; + private OsuSpriteText overallDifficulty; + private OsuSpriteText drainRate; + private OsuSpriteText circleSize; + private OsuSpriteText approachRate; + private OsuSpriteText BPM; + private OsuSpriteText maxCombo; + private OsuSpriteText length; [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -35,6 +43,7 @@ namespace osu.Game.Beatmaps.Drawables Colour = colours.Gray3, RelativeSizeAxes = Axes.Both }, + // Headers new FillFlowContainer { AutoSizeAxes = Axes.Both, @@ -55,6 +64,84 @@ namespace osu.Game.Beatmaps.Drawables { Anchor = Anchor.Centre, Origin = Anchor.Centre, + }, + // Difficulty stats + new FillFlowContainer() + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), + }, + overallDifficulty = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 14), + }, + drainRate = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 14), + }, + circleSize = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 14), + }, + approachRate = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 14), + }, + } + }, + // Misc stats + new FillFlowContainer() + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), + }, + length = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 14), + }, + BPM = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 14), + }, + maxCombo = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 14), + }, + } } } } @@ -68,10 +155,21 @@ namespace osu.Game.Beatmaps.Drawables if (displayedContent != null) starRating.Current.UnbindFrom(displayedContent.Difficulty); + // Header row displayedContent = content; - starRating.Current.BindTarget = displayedContent.Difficulty; difficultyName.Text = displayedContent.BeatmapInfo.DifficultyName; + + // Difficulty row + overallDifficulty.Text = "OD: " + displayedContent.BeatmapInfo.Difficulty.OverallDifficulty.ToString("0.##"); + drainRate.Text = "| HP: " + displayedContent.BeatmapInfo.Difficulty.DrainRate.ToString("0.##"); + circleSize.Text = "| CS: " + displayedContent.BeatmapInfo.Difficulty.CircleSize.ToString("0.##"); + approachRate.Text = "| AR: " + displayedContent.BeatmapInfo.Difficulty.ApproachRate.ToString("0.##"); + + // Misc row + length.Text = "Length: " + TimeSpan.FromMilliseconds(displayedContent.BeatmapInfo.Length).ToString("mm\\:ss"); + BPM.Text = "| BPM: " + displayedContent.BeatmapInfo.BPM; + maxCombo.Text = "| Max Combo: " + displayedContent.BeatmapInfo.TotalObjectCount; } public void Move(Vector2 pos) => Position = pos; From 803329c5d8aa3a73ef9a58875adb8255f241a0ec Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Fri, 22 Dec 2023 15:58:41 -0500 Subject: [PATCH 013/223] rollback my accidental global.json change --- global.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/global.json b/global.json index 7835999220..d6c2c37f77 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,6 @@ { "sdk": { - "version": "6.0.0", - "rollForward": "latestFeature", - "allowPrerelease": true + "version": "6.0.100", + "rollForward": "latestFeature" } } \ No newline at end of file From f7c1e66165b5415a3779961f852677fca073c3d5 Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Fri, 22 Dec 2023 17:28:02 -0500 Subject: [PATCH 014/223] Make the difficulty stats change based on the currently applied mods --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 10 ++- .../Drawables/DifficultyIconTooltip.cs | 61 ++++++++++++++----- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 2 +- 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 1665ec52fa..44981003f2 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osuTK; using osuTK.Graphics; @@ -39,6 +40,8 @@ namespace osu.Game.Beatmaps.Drawables private readonly IRulesetInfo ruleset; + private readonly Mod[]? mods; + private Drawable background = null!; private readonly Container iconContainer; @@ -58,11 +61,14 @@ namespace osu.Game.Beatmaps.Drawables /// Creates a new . Will use provided beatmap's for initial value. /// /// The beatmap to be displayed in the tooltip, and to be used for the initial star rating value. + /// The mods type beat /// An optional ruleset to be used for the icon display, in place of the beatmap's ruleset. - public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null) + public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null, Mod[]? mods = null) : this(ruleset ?? beatmap.Ruleset) { this.beatmap = beatmap; + this.mods = mods; + Current.Value = new StarDifficulty(beatmap.StarRating, 0); } @@ -128,6 +134,6 @@ namespace osu.Game.Beatmaps.Drawables GetCustomTooltip() => new DifficultyIconTooltip(); DifficultyIconTooltipContent IHasCustomTooltip. - TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current) : null)!; + TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current, ruleset, mods) : null)!; } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 7ea2c6a0a2..0f5c94ac1d 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -12,6 +13,8 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osuTK; namespace osu.Game.Beatmaps.Drawables @@ -24,7 +27,7 @@ namespace osu.Game.Beatmaps.Drawables private OsuSpriteText drainRate; private OsuSpriteText circleSize; private OsuSpriteText approachRate; - private OsuSpriteText BPM; + private OsuSpriteText bpm; private OsuSpriteText maxCombo; private OsuSpriteText length; @@ -66,7 +69,7 @@ namespace osu.Game.Beatmaps.Drawables Origin = Anchor.Centre, }, // Difficulty stats - new FillFlowContainer() + new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -81,7 +84,7 @@ namespace osu.Game.Beatmaps.Drawables Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), }, - overallDifficulty = new OsuSpriteText + circleSize = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -93,13 +96,13 @@ namespace osu.Game.Beatmaps.Drawables Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 14), }, - circleSize = new OsuSpriteText + approachRate = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 14), }, - approachRate = new OsuSpriteText + overallDifficulty = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -108,7 +111,7 @@ namespace osu.Game.Beatmaps.Drawables } }, // Misc stats - new FillFlowContainer() + new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -129,7 +132,7 @@ namespace osu.Game.Beatmaps.Drawables Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 14), }, - BPM = new OsuSpriteText + bpm = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -155,20 +158,44 @@ namespace osu.Game.Beatmaps.Drawables if (displayedContent != null) starRating.Current.UnbindFrom(displayedContent.Difficulty); - // Header row displayedContent = content; + + // Header row starRating.Current.BindTarget = displayedContent.Difficulty; difficultyName.Text = displayedContent.BeatmapInfo.DifficultyName; + double rate = 1; + + if (displayedContent.Mods != null) + { + foreach (var mod in displayedContent.Mods.OfType()) + rate = mod.ApplyToRate(0, rate); + } + + double bpmAdjusted = displayedContent.BeatmapInfo.BPM * rate; + + BeatmapDifficulty originalDifficulty = new BeatmapDifficulty(displayedContent.BeatmapInfo.Difficulty); + + if (displayedContent.Mods != null) + { + foreach (var mod in displayedContent.Mods.OfType()) + { + mod.ApplyToDifficulty(originalDifficulty); + } + } + + Ruleset ruleset = displayedContent.Ruleset.CreateInstance(); + BeatmapDifficulty adjustedDifficulty = ruleset.GetRateAdjustedDisplayDifficulty(originalDifficulty, rate); + // Difficulty row - overallDifficulty.Text = "OD: " + displayedContent.BeatmapInfo.Difficulty.OverallDifficulty.ToString("0.##"); - drainRate.Text = "| HP: " + displayedContent.BeatmapInfo.Difficulty.DrainRate.ToString("0.##"); - circleSize.Text = "| CS: " + displayedContent.BeatmapInfo.Difficulty.CircleSize.ToString("0.##"); - approachRate.Text = "| AR: " + displayedContent.BeatmapInfo.Difficulty.ApproachRate.ToString("0.##"); + circleSize.Text = "CS: " + adjustedDifficulty.CircleSize.ToString("0.##"); + drainRate.Text = "| HP: " + adjustedDifficulty.DrainRate.ToString("0.##"); + approachRate.Text = "| AR: " + adjustedDifficulty.ApproachRate.ToString("0.##"); + overallDifficulty.Text = "| OD: " + adjustedDifficulty.OverallDifficulty.ToString("0.##"); // Misc row - length.Text = "Length: " + TimeSpan.FromMilliseconds(displayedContent.BeatmapInfo.Length).ToString("mm\\:ss"); - BPM.Text = "| BPM: " + displayedContent.BeatmapInfo.BPM; + length.Text = "Length: " + TimeSpan.FromMilliseconds(displayedContent.BeatmapInfo.Length / rate).ToString("mm\\:ss"); + bpm.Text = "| BPM: " + bpmAdjusted; maxCombo.Text = "| Max Combo: " + displayedContent.BeatmapInfo.TotalObjectCount; } @@ -183,11 +210,15 @@ namespace osu.Game.Beatmaps.Drawables { public readonly IBeatmapInfo BeatmapInfo; public readonly IBindable Difficulty; + public readonly IRulesetInfo Ruleset; + public readonly Mod[] Mods; - public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty) + public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty, IRulesetInfo rulesetInfo, Mod[] mods) { BeatmapInfo = beatmapInfo; Difficulty = difficulty; + Ruleset = rulesetInfo; + Mods = mods; } } } diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 8f405399a7..eb23ed6f8f 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -283,7 +283,7 @@ namespace osu.Game.Screens.OnlinePlay } if (beatmap != null) - difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset) { Size = new Vector2(icon_height) }; + difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset, requiredMods) { Size = new Vector2(icon_height) }; else difficultyIconContainer.Clear(); From d2efa2e56a34a28a2656ca30885046aa33cd06f7 Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Sun, 14 Jan 2024 15:47:50 -0500 Subject: [PATCH 015/223] peppy said he prefers the version without pipes so ill remove the pipes --- osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 0f5c94ac1d..a4ba2a27f6 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -189,14 +189,14 @@ namespace osu.Game.Beatmaps.Drawables // Difficulty row circleSize.Text = "CS: " + adjustedDifficulty.CircleSize.ToString("0.##"); - drainRate.Text = "| HP: " + adjustedDifficulty.DrainRate.ToString("0.##"); - approachRate.Text = "| AR: " + adjustedDifficulty.ApproachRate.ToString("0.##"); - overallDifficulty.Text = "| OD: " + adjustedDifficulty.OverallDifficulty.ToString("0.##"); + drainRate.Text = " HP: " + adjustedDifficulty.DrainRate.ToString("0.##"); + approachRate.Text = " AR: " + adjustedDifficulty.ApproachRate.ToString("0.##"); + overallDifficulty.Text = " OD: " + adjustedDifficulty.OverallDifficulty.ToString("0.##"); // Misc row length.Text = "Length: " + TimeSpan.FromMilliseconds(displayedContent.BeatmapInfo.Length / rate).ToString("mm\\:ss"); - bpm.Text = "| BPM: " + bpmAdjusted; - maxCombo.Text = "| Max Combo: " + displayedContent.BeatmapInfo.TotalObjectCount; + bpm.Text = " BPM: " + bpmAdjusted; + maxCombo.Text = " Max Combo: " + displayedContent.BeatmapInfo.TotalObjectCount; } public void Move(Vector2 pos) => Position = pos; From 0237c9c6d712ee07a9f877b589e80bcf53591045 Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Sun, 14 Jan 2024 15:57:16 -0500 Subject: [PATCH 016/223] peppy said he prefers the version without pipes so ill remove the pipes --- global.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/global.json b/global.json index d6c2c37f77..5dcd5f425a 100644 --- a/global.json +++ b/global.json @@ -3,4 +3,5 @@ "version": "6.0.100", "rollForward": "latestFeature" } -} \ No newline at end of file +} + From b6422bc8bdb88a5b19b41992fb90bec6a966368d Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Wed, 17 Jan 2024 09:07:17 -0500 Subject: [PATCH 017/223] Apply suggested changes - Change difficultyicon mods parameter docstring to be more professional - Add a parameter for controlling whether the difficulty statistics show or not. Defaults to false - Round the BPM in the tooltip to make sure it displays correctly --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 10 ++++-- .../Drawables/DifficultyIconTooltip.cs | 34 ++++++++++--------- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 2 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 44981003f2..9c2a435cb0 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -42,6 +42,8 @@ namespace osu.Game.Beatmaps.Drawables private readonly Mod[]? mods; + private readonly bool showTooltip; + private Drawable background = null!; private readonly Container iconContainer; @@ -61,13 +63,15 @@ namespace osu.Game.Beatmaps.Drawables /// Creates a new . Will use provided beatmap's for initial value. /// /// The beatmap to be displayed in the tooltip, and to be used for the initial star rating value. - /// The mods type beat + /// An array of mods to account for in the calculations /// An optional ruleset to be used for the icon display, in place of the beatmap's ruleset. - public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null, Mod[]? mods = null) + /// Whether to display a tooltip on hover. Defaults to false. + public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null, Mod[]? mods = null, bool showTooltip = false) : this(ruleset ?? beatmap.Ruleset) { this.beatmap = beatmap; this.mods = mods; + this.showTooltip = showTooltip; Current.Value = new StarDifficulty(beatmap.StarRating, 0); } @@ -134,6 +138,6 @@ namespace osu.Game.Beatmaps.Drawables GetCustomTooltip() => new DifficultyIconTooltip(); DifficultyIconTooltipContent IHasCustomTooltip. - TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current, ruleset, mods) : null)!; + TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current, ruleset, mods, showTooltip) : null)!; } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index a4ba2a27f6..c5e276e6b4 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -31,6 +31,9 @@ namespace osu.Game.Beatmaps.Drawables private OsuSpriteText maxCombo; private OsuSpriteText length; + private FillFlowContainer difficultyFillFlowContainer; + private FillFlowContainer miscFillFlowContainer; + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -69,21 +72,16 @@ namespace osu.Game.Beatmaps.Drawables Origin = Anchor.Centre, }, // Difficulty stats - new FillFlowContainer + difficultyFillFlowContainer = new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Alpha = 0, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(5), Children = new Drawable[] { - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), - }, circleSize = new OsuSpriteText { Anchor = Anchor.Centre, @@ -111,21 +109,16 @@ namespace osu.Game.Beatmaps.Drawables } }, // Misc stats - new FillFlowContainer + miscFillFlowContainer = new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Alpha = 0, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(5), Children = new Drawable[] { - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), - }, length = new OsuSpriteText { Anchor = Anchor.Centre, @@ -164,6 +157,13 @@ namespace osu.Game.Beatmaps.Drawables starRating.Current.BindTarget = displayedContent.Difficulty; difficultyName.Text = displayedContent.BeatmapInfo.DifficultyName; + // Don't show difficulty stats if showTooltip is false + if (!displayedContent.ShowTooltip) return; + + // Show the difficulty stats if showTooltip is true + difficultyFillFlowContainer.Show(); + miscFillFlowContainer.Show(); + double rate = 1; if (displayedContent.Mods != null) @@ -195,7 +195,7 @@ namespace osu.Game.Beatmaps.Drawables // Misc row length.Text = "Length: " + TimeSpan.FromMilliseconds(displayedContent.BeatmapInfo.Length / rate).ToString("mm\\:ss"); - bpm.Text = " BPM: " + bpmAdjusted; + bpm.Text = " BPM: " + Math.Round(bpmAdjusted, 0); maxCombo.Text = " Max Combo: " + displayedContent.BeatmapInfo.TotalObjectCount; } @@ -212,13 +212,15 @@ namespace osu.Game.Beatmaps.Drawables public readonly IBindable Difficulty; public readonly IRulesetInfo Ruleset; public readonly Mod[] Mods; + public readonly bool ShowTooltip; - public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty, IRulesetInfo rulesetInfo, Mod[] mods) + public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty, IRulesetInfo rulesetInfo, Mod[] mods, bool showTooltip = false) { BeatmapInfo = beatmapInfo; Difficulty = difficulty; Ruleset = rulesetInfo; Mods = mods; + ShowTooltip = showTooltip; } } } diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index eb23ed6f8f..2a6387871f 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -283,7 +283,7 @@ namespace osu.Game.Screens.OnlinePlay } if (beatmap != null) - difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset, requiredMods) { Size = new Vector2(icon_height) }; + difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset, requiredMods, true) { Size = new Vector2(icon_height) }; else difficultyIconContainer.Clear(); From 9a6541356eb32899ffc54bd1db2a151e3db5b42e Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Wed, 17 Jan 2024 13:31:23 -0500 Subject: [PATCH 018/223] Refactor the extended tooltip variables to be more descriptive --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 10 +++++----- osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 9c2a435cb0..7a9b2fe389 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -42,7 +42,7 @@ namespace osu.Game.Beatmaps.Drawables private readonly Mod[]? mods; - private readonly bool showTooltip; + private readonly bool showExtendedTooltip; private Drawable background = null!; @@ -65,13 +65,13 @@ namespace osu.Game.Beatmaps.Drawables /// The beatmap to be displayed in the tooltip, and to be used for the initial star rating value. /// An array of mods to account for in the calculations /// An optional ruleset to be used for the icon display, in place of the beatmap's ruleset. - /// Whether to display a tooltip on hover. Defaults to false. - public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null, Mod[]? mods = null, bool showTooltip = false) + /// Whether to include the difficulty stats in the tooltip or not. Defaults to false + public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null, Mod[]? mods = null, bool showExtendedTooltip = false) : this(ruleset ?? beatmap.Ruleset) { this.beatmap = beatmap; this.mods = mods; - this.showTooltip = showTooltip; + this.showExtendedTooltip = showExtendedTooltip; Current.Value = new StarDifficulty(beatmap.StarRating, 0); } @@ -138,6 +138,6 @@ namespace osu.Game.Beatmaps.Drawables GetCustomTooltip() => new DifficultyIconTooltip(); DifficultyIconTooltipContent IHasCustomTooltip. - TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current, ruleset, mods, showTooltip) : null)!; + TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current, ruleset, mods, showExtendedTooltip) : null)!; } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index c5e276e6b4..fae4100473 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -157,10 +157,10 @@ namespace osu.Game.Beatmaps.Drawables starRating.Current.BindTarget = displayedContent.Difficulty; difficultyName.Text = displayedContent.BeatmapInfo.DifficultyName; - // Don't show difficulty stats if showTooltip is false - if (!displayedContent.ShowTooltip) return; + // Don't show difficulty stats if showExtendedTooltip is false + if (!displayedContent.ShowExtendedTooltip) return; - // Show the difficulty stats if showTooltip is true + // Show the difficulty stats if showExtendedTooltip is true difficultyFillFlowContainer.Show(); miscFillFlowContainer.Show(); @@ -212,15 +212,15 @@ namespace osu.Game.Beatmaps.Drawables public readonly IBindable Difficulty; public readonly IRulesetInfo Ruleset; public readonly Mod[] Mods; - public readonly bool ShowTooltip; + public readonly bool ShowExtendedTooltip; - public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty, IRulesetInfo rulesetInfo, Mod[] mods, bool showTooltip = false) + public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty, IRulesetInfo rulesetInfo, Mod[] mods, bool showExtendedTooltip = false) { BeatmapInfo = beatmapInfo; Difficulty = difficulty; Ruleset = rulesetInfo; Mods = mods; - ShowTooltip = showTooltip; + ShowExtendedTooltip = showExtendedTooltip; } } } From 060ea1d4fd82899991eae7b9cdd8468c18dc551c Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Wed, 17 Jan 2024 14:04:13 -0500 Subject: [PATCH 019/223] Switch from using a constructor argument to using a public field for ShowExtendedTooltip --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 13 +++++++------ .../Screens/OnlinePlay/DrawableRoomPlaylistItem.cs | 8 +++++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 7a9b2fe389..fc78d6f322 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -36,14 +36,17 @@ namespace osu.Game.Beatmaps.Drawables /// public bool ShowTooltip { get; set; } = true; + /// + /// Whether to include the difficulty stats in the tooltip or not. Defaults to false. Has no effect if is false. + /// + public bool ShowExtendedTooltip { get; set; } + private readonly IBeatmapInfo? beatmap; private readonly IRulesetInfo ruleset; private readonly Mod[]? mods; - private readonly bool showExtendedTooltip; - private Drawable background = null!; private readonly Container iconContainer; @@ -65,13 +68,11 @@ namespace osu.Game.Beatmaps.Drawables /// The beatmap to be displayed in the tooltip, and to be used for the initial star rating value. /// An array of mods to account for in the calculations /// An optional ruleset to be used for the icon display, in place of the beatmap's ruleset. - /// Whether to include the difficulty stats in the tooltip or not. Defaults to false - public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null, Mod[]? mods = null, bool showExtendedTooltip = false) + public DifficultyIcon(IBeatmapInfo beatmap, IRulesetInfo? ruleset = null, Mod[]? mods = null) : this(ruleset ?? beatmap.Ruleset) { this.beatmap = beatmap; this.mods = mods; - this.showExtendedTooltip = showExtendedTooltip; Current.Value = new StarDifficulty(beatmap.StarRating, 0); } @@ -138,6 +139,6 @@ namespace osu.Game.Beatmaps.Drawables GetCustomTooltip() => new DifficultyIconTooltip(); DifficultyIconTooltipContent IHasCustomTooltip. - TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current, ruleset, mods, showExtendedTooltip) : null)!; + TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current, ruleset, mods, ShowExtendedTooltip) : null)!; } } diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 2a6387871f..8cfdc2e0e2 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -283,7 +283,13 @@ namespace osu.Game.Screens.OnlinePlay } if (beatmap != null) - difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset, requiredMods, true) { Size = new Vector2(icon_height) }; + { + difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset, requiredMods) + { + Size = new Vector2(icon_height), + ShowExtendedTooltip = true + }; + } else difficultyIconContainer.Clear(); From d80a5d44eedca57e8be969d771152edb4fe4b229 Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Thu, 18 Jan 2024 03:17:37 -0500 Subject: [PATCH 020/223] Add tests for DifficultyIcon --- .../Beatmaps/TestSceneDifficultyIcon.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs new file mode 100644 index 0000000000..aa2543eea1 --- /dev/null +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs @@ -0,0 +1,42 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Platform; +using osu.Game.Beatmaps.Drawables; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Tests.Visual.Beatmaps +{ + public partial class TestSceneDifficultyIcon : OsuTestScene + { + [Test] + public void createDifficultyIcon() + { + DifficultyIcon difficultyIcon = null; + + AddStep("create difficulty icon", () => + { + Child = difficultyIcon = new DifficultyIcon(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo, new OsuRuleset().RulesetInfo) + { + ShowTooltip = true, + ShowExtendedTooltip = true + }; + }); + + AddStep("hide extended tooltip", () => difficultyIcon.ShowExtendedTooltip = false); + + AddStep("hide tooltip", () => difficultyIcon.ShowTooltip = false); + + AddStep("show tooltip", () => difficultyIcon.ShowTooltip = true); + + AddStep("show extended tooltip", () => difficultyIcon.ShowExtendedTooltip = true); + } + } +} From 5c70c786b4581d91c5b2d069e04b9d774cf79351 Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Thu, 18 Jan 2024 03:18:44 -0500 Subject: [PATCH 021/223] Fix extended tooltip content still being shown despite ShowExtendedTooltip being false --- osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index fae4100473..fe23b49346 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -158,7 +158,12 @@ namespace osu.Game.Beatmaps.Drawables difficultyName.Text = displayedContent.BeatmapInfo.DifficultyName; // Don't show difficulty stats if showExtendedTooltip is false - if (!displayedContent.ShowExtendedTooltip) return; + if (!displayedContent.ShowExtendedTooltip) + { + difficultyFillFlowContainer.Hide(); + miscFillFlowContainer.Hide(); + return; + } // Show the difficulty stats if showExtendedTooltip is true difficultyFillFlowContainer.Show(); From 87369f8a808b29e3da0bde82027a439e763532dc Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Thu, 18 Jan 2024 11:16:03 -0500 Subject: [PATCH 022/223] Conform to code style & remove unused imports --- osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs index aa2543eea1..79f9aec2e3 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs @@ -4,11 +4,7 @@ #nullable disable using NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Platform; using osu.Game.Beatmaps.Drawables; -using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Tests.Beatmaps; @@ -17,7 +13,7 @@ namespace osu.Game.Tests.Visual.Beatmaps public partial class TestSceneDifficultyIcon : OsuTestScene { [Test] - public void createDifficultyIcon() + public void CreateDifficultyIcon() { DifficultyIcon difficultyIcon = null; From f12be60d8d33471fc8acb4ee54c369f4f4e928e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Jan 2024 17:18:22 +0900 Subject: [PATCH 023/223] Make test actually test multiple icons --- .../Beatmaps/TestSceneDifficultyIcon.cs | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs index 79f9aec2e3..80320c138b 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs @@ -4,27 +4,58 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Utils; using osu.Game.Beatmaps.Drawables; using osu.Game.Rulesets.Osu; using osu.Game.Tests.Beatmaps; +using osuTK; namespace osu.Game.Tests.Visual.Beatmaps { public partial class TestSceneDifficultyIcon : OsuTestScene { + private FillFlowContainer fill; + + protected override void LoadComplete() + { + base.LoadComplete(); + + Child = fill = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + Width = 300, + Direction = FillDirection.Full, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + [Test] public void CreateDifficultyIcon() { DifficultyIcon difficultyIcon = null; - AddStep("create difficulty icon", () => + AddRepeatStep("create difficulty icon", () => { - Child = difficultyIcon = new DifficultyIcon(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo, new OsuRuleset().RulesetInfo) + var rulesetInfo = new OsuRuleset().RulesetInfo; + var beatmapInfo = new TestBeatmap(rulesetInfo).BeatmapInfo; + + beatmapInfo.Difficulty.ApproachRate = RNG.Next(0, 10); + beatmapInfo.Difficulty.CircleSize = RNG.Next(0, 10); + beatmapInfo.Difficulty.OverallDifficulty = RNG.Next(0, 10); + beatmapInfo.Difficulty.DrainRate = RNG.Next(0, 10); + beatmapInfo.StarRating = RNG.NextSingle(0, 10); + beatmapInfo.BPM = RNG.Next(60, 300); + + fill.Add(difficultyIcon = new DifficultyIcon(beatmapInfo, rulesetInfo) { + Scale = new Vector2(2), ShowTooltip = true, ShowExtendedTooltip = true - }; - }); + }); + }, 10); AddStep("hide extended tooltip", () => difficultyIcon.ShowExtendedTooltip = false); From 2305a53a02b23185d83a9740ce876350adc711cc Mon Sep 17 00:00:00 2001 From: smallketchup82 <69545310+smallketchup82@users.noreply.github.com> Date: Mon, 22 Jan 2024 08:59:37 -0500 Subject: [PATCH 024/223] Remove max combo reading & remove unnecessary commas --- .../Drawables/DifficultyIconTooltip.cs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index fe23b49346..7fe0080e89 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -28,7 +28,6 @@ namespace osu.Game.Beatmaps.Drawables private OsuSpriteText circleSize; private OsuSpriteText approachRate; private OsuSpriteText bpm; - private OsuSpriteText maxCombo; private OsuSpriteText length; private FillFlowContainer difficultyFillFlowContainer; @@ -64,12 +63,12 @@ namespace osu.Game.Beatmaps.Drawables { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold), + Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold) }, starRating = new StarRatingDisplay(default, StarRatingDisplaySize.Small) { Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Origin = Anchor.Centre }, // Difficulty stats difficultyFillFlowContainer = new FillFlowContainer @@ -86,26 +85,26 @@ namespace osu.Game.Beatmaps.Drawables { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14), + Font = OsuFont.GetFont(size: 14) }, drainRate = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14), + Font = OsuFont.GetFont(size: 14) }, approachRate = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14), + Font = OsuFont.GetFont(size: 14) }, overallDifficulty = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14), - }, + Font = OsuFont.GetFont(size: 14) + } } }, // Misc stats @@ -123,19 +122,13 @@ namespace osu.Game.Beatmaps.Drawables { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14), + Font = OsuFont.GetFont(size: 14) }, bpm = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14), - }, - maxCombo = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14), + Font = OsuFont.GetFont(size: 14) }, } } @@ -201,7 +194,6 @@ namespace osu.Game.Beatmaps.Drawables // Misc row length.Text = "Length: " + TimeSpan.FromMilliseconds(displayedContent.BeatmapInfo.Length / rate).ToString("mm\\:ss"); bpm.Text = " BPM: " + Math.Round(bpmAdjusted, 0); - maxCombo.Text = " Max Combo: " + displayedContent.BeatmapInfo.TotalObjectCount; } public void Move(Vector2 pos) => Position = pos; From 64ba95bbd664964409224a8f589b473af7d6ca1e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Jan 2024 21:11:33 +0900 Subject: [PATCH 025/223] Remove pointless comments --- osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 7fe0080e89..6caaab1508 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -48,7 +48,6 @@ namespace osu.Game.Beatmaps.Drawables Colour = colours.Gray3, RelativeSizeAxes = Axes.Both }, - // Headers new FillFlowContainer { AutoSizeAxes = Axes.Both, @@ -70,7 +69,6 @@ namespace osu.Game.Beatmaps.Drawables Anchor = Anchor.Centre, Origin = Anchor.Centre }, - // Difficulty stats difficultyFillFlowContainer = new FillFlowContainer { Anchor = Anchor.Centre, @@ -107,7 +105,6 @@ namespace osu.Game.Beatmaps.Drawables } } }, - // Misc stats miscFillFlowContainer = new FillFlowContainer { Anchor = Anchor.Centre, @@ -146,11 +143,9 @@ namespace osu.Game.Beatmaps.Drawables displayedContent = content; - // Header row starRating.Current.BindTarget = displayedContent.Difficulty; difficultyName.Text = displayedContent.BeatmapInfo.DifficultyName; - // Don't show difficulty stats if showExtendedTooltip is false if (!displayedContent.ShowExtendedTooltip) { difficultyFillFlowContainer.Hide(); @@ -158,7 +153,6 @@ namespace osu.Game.Beatmaps.Drawables return; } - // Show the difficulty stats if showExtendedTooltip is true difficultyFillFlowContainer.Show(); miscFillFlowContainer.Show(); @@ -185,13 +179,11 @@ namespace osu.Game.Beatmaps.Drawables Ruleset ruleset = displayedContent.Ruleset.CreateInstance(); BeatmapDifficulty adjustedDifficulty = ruleset.GetRateAdjustedDisplayDifficulty(originalDifficulty, rate); - // Difficulty row circleSize.Text = "CS: " + adjustedDifficulty.CircleSize.ToString("0.##"); drainRate.Text = " HP: " + adjustedDifficulty.DrainRate.ToString("0.##"); approachRate.Text = " AR: " + adjustedDifficulty.ApproachRate.ToString("0.##"); overallDifficulty.Text = " OD: " + adjustedDifficulty.OverallDifficulty.ToString("0.##"); - // Misc row length.Text = "Length: " + TimeSpan.FromMilliseconds(displayedContent.BeatmapInfo.Length / rate).ToString("mm\\:ss"); bpm.Text = " BPM: " + Math.Round(bpmAdjusted, 0); } From 3c18efed0530c362ae363c84f5a5321c7e60eb3e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Jan 2024 21:13:25 +0900 Subject: [PATCH 026/223] Remove transparency --- osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 6caaab1508..fa07b150d5 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -44,7 +44,6 @@ namespace osu.Game.Beatmaps.Drawables { new Box { - Alpha = 0.9f, Colour = colours.Gray3, RelativeSizeAxes = Axes.Both }, From aeac0a2a9d83c741b65c81e04ab445061d94324d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Jan 2024 21:16:12 +0900 Subject: [PATCH 027/223] Nullability --- .../Drawables/DifficultyIconTooltip.cs | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index fa07b150d5..803618f15e 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; using osu.Framework.Allocation; @@ -21,17 +19,17 @@ namespace osu.Game.Beatmaps.Drawables { internal partial class DifficultyIconTooltip : VisibilityContainer, ITooltip { - private OsuSpriteText difficultyName; - private StarRatingDisplay starRating; - private OsuSpriteText overallDifficulty; - private OsuSpriteText drainRate; - private OsuSpriteText circleSize; - private OsuSpriteText approachRate; - private OsuSpriteText bpm; - private OsuSpriteText length; + private OsuSpriteText difficultyName = null!; + private StarRatingDisplay starRating = null!; + private OsuSpriteText overallDifficulty = null!; + private OsuSpriteText drainRate = null!; + private OsuSpriteText circleSize = null!; + private OsuSpriteText approachRate = null!; + private OsuSpriteText bpm = null!; + private OsuSpriteText length = null!; - private FillFlowContainer difficultyFillFlowContainer; - private FillFlowContainer miscFillFlowContainer; + private FillFlowContainer difficultyFillFlowContainer = null!; + private FillFlowContainer miscFillFlowContainer = null!; [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -133,7 +131,7 @@ namespace osu.Game.Beatmaps.Drawables }; } - private DifficultyIconTooltipContent displayedContent; + private DifficultyIconTooltipContent? displayedContent; public void SetContent(DifficultyIconTooltipContent content) { @@ -178,12 +176,12 @@ namespace osu.Game.Beatmaps.Drawables Ruleset ruleset = displayedContent.Ruleset.CreateInstance(); BeatmapDifficulty adjustedDifficulty = ruleset.GetRateAdjustedDisplayDifficulty(originalDifficulty, rate); - circleSize.Text = "CS: " + adjustedDifficulty.CircleSize.ToString("0.##"); - drainRate.Text = " HP: " + adjustedDifficulty.DrainRate.ToString("0.##"); - approachRate.Text = " AR: " + adjustedDifficulty.ApproachRate.ToString("0.##"); - overallDifficulty.Text = " OD: " + adjustedDifficulty.OverallDifficulty.ToString("0.##"); + circleSize.Text = @"CS: " + adjustedDifficulty.CircleSize.ToString(@"0.##"); + drainRate.Text = @" HP: " + adjustedDifficulty.DrainRate.ToString(@"0.##"); + approachRate.Text = @" AR: " + adjustedDifficulty.ApproachRate.ToString(@"0.##"); + overallDifficulty.Text = @" OD: " + adjustedDifficulty.OverallDifficulty.ToString(@"0.##"); - length.Text = "Length: " + TimeSpan.FromMilliseconds(displayedContent.BeatmapInfo.Length / rate).ToString("mm\\:ss"); + length.Text = "Length: " + TimeSpan.FromMilliseconds(displayedContent.BeatmapInfo.Length / rate).ToString(@"mm\:ss"); bpm.Text = " BPM: " + Math.Round(bpmAdjusted, 0); } @@ -199,10 +197,10 @@ namespace osu.Game.Beatmaps.Drawables public readonly IBeatmapInfo BeatmapInfo; public readonly IBindable Difficulty; public readonly IRulesetInfo Ruleset; - public readonly Mod[] Mods; + public readonly Mod[]? Mods; public readonly bool ShowExtendedTooltip; - public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty, IRulesetInfo rulesetInfo, Mod[] mods, bool showExtendedTooltip = false) + public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty, IRulesetInfo rulesetInfo, Mod[]? mods, bool showExtendedTooltip = false) { BeatmapInfo = beatmapInfo; Difficulty = difficulty; From 50300adef86222ed1554f512dafe857cf25d2cf3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Jan 2024 21:17:29 +0900 Subject: [PATCH 028/223] Tidy things up --- .../Drawables/DifficultyIconTooltip.cs | 44 +++---------------- 1 file changed, 6 insertions(+), 38 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 803618f15e..71366de654 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -76,30 +76,10 @@ namespace osu.Game.Beatmaps.Drawables Spacing = new Vector2(5), Children = new Drawable[] { - circleSize = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14) - }, - drainRate = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14) - }, - approachRate = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14) - }, - overallDifficulty = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14) - } + circleSize = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, + drainRate = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, + approachRate = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, + overallDifficulty = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) } } }, miscFillFlowContainer = new FillFlowContainer @@ -112,18 +92,8 @@ namespace osu.Game.Beatmaps.Drawables Spacing = new Vector2(5), Children = new Drawable[] { - length = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14) - }, - bpm = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 14) - }, + length = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, + bpm = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, } } } @@ -168,9 +138,7 @@ namespace osu.Game.Beatmaps.Drawables if (displayedContent.Mods != null) { foreach (var mod in displayedContent.Mods.OfType()) - { mod.ApplyToDifficulty(originalDifficulty); - } } Ruleset ruleset = displayedContent.Ruleset.CreateInstance(); From 5d456c8d68fe61fa6fc97f8db235b0c6d429a55d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 29 Jan 2024 04:55:21 +0300 Subject: [PATCH 029/223] Rework drawing of graded circles --- .../Expanded/Accuracy/AccuracyCircle.cs | 87 +++++++++++-------- 1 file changed, 52 insertions(+), 35 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 0aff98df2b..8d32989110 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -169,46 +169,63 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy { new CircularProgress { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.X), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyX } - }, - new CircularProgress - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.S), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyX - virtual_ss_percentage } - }, - new CircularProgress - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.A), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyS } - }, - new CircularProgress - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.B), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyA } - }, - new CircularProgress - { - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.C), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyB } - }, - new CircularProgress - { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.D), InnerRadius = RANK_CIRCLE_RADIUS, Current = { Value = accuracyC } }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.C), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = accuracyB - accuracyC }, + Rotation = (float)accuracyC * 360 + }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.B), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = accuracyA - accuracyB }, + Rotation = (float)accuracyB * 360 + }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.A), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = accuracyS - accuracyA }, + Rotation = (float)accuracyA * 360 + }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.S), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = accuracyX - accuracyS - virtual_ss_percentage }, + Rotation = (float)accuracyS * 360 + }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.X), + InnerRadius = RANK_CIRCLE_RADIUS, + Current = { Value = 1f - (accuracyX - virtual_ss_percentage) }, + Rotation = (float)(accuracyX - virtual_ss_percentage) * 360 + }, new RankNotch((float)accuracyX), new RankNotch((float)(accuracyX - virtual_ss_percentage)), new RankNotch((float)accuracyS), From 32b0e0b7380fcb54219fea66b4f46f2a83ece1e1 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 29 Jan 2024 05:05:18 +0300 Subject: [PATCH 030/223] Remove RankNotch --- .../Expanded/Accuracy/AccuracyCircle.cs | 33 ++++++------- .../Ranking/Expanded/Accuracy/RankNotch.cs | 49 ------------------- 2 files changed, 14 insertions(+), 68 deletions(-) delete mode 100644 osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 8d32989110..7bd586ebb7 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -76,9 +76,9 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy private const double virtual_ss_percentage = 0.01; /// - /// The width of a in terms of accuracy. + /// The width of a solid "notch" in terms of accuracy that appears at the ends of the rank circles to add separation. /// - public const double NOTCH_WIDTH_PERCENTAGE = 1.0 / 360; + public const float NOTCH_WIDTH_PERCENTAGE = 2f / 360; /// /// The easing for the circle filling transforms. @@ -174,7 +174,8 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.D), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyC } + Current = { Value = accuracyC - NOTCH_WIDTH_PERCENTAGE }, + Rotation = NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 }, new CircularProgress { @@ -183,8 +184,8 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.C), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyB - accuracyC }, - Rotation = (float)accuracyC * 360 + Current = { Value = accuracyB - accuracyC - NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)accuracyC * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 }, new CircularProgress { @@ -193,8 +194,8 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.B), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyA - accuracyB }, - Rotation = (float)accuracyB * 360 + Current = { Value = accuracyA - accuracyB - NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)accuracyB * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 }, new CircularProgress { @@ -203,8 +204,8 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.A), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyS - accuracyA }, - Rotation = (float)accuracyA * 360 + Current = { Value = accuracyS - accuracyA - NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)accuracyA * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 }, new CircularProgress { @@ -213,8 +214,8 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.S), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyX - accuracyS - virtual_ss_percentage }, - Rotation = (float)accuracyS * 360 + Current = { Value = accuracyX - accuracyS - virtual_ss_percentage - NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)accuracyS * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 }, new CircularProgress { @@ -223,15 +224,9 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.X), InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = 1f - (accuracyX - virtual_ss_percentage) }, - Rotation = (float)(accuracyX - virtual_ss_percentage) * 360 + Current = { Value = 1f - (accuracyX - virtual_ss_percentage) - NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)(accuracyX - virtual_ss_percentage) * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 }, - new RankNotch((float)accuracyX), - new RankNotch((float)(accuracyX - virtual_ss_percentage)), - new RankNotch((float)accuracyS), - new RankNotch((float)accuracyA), - new RankNotch((float)accuracyB), - new RankNotch((float)accuracyC), new BufferedContainer { Name = "Graded circle mask", diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs deleted file mode 100644 index 244acbe8b1..0000000000 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs +++ /dev/null @@ -1,49 +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.Shapes; -using osu.Game.Graphics; -using osuTK; - -namespace osu.Game.Screens.Ranking.Expanded.Accuracy -{ - /// - /// A solid "notch" of the that appears at the ends of the rank circles to add separation. - /// - public partial class RankNotch : CompositeDrawable - { - private readonly float position; - - public RankNotch(float position) - { - this.position = position; - - RelativeSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load() - { - InternalChild = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Rotation = position * 360f, - Child = new Box - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Y, - Height = AccuracyCircle.RANK_CIRCLE_RADIUS, - Width = (float)AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 360f, - Colour = OsuColour.Gray(0.3f), - EdgeSmoothness = new Vector2(1f) - } - }; - } - } -} From 5783838b07df8420916904ab307f91b23fb8a6ad Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 29 Jan 2024 05:14:24 +0300 Subject: [PATCH 031/223] Move graded circles into a separate class --- .../Expanded/Accuracy/AccuracyCircle.cs | 105 ++-------------- .../Expanded/Accuracy/GradedCircles.cs | 113 ++++++++++++++++++ 2 files changed, 120 insertions(+), 98 deletions(-) create mode 100644 osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 7bd586ebb7..3141810894 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -20,7 +20,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Skinning; -using osuTK; using osuTK.Graphics; namespace osu.Game.Screens.Ranking.Expanded.Accuracy @@ -73,7 +72,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// /// SS is displayed as a 1% region, otherwise it would be invisible. /// - private const double virtual_ss_percentage = 0.01; + public const double VIRTUAL_SS_PERCENTAGE = 0.01; /// /// The width of a solid "notch" in terms of accuracy that appears at the ends of the rank circles to add separation. @@ -88,7 +87,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy private readonly ScoreInfo score; private CircularProgress accuracyCircle; - private CircularProgress innerMask; + private GradedCircles gradedCircles; private Container badges; private RankText rankText; @@ -157,96 +156,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#7CF6FF"), Color4Extensions.FromHex("#BAFFA9")), InnerRadius = accuracy_circle_radius, }, - new BufferedContainer - { - Name = "Graded circles", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.8f), - Padding = new MarginPadding(2), - Children = new Drawable[] - { - new CircularProgress - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.D), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyC - NOTCH_WIDTH_PERCENTAGE }, - Rotation = NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 - }, - new CircularProgress - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.C), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyB - accuracyC - NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)accuracyC * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 - }, - new CircularProgress - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.B), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyA - accuracyB - NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)accuracyB * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 - }, - new CircularProgress - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.A), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyS - accuracyA - NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)accuracyA * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 - }, - new CircularProgress - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.S), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = accuracyX - accuracyS - virtual_ss_percentage - NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)accuracyS * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 - }, - new CircularProgress - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.X), - InnerRadius = RANK_CIRCLE_RADIUS, - Current = { Value = 1f - (accuracyX - virtual_ss_percentage) - NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)(accuracyX - virtual_ss_percentage) * 360 + NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 - }, - new BufferedContainer - { - Name = "Graded circle mask", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(1), - Blending = new BlendingParameters - { - Source = BlendingType.DstColor, - Destination = BlendingType.OneMinusSrcColor, - SourceAlpha = BlendingType.One, - DestinationAlpha = BlendingType.SrcAlpha - }, - Child = innerMask = new CircularProgress - { - RelativeSizeAxes = Axes.Both, - InnerRadius = RANK_CIRCLE_RADIUS - 0.02f, - } - } - } - }, + gradedCircles = new GradedCircles(accuracyC, accuracyB, accuracyA, accuracyS, accuracyX), badges = new Container { Name = "Rank badges", @@ -259,7 +169,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy new RankBadge(accuracyB, Interpolation.Lerp(accuracyB, accuracyA, 0.5), getRank(ScoreRank.B)), // The S and A badges are moved down slightly to prevent collision with the SS badge. new RankBadge(accuracyA, Interpolation.Lerp(accuracyA, accuracyS, 0.25), getRank(ScoreRank.A)), - new RankBadge(accuracyS, Interpolation.Lerp(accuracyS, (accuracyX - virtual_ss_percentage), 0.25), getRank(ScoreRank.S)), + new RankBadge(accuracyS, Interpolation.Lerp(accuracyS, (accuracyX - VIRTUAL_SS_PERCENTAGE), 0.25), getRank(ScoreRank.S)), new RankBadge(accuracyX, accuracyX, getRank(ScoreRank.X)), } }, @@ -301,8 +211,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy }); } - using (BeginDelayedSequence(RANK_CIRCLE_TRANSFORM_DELAY)) - innerMask.FillTo(1f, RANK_CIRCLE_TRANSFORM_DURATION, ACCURACY_TRANSFORM_EASING); + gradedCircles.Transform(); using (BeginDelayedSequence(ACCURACY_TRANSFORM_DELAY)) { @@ -331,7 +240,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy if (score.Rank == ScoreRank.X || score.Rank == ScoreRank.XH) targetAccuracy = 1; else - targetAccuracy = Math.Min(accuracyX - virtual_ss_percentage - NOTCH_WIDTH_PERCENTAGE / 2, targetAccuracy); + targetAccuracy = Math.Min(accuracyX - VIRTUAL_SS_PERCENTAGE - NOTCH_WIDTH_PERCENTAGE / 2, targetAccuracy); // The accuracy circle gauge visually fills up a bit too much. // This wouldn't normally matter but we want it to align properly with the inner graded circle in the above cases. @@ -368,7 +277,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy if (badge.Accuracy > score.Accuracy) continue; - using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, Math.Min(accuracyX - virtual_ss_percentage, badge.Accuracy) / targetAccuracy) * ACCURACY_TRANSFORM_DURATION)) + using (BeginDelayedSequence(inverseEasing(ACCURACY_TRANSFORM_EASING, Math.Min(accuracyX - VIRTUAL_SS_PERCENTAGE, badge.Accuracy) / targetAccuracy) * ACCURACY_TRANSFORM_DURATION)) { badge.Appear(); diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs new file mode 100644 index 0000000000..51c4237528 --- /dev/null +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs @@ -0,0 +1,113 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Scoring; +using osuTK; + +namespace osu.Game.Screens.Ranking.Expanded.Accuracy +{ + public partial class GradedCircles : BufferedContainer + { + private readonly CircularProgress innerMask; + + public GradedCircles(double accuracyC, double accuracyB, double accuracyA, double accuracyS, double accuracyX) + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + RelativeSizeAxes = Axes.Both; + Size = new Vector2(0.8f); + Padding = new MarginPadding(2); + Children = new Drawable[] + { + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.D), + InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, + Current = { Value = accuracyC - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, + Rotation = AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.C), + InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, + Current = { Value = accuracyB - accuracyC - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)accuracyC * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.B), + InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, + Current = { Value = accuracyA - accuracyB - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)accuracyB * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.A), + InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, + Current = { Value = accuracyS - accuracyA - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)accuracyA * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.S), + InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, + Current = { Value = accuracyX - accuracyS - AccuracyCircle.VIRTUAL_SS_PERCENTAGE - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)accuracyS * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + }, + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.ForRank(ScoreRank.X), + InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, + Current = { Value = 1f - (accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE) - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, + Rotation = (float)(accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE) * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + }, + new BufferedContainer + { + Name = "Graded circle mask", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(1), + Blending = new BlendingParameters + { + Source = BlendingType.DstColor, + Destination = BlendingType.OneMinusSrcColor, + SourceAlpha = BlendingType.One, + DestinationAlpha = BlendingType.SrcAlpha + }, + Child = innerMask = new CircularProgress + { + RelativeSizeAxes = Axes.Both, + InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS - 0.02f, + } + } + }; + } + + public void Transform() + { + using (BeginDelayedSequence(AccuracyCircle.RANK_CIRCLE_TRANSFORM_DELAY)) + innerMask.FillTo(1f, AccuracyCircle.RANK_CIRCLE_TRANSFORM_DURATION, AccuracyCircle.ACCURACY_TRANSFORM_EASING); + } + } +} From 9c411ad48d81fa384619a6eb8c49c3e56f760fbc Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 29 Jan 2024 05:19:28 +0300 Subject: [PATCH 032/223] Simplify notch math --- .../Ranking/Expanded/Accuracy/GradedCircles.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs index 51c4237528..5241a4d983 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Colour = OsuColour.ForRank(ScoreRank.D), InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, Current = { Value = accuracyC - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + Rotation = AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 180 }, new CircularProgress { @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Colour = OsuColour.ForRank(ScoreRank.C), InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, Current = { Value = accuracyB - accuracyC - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)accuracyC * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + Rotation = (float)(accuracyC + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 }, new CircularProgress { @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Colour = OsuColour.ForRank(ScoreRank.B), InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, Current = { Value = accuracyA - accuracyB - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)accuracyB * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + Rotation = (float)(accuracyB + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 }, new CircularProgress { @@ -61,7 +61,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Colour = OsuColour.ForRank(ScoreRank.A), InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, Current = { Value = accuracyS - accuracyA - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)accuracyA * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + Rotation = (float)(accuracyA + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 }, new CircularProgress { @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Colour = OsuColour.ForRank(ScoreRank.S), InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, Current = { Value = accuracyX - accuracyS - AccuracyCircle.VIRTUAL_SS_PERCENTAGE - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)accuracyS * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + Rotation = (float)(accuracyS + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 }, new CircularProgress { @@ -81,7 +81,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Colour = OsuColour.ForRank(ScoreRank.X), InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, Current = { Value = 1f - (accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE) - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)(accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE) * 360 + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f * 360 + Rotation = (float)(accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 }, new BufferedContainer { From 809ca81b9ccba45aa1ea29fe4645805b8e32e2e7 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 29 Jan 2024 05:29:29 +0300 Subject: [PATCH 033/223] Add TestSceneGradedCircles --- .../Visual/Ranking/TestSceneGradedCircles.cs | 44 +++++++++++++++++++ .../Expanded/Accuracy/GradedCircles.cs | 6 +++ 2 files changed, 50 insertions(+) create mode 100644 osu.Game.Tests/Visual/Ranking/TestSceneGradedCircles.cs diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneGradedCircles.cs b/osu.Game.Tests/Visual/Ranking/TestSceneGradedCircles.cs new file mode 100644 index 0000000000..87fbca5c44 --- /dev/null +++ b/osu.Game.Tests/Visual/Ranking/TestSceneGradedCircles.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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Screens.Ranking.Expanded.Accuracy; +using osuTK; + +namespace osu.Game.Tests.Visual.Ranking +{ + public partial class TestSceneGradedCircles : OsuTestScene + { + private readonly GradedCircles ring; + + public TestSceneGradedCircles() + { + ScoreProcessor scoreProcessor = new OsuRuleset().CreateScoreProcessor(); + double accuracyX = scoreProcessor.AccuracyCutoffFromRank(ScoreRank.X); + double accuracyS = scoreProcessor.AccuracyCutoffFromRank(ScoreRank.S); + + double accuracyA = scoreProcessor.AccuracyCutoffFromRank(ScoreRank.A); + double accuracyB = scoreProcessor.AccuracyCutoffFromRank(ScoreRank.B); + double accuracyC = scoreProcessor.AccuracyCutoffFromRank(ScoreRank.C); + + Add(new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(400), + Child = ring = new GradedCircles(accuracyC, accuracyB, accuracyA, accuracyS, accuracyX) + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AddSliderStep("Progress", 0.0, 1.0, 1.0, p => ring.Progress = p); + } + } +} diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs index 5241a4d983..2ce8c511e0 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs @@ -12,6 +12,12 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy { public partial class GradedCircles : BufferedContainer { + public double Progress + { + get => innerMask.Current.Value; + set => innerMask.Current.Value = value; + } + private readonly CircularProgress innerMask; public GradedCircles(double accuracyC, double accuracyB, double accuracyA, double accuracyS, double accuracyX) From 3987faa21cc80c39b42f465d1ef3f3046e235843 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 29 Jan 2024 06:13:52 +0300 Subject: [PATCH 034/223] Rework GradedCircles to not use BufferedContainer --- .../Expanded/Accuracy/AccuracyCircle.cs | 5 +- .../Expanded/Accuracy/GradedCircles.cs | 118 ++++++++---------- 2 files changed, 52 insertions(+), 71 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 3141810894..5b929554ff 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// /// The width of a solid "notch" in terms of accuracy that appears at the ends of the rank circles to add separation. /// - public const float NOTCH_WIDTH_PERCENTAGE = 2f / 360; + public const double NOTCH_WIDTH_PERCENTAGE = 2.0 / 360; /// /// The easing for the circle filling transforms. @@ -211,7 +211,8 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy }); } - gradedCircles.Transform(); + using (BeginDelayedSequence(RANK_CIRCLE_TRANSFORM_DELAY)) + gradedCircles.TransformTo(nameof(GradedCircles.Progress), 1.0, RANK_CIRCLE_TRANSFORM_DURATION, ACCURACY_TRANSFORM_EASING); using (BeginDelayedSequence(ACCURACY_TRANSFORM_DELAY)) { diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs index 2ce8c511e0..19c7a9b606 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; @@ -10,15 +11,31 @@ using osuTK; namespace osu.Game.Screens.Ranking.Expanded.Accuracy { - public partial class GradedCircles : BufferedContainer + public partial class GradedCircles : CompositeDrawable { + private double progress; + public double Progress { - get => innerMask.Current.Value; - set => innerMask.Current.Value = value; + get => progress; + set + { + progress = value; + dProgress.RevealProgress = value; + cProgress.RevealProgress = value; + bProgress.RevealProgress = value; + aProgress.RevealProgress = value; + sProgress.RevealProgress = value; + xProgress.RevealProgress = value; + } } - private readonly CircularProgress innerMask; + private readonly GradedCircle dProgress; + private readonly GradedCircle cProgress; + private readonly GradedCircle bProgress; + private readonly GradedCircle aProgress; + private readonly GradedCircle sProgress; + private readonly GradedCircle xProgress; public GradedCircles(double accuracyC, double accuracyB, double accuracyA, double accuracyS, double accuracyX) { @@ -27,93 +44,56 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy RelativeSizeAxes = Axes.Both; Size = new Vector2(0.8f); Padding = new MarginPadding(2); - Children = new Drawable[] + InternalChildren = new Drawable[] { - new CircularProgress + dProgress = new GradedCircle(0.0, accuracyC) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.D), - InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, - Current = { Value = accuracyC - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 180 }, - new CircularProgress + cProgress = new GradedCircle(accuracyC, accuracyB) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.C), - InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, - Current = { Value = accuracyB - accuracyC - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)(accuracyC + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 }, - new CircularProgress + bProgress = new GradedCircle(accuracyB, accuracyA) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.B), - InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, - Current = { Value = accuracyA - accuracyB - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)(accuracyB + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 }, - new CircularProgress + aProgress = new GradedCircle(accuracyA, accuracyS) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.A), - InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, - Current = { Value = accuracyS - accuracyA - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)(accuracyA + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 }, - new CircularProgress + sProgress = new GradedCircle(accuracyS, accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.S), - InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, - Current = { Value = accuracyX - accuracyS - AccuracyCircle.VIRTUAL_SS_PERCENTAGE - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)(accuracyS + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 }, - new CircularProgress + xProgress = new GradedCircle(accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE, 1.0) { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = OsuColour.ForRank(ScoreRank.X), - InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS, - Current = { Value = 1f - (accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE) - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE }, - Rotation = (float)(accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5f) * 360 - }, - new BufferedContainer - { - Name = "Graded circle mask", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(1), - Blending = new BlendingParameters - { - Source = BlendingType.DstColor, - Destination = BlendingType.OneMinusSrcColor, - SourceAlpha = BlendingType.One, - DestinationAlpha = BlendingType.SrcAlpha - }, - Child = innerMask = new CircularProgress - { - RelativeSizeAxes = Axes.Both, - InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS - 0.02f, - } + Colour = OsuColour.ForRank(ScoreRank.X) } }; } - public void Transform() + private partial class GradedCircle : CircularProgress { - using (BeginDelayedSequence(AccuracyCircle.RANK_CIRCLE_TRANSFORM_DELAY)) - innerMask.FillTo(1f, AccuracyCircle.RANK_CIRCLE_TRANSFORM_DURATION, AccuracyCircle.ACCURACY_TRANSFORM_EASING); + public double RevealProgress + { + set => Current.Value = Math.Clamp(value, startProgress, endProgress) - startProgress; + } + + private readonly double startProgress; + private readonly double endProgress; + + public GradedCircle(double startProgress, double endProgress) + { + this.startProgress = startProgress + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5; + this.endProgress = endProgress - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + RelativeSizeAxes = Axes.Both; + InnerRadius = AccuracyCircle.RANK_CIRCLE_RADIUS; + Rotation = (float)this.startProgress * 360; + } } } } From 0c0ba7abefe04e16f3d153964f7fe8f139ba2373 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 29 Jan 2024 06:28:38 +0300 Subject: [PATCH 035/223] Adjust values to visually match previous --- osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs | 2 +- osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 5b929554ff..8304e7a542 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// /// Relative width of the rank circles. /// - public const float RANK_CIRCLE_RADIUS = 0.06f; + public const float RANK_CIRCLE_RADIUS = 0.05f; /// /// Relative width of the circle showing the accuracy. diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs index 19c7a9b606..efcb848530 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Origin = Anchor.Centre; RelativeSizeAxes = Axes.Both; Size = new Vector2(0.8f); - Padding = new MarginPadding(2); + Padding = new MarginPadding(2.5f); InternalChildren = new Drawable[] { dProgress = new GradedCircle(0.0, accuracyC) From 7165511754ad437f035e87fdd96323d3c75e7a67 Mon Sep 17 00:00:00 2001 From: syscats Date: Wed, 31 Jan 2024 15:49:31 +0100 Subject: [PATCH 036/223] Use ordinal sorting for artist string comparison --- osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 6d2e938fb7..857f7efb8e 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Select.Carousel { default: case SortMode.Artist: - comparison = string.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist, StringComparison.OrdinalIgnoreCase); + comparison = string.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist, StringComparison.Ordinal); break; case SortMode.Title: From 0407b5d84ac0bc2d872ffc3bb173f622900ffd45 Mon Sep 17 00:00:00 2001 From: syscats Date: Thu, 1 Feb 2024 14:03:59 +0100 Subject: [PATCH 037/223] use ordinal sorting on each method --- osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 857f7efb8e..f7b715862a 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -71,15 +71,15 @@ namespace osu.Game.Screens.Select.Carousel break; case SortMode.Title: - comparison = string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.OrdinalIgnoreCase); + comparison = string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.Ordinal); break; case SortMode.Author: - comparison = string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.OrdinalIgnoreCase); + comparison = string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.Ordinal); break; case SortMode.Source: - comparison = string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.OrdinalIgnoreCase); + comparison = string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.Ordinal); break; case SortMode.DateAdded: From dfd966e039e49a3582b519146440b866ae00705c Mon Sep 17 00:00:00 2001 From: Mike Will Date: Wed, 31 Jan 2024 18:47:47 -0500 Subject: [PATCH 038/223] Improve silence detection in `MutedNotification` Instead of checking the master and music volumes separately to see if they're <= 1%, check the aggregate of the two volumes to see if it's <= -60 dB. When muted notification is activated, restore the aggregate volume level to -30 dB. --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 16 +++++++++---- osu.Game/Screens/Play/PlayerLoader.cs | 23 +++++++++++++------ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index f97372e9b6..2798d77373 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -264,15 +264,23 @@ namespace osu.Game.Tests.Visual.Gameplay } [Test] - public void TestMutedNotificationMasterVolume() + public void TestMutedNotificationHighMasterVolume() { - addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, () => audioManager.Volume.Value == 0.5); + addVolumeSteps("high master volume", () => + { + audioManager.Volume.Value = 0.1; + audioManager.VolumeTrack.Value = 0.01; + }, () => audioManager.Volume.Value == 0.1 && audioManager.VolumeTrack.Value == 0.32); } [Test] - public void TestMutedNotificationTrackVolume() + public void TestMutedNotificationLowMasterVolume() { - addVolumeSteps("music volume", () => audioManager.VolumeTrack.Value = 0, () => audioManager.VolumeTrack.Value == 0.5); + addVolumeSteps("low master volume", () => + { + audioManager.Volume.Value = 0.01; + audioManager.VolumeTrack.Value = 0.1; + }, () => audioManager.Volume.Value == 0.03 && audioManager.VolumeTrack.Value == 1); } [Test] diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 232de53ac3..6282041f2c 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -544,14 +544,14 @@ namespace osu.Game.Screens.Play private int restartCount; - private const double volume_requirement = 0.01; + private const double volume_requirement = 1e-3; // -60 dB private void showMuteWarningIfNeeded() { if (!muteWarningShownOnce.Value) { // Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value <= volume_requirement || audioManager.VolumeTrack.Value <= volume_requirement) + if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value * audioManager.VolumeTrack.Value <= volume_requirement) { notificationOverlay?.Post(new MutedNotification()); muteWarningShownOnce.Value = true; @@ -581,11 +581,20 @@ namespace osu.Game.Screens.Play volumeOverlay.IsMuted.Value = false; // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. - // Note that we only restore halfway to ensure the user isn't suddenly overloaded by unexpectedly high volume. - if (audioManager.Volume.Value <= volume_requirement) - audioManager.Volume.Value = 0.5f; - if (audioManager.VolumeTrack.Value <= volume_requirement) - audioManager.VolumeTrack.Value = 0.5f; + // Note that we only restore to -30 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. + if (audioManager.Volume.Value * audioManager.VolumeTrack.Value <= volume_requirement) + { + // Prioritize increasing music over master volume as to avoid also increasing effects volume. + const double target = 0.031622776601684; // 10 ^ (-30 / 20) + double result = target / Math.Max(0.01, audioManager.Volume.Value); + if (result > 1) + { + audioManager.Volume.Value = target; + audioManager.VolumeTrack.Value = 1; + } + else + audioManager.VolumeTrack.Value = result; + } return true; }; From 3122211268346b9c57e3ea8b96e77090251f06e5 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 2 Feb 2024 02:12:46 -0500 Subject: [PATCH 039/223] Change silence threshold and target restore volume level --- osu.Game/Screens/Play/PlayerLoader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 6282041f2c..9ec7197429 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -544,7 +544,7 @@ namespace osu.Game.Screens.Play private int restartCount; - private const double volume_requirement = 1e-3; // -60 dB + private const double volume_requirement = 0.01; private void showMuteWarningIfNeeded() { @@ -581,11 +581,11 @@ namespace osu.Game.Screens.Play volumeOverlay.IsMuted.Value = false; // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. - // Note that we only restore to -30 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. + // Note that we only restore to -20 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. if (audioManager.Volume.Value * audioManager.VolumeTrack.Value <= volume_requirement) { // Prioritize increasing music over master volume as to avoid also increasing effects volume. - const double target = 0.031622776601684; // 10 ^ (-30 / 20) + const double target = 0.1; double result = target / Math.Max(0.01, audioManager.Volume.Value); if (result > 1) { From f4a2d5f3f489c1332f7e200747dd9b665337db7a Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 2 Feb 2024 02:41:58 -0500 Subject: [PATCH 040/223] Round off inaccuracies in the aggregate volume before evaluating --- osu.Game/Screens/Play/PlayerLoader.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 9ec7197429..50c95ce525 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -551,7 +551,8 @@ namespace osu.Game.Screens.Play if (!muteWarningShownOnce.Value) { // Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value * audioManager.VolumeTrack.Value <= volume_requirement) + double aggregate = Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 100) / 100; + if (volumeOverlay?.IsMuted.Value == true || aggregate <= volume_requirement) { notificationOverlay?.Post(new MutedNotification()); muteWarningShownOnce.Value = true; @@ -582,7 +583,8 @@ namespace osu.Game.Screens.Play // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. // Note that we only restore to -20 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. - if (audioManager.Volume.Value * audioManager.VolumeTrack.Value <= volume_requirement) + double aggregate = Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 100) / 100; + if (aggregate <= volume_requirement) { // Prioritize increasing music over master volume as to avoid also increasing effects volume. const double target = 0.1; From 5d9200b4fe02c4ed0f287fe0f43c5f2433b52ec9 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 2 Feb 2024 02:59:02 -0500 Subject: [PATCH 041/223] Update tests to reflect new restore target volume --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 2798d77373..99bb006071 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -268,9 +268,9 @@ namespace osu.Game.Tests.Visual.Gameplay { addVolumeSteps("high master volume", () => { - audioManager.Volume.Value = 0.1; + audioManager.Volume.Value = 0.15; audioManager.VolumeTrack.Value = 0.01; - }, () => audioManager.Volume.Value == 0.1 && audioManager.VolumeTrack.Value == 0.32); + }, () => audioManager.Volume.Value == 0.15 && audioManager.VolumeTrack.Value == 0.67); } [Test] @@ -279,8 +279,8 @@ namespace osu.Game.Tests.Visual.Gameplay addVolumeSteps("low master volume", () => { audioManager.Volume.Value = 0.01; - audioManager.VolumeTrack.Value = 0.1; - }, () => audioManager.Volume.Value == 0.03 && audioManager.VolumeTrack.Value == 1); + audioManager.VolumeTrack.Value = 0.15; + }, () => audioManager.Volume.Value == 0.1 && audioManager.VolumeTrack.Value == 1); } [Test] From c60e110976ca7214c200d90da45bdd165cb0b39c Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 2 Feb 2024 03:09:19 -0500 Subject: [PATCH 042/223] Try to fix code quality issues raised by workflow --- osu.Game/Screens/Play/PlayerLoader.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 50c95ce525..1d0ecfc12d 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -551,8 +551,7 @@ namespace osu.Game.Screens.Play if (!muteWarningShownOnce.Value) { // Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - double aggregate = Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 100) / 100; - if (volumeOverlay?.IsMuted.Value == true || aggregate <= volume_requirement) + if (volumeOverlay?.IsMuted.Value == true || Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 100) / 100 <= volume_requirement) { notificationOverlay?.Post(new MutedNotification()); muteWarningShownOnce.Value = true; @@ -583,11 +582,11 @@ namespace osu.Game.Screens.Play // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. // Note that we only restore to -20 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. - double aggregate = Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 100) / 100; - if (aggregate <= volume_requirement) + if (Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 100) / 100 <= volume_requirement) { - // Prioritize increasing music over master volume as to avoid also increasing effects volume. const double target = 0.1; + + // Prioritize increasing music over master volume as to avoid also increasing effects volume. double result = target / Math.Max(0.01, audioManager.Volume.Value); if (result > 1) { From 29a28905820bb1242cda326a2e4610e058bef1c2 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 2 Feb 2024 03:46:05 -0500 Subject: [PATCH 043/223] fix code quality error #2 --- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 1d0ecfc12d..40ffa844da 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -584,10 +584,10 @@ namespace osu.Game.Screens.Play // Note that we only restore to -20 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. if (Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 100) / 100 <= volume_requirement) { - const double target = 0.1; - // Prioritize increasing music over master volume as to avoid also increasing effects volume. + const double target = 0.1; double result = target / Math.Max(0.01, audioManager.Volume.Value); + if (result > 1) { audioManager.Volume.Value = target; From 906560f66d971778ab8ec00866b3aa3d0afb8caa Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 2 Feb 2024 04:06:22 -0500 Subject: [PATCH 044/223] Fix mute button test Lowering the master volume in the previous test meant that the volume levels would end up being modified. --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 99bb006071..04b681989f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -289,9 +289,10 @@ namespace osu.Game.Tests.Visual.Gameplay addVolumeSteps("mute button", () => { // Importantly, in the case the volume is muted but the user has a volume level set, it should be retained. + audioManager.Volume.Value = 0.5f; audioManager.VolumeTrack.Value = 0.5f; volumeOverlay.IsMuted.Value = true; - }, () => !volumeOverlay.IsMuted.Value && audioManager.VolumeTrack.Value == 0.5f); + }, () => !volumeOverlay.IsMuted.Value && audioManager.Volume.Value == 0.5f && audioManager.VolumeTrack.Value == 0.5f); } /// From e4ec8c111b90542c8705e73eaabca6bf9557f63f Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 2 Feb 2024 05:48:57 -0500 Subject: [PATCH 045/223] give better volume names to `addVolumeSteps` --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 04b681989f..67e94a2960 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -266,7 +266,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestMutedNotificationHighMasterVolume() { - addVolumeSteps("high master volume", () => + addVolumeSteps("master and music volumes", () => { audioManager.Volume.Value = 0.15; audioManager.VolumeTrack.Value = 0.01; @@ -276,7 +276,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestMutedNotificationLowMasterVolume() { - addVolumeSteps("low master volume", () => + addVolumeSteps("master and music volumes", () => { audioManager.Volume.Value = 0.01; audioManager.VolumeTrack.Value = 0.15; From 20504c55ef02b83ea9c575d3b435148a4eff8931 Mon Sep 17 00:00:00 2001 From: Loreos7 Date: Fri, 2 Feb 2024 15:32:55 +0300 Subject: [PATCH 046/223] localise storage error popup dialog --- .../Localisation/StorageErrorDialogStrings.cs | 49 +++++++++++++++++++ osu.Game/Screens/Menu/StorageErrorDialog.cs | 17 ++++--- 2 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Localisation/StorageErrorDialogStrings.cs diff --git a/osu.Game/Localisation/StorageErrorDialogStrings.cs b/osu.Game/Localisation/StorageErrorDialogStrings.cs new file mode 100644 index 0000000000..6ad388dd1f --- /dev/null +++ b/osu.Game/Localisation/StorageErrorDialogStrings.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.Localisation; + +namespace osu.Game.Localisation +{ + public static class StorageErrorDialogStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.StorageErrorDialog"; + + /// + /// "osu! storage error" + /// + public static LocalisableString StorageError => new TranslatableString(getKey(@"storage_error"), @"osu! storage error"); + + /// + /// "The specified osu! data location ("{0}") is not accessible. If it is on external storage, please reconnect the device and try again." + /// + public static LocalisableString LocationIsNotAccessible(string? loc) => new TranslatableString(getKey(@"location_is_not_accessible"), @"The specified osu! data location (""{0}"") is not accessible. If it is on external storage, please reconnect the device and try again.", loc); + + /// + /// "The specified osu! data location ("{0}") is empty. If you have moved the files, please close osu! and move them back." + /// + public static LocalisableString LocationIsEmpty(string? loc2) => new TranslatableString(getKey(@"location_is_empty"), @"The specified osu! data location (""{0}"") is empty. If you have moved the files, please close osu! and move them back.", loc2); + + /// + /// "Try again" + /// + public static LocalisableString TryAgain => new TranslatableString(getKey(@"try_again"), @"Try again"); + + /// + /// "Use default location until restart" + /// + public static LocalisableString UseDefaultLocation => new TranslatableString(getKey(@"use_default_location"), @"Use default location until restart"); + + /// + /// "Reset to default location" + /// + public static LocalisableString ResetToDefaultLocation => new TranslatableString(getKey(@"reset_to_default_location"), @"Reset to default location"); + + /// + /// "Start fresh at specified location" + /// + public static LocalisableString StartFresh => new TranslatableString(getKey(@"start_fresh"), @"Start fresh at specified location"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Screens/Menu/StorageErrorDialog.cs b/osu.Game/Screens/Menu/StorageErrorDialog.cs index dd43289873..b48046d190 100644 --- a/osu.Game/Screens/Menu/StorageErrorDialog.cs +++ b/osu.Game/Screens/Menu/StorageErrorDialog.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Game.IO; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; @@ -17,7 +18,7 @@ namespace osu.Game.Screens.Menu public StorageErrorDialog(OsuStorage storage, OsuStorageError error) { - HeaderText = "osu! storage error"; + HeaderText = StorageErrorDialogStrings.StorageError; Icon = FontAwesome.Solid.ExclamationTriangle; var buttons = new List(); @@ -25,13 +26,13 @@ namespace osu.Game.Screens.Menu switch (error) { case OsuStorageError.NotAccessible: - BodyText = $"The specified osu! data location (\"{storage.CustomStoragePath}\") is not accessible. If it is on external storage, please reconnect the device and try again."; + BodyText = StorageErrorDialogStrings.LocationIsNotAccessible(storage.CustomStoragePath); buttons.AddRange(new PopupDialogButton[] { new PopupDialogCancelButton { - Text = "Try again", + Text = StorageErrorDialogStrings.TryAgain, Action = () => { if (!storage.TryChangeToCustomStorage(out var nextError)) @@ -40,29 +41,29 @@ namespace osu.Game.Screens.Menu }, new PopupDialogCancelButton { - Text = "Use default location until restart", + Text = StorageErrorDialogStrings.UseDefaultLocation, }, new PopupDialogOkButton { - Text = "Reset to default location", + Text = StorageErrorDialogStrings.ResetToDefaultLocation, Action = storage.ResetCustomStoragePath }, }); break; case OsuStorageError.AccessibleButEmpty: - BodyText = $"The specified osu! data location (\"{storage.CustomStoragePath}\") is empty. If you have moved the files, please close osu! and move them back."; + BodyText = StorageErrorDialogStrings.LocationIsEmpty(storage.CustomStoragePath); // Todo: Provide the option to search for the files similar to migration. buttons.AddRange(new PopupDialogButton[] { new PopupDialogCancelButton { - Text = "Start fresh at specified location" + Text = StorageErrorDialogStrings.StartFresh }, new PopupDialogOkButton { - Text = "Reset to default location", + Text = StorageErrorDialogStrings.ResetToDefaultLocation, Action = storage.ResetCustomStoragePath }, }); From 2ab967f783fd25d95e9142bffb79eb78e03e7cbc Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 2 Feb 2024 13:27:26 -0500 Subject: [PATCH 047/223] Increase precision of aggregate volume rounding It should be large enough to account for true accuracy but small enough to disregard any hair-thin inaccuracy found at the very end of the float value. --- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 40ffa844da..aafa93c122 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -551,7 +551,7 @@ namespace osu.Game.Screens.Play if (!muteWarningShownOnce.Value) { // Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - if (volumeOverlay?.IsMuted.Value == true || Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 100) / 100 <= volume_requirement) + if (volumeOverlay?.IsMuted.Value == true || Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 1e6) / 1e6 <= volume_requirement) { notificationOverlay?.Post(new MutedNotification()); muteWarningShownOnce.Value = true; @@ -582,7 +582,7 @@ namespace osu.Game.Screens.Play // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. // Note that we only restore to -20 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. - if (Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 100) / 100 <= volume_requirement) + if (Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 1e6) / 1e6 <= volume_requirement) { // Prioritize increasing music over master volume as to avoid also increasing effects volume. const double target = 0.1; From 9a5348598af58008e0c22897964f81bf27d34ee0 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 2 Feb 2024 14:22:24 -0500 Subject: [PATCH 048/223] Replace aggregate rounding method with a float cast --- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index aafa93c122..6154e443ef 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -551,7 +551,7 @@ namespace osu.Game.Screens.Play if (!muteWarningShownOnce.Value) { // Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - if (volumeOverlay?.IsMuted.Value == true || Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 1e6) / 1e6 <= volume_requirement) + if (volumeOverlay?.IsMuted.Value == true || (float)(audioManager.Volume.Value * audioManager.VolumeTrack.Value) <= volume_requirement) { notificationOverlay?.Post(new MutedNotification()); muteWarningShownOnce.Value = true; @@ -582,7 +582,7 @@ namespace osu.Game.Screens.Play // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. // Note that we only restore to -20 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. - if (Math.Floor(audioManager.Volume.Value * audioManager.VolumeTrack.Value * 1e6) / 1e6 <= volume_requirement) + if ((float)(audioManager.Volume.Value * audioManager.VolumeTrack.Value) <= volume_requirement) { // Prioritize increasing music over master volume as to avoid also increasing effects volume. const double target = 0.1; From 397def9ceb543ca7e6d0ada77bfde9558dae286d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 4 Feb 2024 02:58:15 +0300 Subject: [PATCH 049/223] Move layout specification outside the GradedCircles class --- .../Visual/Ranking/TestSceneGradedCircles.cs | 6 ++---- .../Ranking/Expanded/Accuracy/AccuracyCircle.cs | 14 +++++++++++++- .../Ranking/Expanded/Accuracy/GradedCircles.cs | 6 ------ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneGradedCircles.cs b/osu.Game.Tests/Visual/Ranking/TestSceneGradedCircles.cs index 87fbca5c44..116386b4b5 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneGradedCircles.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneGradedCircles.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; @@ -25,12 +24,11 @@ namespace osu.Game.Tests.Visual.Ranking double accuracyB = scoreProcessor.AccuracyCutoffFromRank(ScoreRank.B); double accuracyC = scoreProcessor.AccuracyCutoffFromRank(ScoreRank.C); - Add(new Container + Add(ring = new GradedCircles(accuracyC, accuracyB, accuracyA, accuracyS, accuracyX) { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(400), - Child = ring = new GradedCircles(accuracyC, accuracyB, accuracyA, accuracyS, accuracyX) + Size = new Vector2(400) }); } diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 8304e7a542..8dc1a48f40 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -20,6 +20,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Skinning; +using osuTK; using osuTK.Graphics; namespace osu.Game.Screens.Ranking.Expanded.Accuracy @@ -156,7 +157,18 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("#7CF6FF"), Color4Extensions.FromHex("#BAFFA9")), InnerRadius = accuracy_circle_radius, }, - gradedCircles = new GradedCircles(accuracyC, accuracyB, accuracyA, accuracyS, accuracyX), + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.8f), + Padding = new MarginPadding(2.5f), + Child = gradedCircles = new GradedCircles(accuracyC, accuracyB, accuracyA, accuracyS, accuracyX) + { + RelativeSizeAxes = Axes.Both + } + }, badges = new Container { Name = "Rank badges", diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs index efcb848530..e60a24a310 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Scoring; -using osuTK; namespace osu.Game.Screens.Ranking.Expanded.Accuracy { @@ -39,11 +38,6 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy public GradedCircles(double accuracyC, double accuracyB, double accuracyA, double accuracyS, double accuracyX) { - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - RelativeSizeAxes = Axes.Both; - Size = new Vector2(0.8f); - Padding = new MarginPadding(2.5f); InternalChildren = new Drawable[] { dProgress = new GradedCircle(0.0, accuracyC) From 4e5c9ddbfe6afad4713e9705cf4b28cd32cfd764 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 4 Feb 2024 03:02:39 +0300 Subject: [PATCH 050/223] Rename notch const to spacing --- .../Ranking/Expanded/Accuracy/AccuracyCircle.cs | 12 ++++++------ .../Ranking/Expanded/Accuracy/GradedCircles.cs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 8dc1a48f40..7edfc00760 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -76,9 +76,9 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy public const double VIRTUAL_SS_PERCENTAGE = 0.01; /// - /// The width of a solid "notch" in terms of accuracy that appears at the ends of the rank circles to add separation. + /// The width of spacing in terms of accuracy between the grade circles. /// - public const double NOTCH_WIDTH_PERCENTAGE = 2.0 / 360; + public const double GRADE_SPACING_PERCENTAGE = 2.0 / 360; /// /// The easing for the circle filling transforms. @@ -241,10 +241,10 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy // to prevent ambiguity on what grade it's pointing at. foreach (double p in notchPercentages) { - if (Precision.AlmostEquals(p, targetAccuracy, NOTCH_WIDTH_PERCENTAGE / 2)) + if (Precision.AlmostEquals(p, targetAccuracy, GRADE_SPACING_PERCENTAGE / 2)) { int tippingDirection = targetAccuracy - p >= 0 ? 1 : -1; // We "round up" here to match rank criteria - targetAccuracy = p + tippingDirection * (NOTCH_WIDTH_PERCENTAGE / 2); + targetAccuracy = p + tippingDirection * (GRADE_SPACING_PERCENTAGE / 2); break; } } @@ -253,7 +253,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy if (score.Rank == ScoreRank.X || score.Rank == ScoreRank.XH) targetAccuracy = 1; else - targetAccuracy = Math.Min(accuracyX - VIRTUAL_SS_PERCENTAGE - NOTCH_WIDTH_PERCENTAGE / 2, targetAccuracy); + targetAccuracy = Math.Min(accuracyX - VIRTUAL_SS_PERCENTAGE - GRADE_SPACING_PERCENTAGE / 2, targetAccuracy); // The accuracy circle gauge visually fills up a bit too much. // This wouldn't normally matter but we want it to align properly with the inner graded circle in the above cases. @@ -349,7 +349,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy .FadeOut(800, Easing.Out); accuracyCircle - .FillTo(accuracyS - NOTCH_WIDTH_PERCENTAGE / 2 - visual_alignment_offset, 70, Easing.OutQuint); + .FillTo(accuracyS - GRADE_SPACING_PERCENTAGE / 2 - visual_alignment_offset, 70, Easing.OutQuint); badges.Single(b => b.Rank == getRank(ScoreRank.S)) .FadeOut(70, Easing.OutQuint); diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs index e60a24a310..57b6d8e4ac 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs @@ -79,8 +79,8 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy public GradedCircle(double startProgress, double endProgress) { - this.startProgress = startProgress + AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5; - this.endProgress = endProgress - AccuracyCircle.NOTCH_WIDTH_PERCENTAGE * 0.5; + this.startProgress = startProgress + AccuracyCircle.GRADE_SPACING_PERCENTAGE * 0.5; + this.endProgress = endProgress - AccuracyCircle.GRADE_SPACING_PERCENTAGE * 0.5; Anchor = Anchor.Centre; Origin = Anchor.Centre; From 4be4ed7ab255fe6cff9b6b882e011a26a5ff15ff Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 5 Feb 2024 23:27:16 +0300 Subject: [PATCH 051/223] Add "ranked" attribute to scores --- osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs | 4 ++++ osu.Game/Scoring/ScoreInfo.cs | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 732da3d5da..42b9d9414f 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -115,6 +115,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("has_replay")] public bool HasReplay { get; set; } + [JsonProperty("ranked")] + public bool Ranked { get; set; } + // These properties are calculated or not relevant to any external usage. public bool ShouldSerializeID() => false; public bool ShouldSerializeUser() => false; @@ -212,6 +215,7 @@ namespace osu.Game.Online.API.Requests.Responses HasOnlineReplay = HasReplay, Mods = mods, PP = PP, + Ranked = Ranked, }; if (beatmap is BeatmapInfo realmBeatmap) diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 32e4bbbf29..fd98107792 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -107,6 +107,12 @@ namespace osu.Game.Scoring public double? PP { get; set; } + /// + /// Whether the performance points in this score is awarded to the player. This is used for online display purposes (see ). + /// + [Ignored] + public bool Ranked { get; set; } + /// /// The online ID of this score. /// From 6b7ffc240bbe3eb9138c3620ad175d2d9c7a3487 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 5 Feb 2024 23:28:21 +0300 Subject: [PATCH 052/223] Support displaying "unranked PP" placeholder --- .../Overlays/BeatmapSet/Scores/ScoreTable.cs | 8 +++--- .../Scores/TopScoreStatisticsSection.cs | 8 +++--- .../Sections/Ranks/DrawableProfileScore.cs | 11 ++++++++ .../UnrankedPerformancePointsPlaceholder.cs | 26 +++++++++++++++++++ 4 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 1fc997fdad..c8ecb38c86 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -180,10 +180,12 @@ namespace osu.Game.Overlays.BeatmapSet.Scores if (showPerformancePoints) { - if (score.PP != null) - content.Add(new StatisticText(score.PP, format: @"N0")); - else + if (!score.Ranked) + content.Add(new UnrankedPerformancePointsPlaceholder { Font = OsuFont.GetFont(size: text_size) }); + else if (score.PP == null) content.Add(new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(text_size) }); + else + content.Add(new StatisticText(score.PP, format: @"N0")); } content.Add(new ScoreboardTime(score.Date, text_size) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs index 72e590b009..488b99d620 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs @@ -125,10 +125,12 @@ namespace osu.Game.Overlays.BeatmapSet.Scores ppColumn.Alpha = value.BeatmapInfo!.Status.GrantsPerformancePoints() ? 1 : 0; - if (value.PP is double pp) - ppColumn.Text = pp.ToLocalisableString(@"N0"); - else + if (!value.Ranked) + ppColumn.Drawable = new UnrankedPerformancePointsPlaceholder { Font = smallFont }; + else if (value.PP is not double pp) ppColumn.Drawable = new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(smallFont.Size) }; + else + ppColumn.Text = pp.ToLocalisableString(@"N0"); statisticsColumns.ChildrenEnumerable = value.GetStatisticsForDisplay().Select(createStatisticsColumn); modsColumn.Mods = value.Mods; diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index c26f2f19ba..c7d7af0bd7 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -216,7 +216,18 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks if (!Score.PP.HasValue) { if (Score.Beatmap?.Status.GrantsPerformancePoints() == true) + { + if (!Score.Ranked) + { + return new UnrankedPerformancePointsPlaceholder + { + Font = OsuFont.GetFont(weight: FontWeight.Bold), + Colour = colourProvider.Highlight1 + }; + } + return new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(16), Colour = colourProvider.Highlight1 }; + } return new OsuSpriteText { diff --git a/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs b/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs new file mode 100644 index 0000000000..4c44def1ee --- /dev/null +++ b/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable +using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; + +namespace osu.Game.Scoring.Drawables +{ + /// + /// A placeholder used in PP columns for scores that do not award PP. + /// + public partial class UnrankedPerformancePointsPlaceholder : SpriteText, IHasTooltip + { + public LocalisableString TooltipText => "pp is not awarded for this score"; // todo: replace with localised string ScoresStrings.StatusNoPp. + + public UnrankedPerformancePointsPlaceholder() + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + Text = "-"; + } + } +} From b78c6ed673353d6d9158dc7b24c5278100a4e74f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 5 Feb 2024 23:28:30 +0300 Subject: [PATCH 053/223] Update design of "unprocessed PP" placeholder to match web --- .../Drawables/UnprocessedPerformancePointsPlaceholder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs b/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs index 99eb7e964d..a2cb69062e 100644 --- a/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs +++ b/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs @@ -21,7 +21,7 @@ namespace osu.Game.Scoring.Drawables { Anchor = Anchor.Centre; Origin = Anchor.Centre; - Icon = FontAwesome.Solid.ExclamationTriangle; + Icon = FontAwesome.Solid.Sync; } } } From b0da0859d8c91a5b0c22805894bb56680c7a15c7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 5 Feb 2024 23:28:53 +0300 Subject: [PATCH 054/223] Add visual test cases --- .../Visual/Online/TestSceneScoresContainer.cs | 19 +++++++++++ .../Online/TestSceneUserProfileScores.cs | 34 ++++++++++++++++--- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs index 2bfbf76c10..33f4d577bd 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs @@ -154,6 +154,19 @@ namespace osu.Game.Tests.Visual.Online }); } + [Test] + public void TestUnrankedPP() + { + AddStep("Load scores with unranked PP", () => + { + var allScores = createScores(); + allScores.Scores[0].Ranked = false; + allScores.UserScore = createUserBest(); + allScores.UserScore.Score.Ranked = false; + scoresContainer.Scores = allScores; + }); + } + private ulong onlineID = 1; private APIScoresCollection createScores() @@ -184,6 +197,7 @@ namespace osu.Game.Tests.Visual.Online MaxCombo = 1234, TotalScore = 1234567890, Accuracy = 1, + Ranked = true, }, new SoloScoreInfo { @@ -206,6 +220,7 @@ namespace osu.Game.Tests.Visual.Online MaxCombo = 1234, TotalScore = 1234789, Accuracy = 0.9997, + Ranked = true, }, new SoloScoreInfo { @@ -227,6 +242,7 @@ namespace osu.Game.Tests.Visual.Online MaxCombo = 1234, TotalScore = 12345678, Accuracy = 0.9854, + Ranked = true, }, new SoloScoreInfo { @@ -247,6 +263,7 @@ namespace osu.Game.Tests.Visual.Online MaxCombo = 1234, TotalScore = 1234567, Accuracy = 0.8765, + Ranked = true, }, new SoloScoreInfo { @@ -263,6 +280,7 @@ namespace osu.Game.Tests.Visual.Online MaxCombo = 1234, TotalScore = 123456, Accuracy = 0.6543, + Ranked = true, }, } }; @@ -309,6 +327,7 @@ namespace osu.Game.Tests.Visual.Online MaxCombo = 1234, TotalScore = 123456, Accuracy = 0.6543, + Ranked = true, }, Position = 1337, }; diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs index 5249e8694d..f72980757b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs @@ -40,7 +40,8 @@ namespace osu.Game.Tests.Visual.Online new APIMod { Acronym = new OsuModHardRock().Acronym }, new APIMod { Acronym = new OsuModDoubleTime().Acronym }, }, - Accuracy = 0.9813 + Accuracy = 0.9813, + Ranked = true, }; var secondScore = new SoloScoreInfo @@ -62,7 +63,8 @@ namespace osu.Game.Tests.Visual.Online new APIMod { Acronym = new OsuModHardRock().Acronym }, new APIMod { Acronym = new OsuModDoubleTime().Acronym }, }, - Accuracy = 0.998546 + Accuracy = 0.998546, + Ranked = true, }; var thirdScore = new SoloScoreInfo @@ -79,7 +81,8 @@ namespace osu.Game.Tests.Visual.Online DifficultyName = "Insane" }, EndedAt = DateTimeOffset.Now, - Accuracy = 0.9726 + Accuracy = 0.9726, + Ranked = true, }; var noPPScore = new SoloScoreInfo @@ -95,7 +98,8 @@ namespace osu.Game.Tests.Visual.Online DifficultyName = "[4K] Cataclysmic Hypernova" }, EndedAt = DateTimeOffset.Now, - Accuracy = 0.55879 + Accuracy = 0.55879, + Ranked = true, }; var unprocessedPPScore = new SoloScoreInfo @@ -112,7 +116,26 @@ namespace osu.Game.Tests.Visual.Online Status = BeatmapOnlineStatus.Ranked, }, EndedAt = DateTimeOffset.Now, - Accuracy = 0.55879 + Accuracy = 0.55879, + Ranked = true, + }; + + var unrankedPPScore = new SoloScoreInfo + { + Rank = ScoreRank.B, + Beatmap = new APIBeatmap + { + BeatmapSet = new APIBeatmapSet + { + Title = "C18H27NO3(extend)", + Artist = "Team Grimoire", + }, + DifficultyName = "[4K] Cataclysmic Hypernova", + Status = BeatmapOnlineStatus.Ranked, + }, + EndedAt = DateTimeOffset.Now, + Accuracy = 0.55879, + Ranked = false, }; Add(new FillFlowContainer @@ -129,6 +152,7 @@ namespace osu.Game.Tests.Visual.Online new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(secondScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(noPPScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(unprocessedPPScore)), + new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(unrankedPPScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(firstScore, 0.97)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(secondScore, 0.85)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(thirdScore, 0.66)), From 5265d33c126c612a787bed98fa1c665d061c78c0 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 6 Feb 2024 23:32:54 +0900 Subject: [PATCH 055/223] Make coverage into a bindable --- .../TestScenePlayfieldCoveringContainer.cs | 12 ++++---- .../Mods/ManiaModPlayfieldCover.cs | 2 +- .../UI/PlayfieldCoveringWrapper.cs | 28 +++++++++++-------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestScenePlayfieldCoveringContainer.cs b/osu.Game.Rulesets.Mania.Tests/TestScenePlayfieldCoveringContainer.cs index 2a8dc715f9..341d52afcf 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestScenePlayfieldCoveringContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestScenePlayfieldCoveringContainer.cs @@ -39,18 +39,18 @@ namespace osu.Game.Rulesets.Mania.Tests public void TestScrollingDownwards() { AddStep("set down scroll", () => scrollingContainer.Direction = ScrollingDirection.Down); - AddStep("set coverage = 0.5", () => cover.Coverage = 0.5f); - AddStep("set coverage = 0.8f", () => cover.Coverage = 0.8f); - AddStep("set coverage = 0.2f", () => cover.Coverage = 0.2f); + AddStep("set coverage = 0.5", () => cover.Coverage.Value = 0.5f); + AddStep("set coverage = 0.8f", () => cover.Coverage.Value = 0.8f); + AddStep("set coverage = 0.2f", () => cover.Coverage.Value = 0.2f); } [Test] public void TestScrollingUpwards() { AddStep("set up scroll", () => scrollingContainer.Direction = ScrollingDirection.Up); - AddStep("set coverage = 0.5", () => cover.Coverage = 0.5f); - AddStep("set coverage = 0.8f", () => cover.Coverage = 0.8f); - AddStep("set coverage = 0.2f", () => cover.Coverage = 0.2f); + AddStep("set coverage = 0.5", () => cover.Coverage.Value = 0.5f); + AddStep("set coverage = 0.8f", () => cover.Coverage.Value = 0.8f); + AddStep("set coverage = 0.2f", () => cover.Coverage.Value = 0.2f); } } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs index bc76c5cfe9..18c3ecc073 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mania.Mods { c.RelativeSizeAxes = Axes.Both; c.Direction = ExpandDirection; - c.Coverage = Coverage.Value; + c.Coverage.BindTo(Coverage); })); } } diff --git a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs index 92f471e36b..0956b2f98f 100644 --- a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs +++ b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs @@ -19,6 +19,11 @@ namespace osu.Game.Rulesets.Mania.UI /// public partial class PlayfieldCoveringWrapper : CompositeDrawable { + /// + /// The relative area that should be completely covered. This does not include the fade. + /// + public readonly BindableFloat Coverage = new BindableFloat(); + /// /// The complete cover, including gradient and fill. /// @@ -94,21 +99,20 @@ namespace osu.Game.Rulesets.Mania.UI scrollDirection.BindValueChanged(onScrollDirectionChanged, true); } + protected override void LoadComplete() + { + base.LoadComplete(); + + Coverage.BindValueChanged(c => + { + filled.Height = c.NewValue; + gradient.Y = -c.NewValue; + }, true); + } + private void onScrollDirectionChanged(ValueChangedEvent direction) => cover.Rotation = direction.NewValue == ScrollingDirection.Up ? 0 : 180f; - /// - /// The relative area that should be completely covered. This does not include the fade. - /// - public float Coverage - { - set - { - filled.Height = value; - gradient.Y = -value; - } - } - /// /// The direction in which the cover expands. /// From 5bc7befbd4d780c8f3e473865e3679521bbfe1f7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 6 Feb 2024 23:47:20 +0900 Subject: [PATCH 056/223] Add progressive cover to mania HD and FI mods --- .../Mods/ManiaModFadeIn.cs | 11 +------ .../Mods/ManiaModHidden.cs | 31 +++++++++++++------ .../Mods/ManiaModPlayfieldCover.cs | 2 -- osu.Game/Rulesets/Mods/ModHidden.cs | 4 +-- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs index 196514c7b1..d436f22cdd 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs @@ -3,13 +3,12 @@ using System; using System.Linq; -using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModFadeIn : ManiaModPlayfieldCover + public class ManiaModFadeIn : ManiaModHidden { public override string Name => "Fade In"; public override string Acronym => "FI"; @@ -19,13 +18,5 @@ namespace osu.Game.Rulesets.Mania.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModHidden)).ToArray(); protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AlongScroll; - - public override BindableNumber Coverage { get; } = new BindableFloat(0.5f) - { - Precision = 0.1f, - MinValue = 0.1f, - MaxValue = 0.7f, - Default = 0.5f, - }; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index f23cb335a5..7dcd5816a9 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -6,24 +6,37 @@ using System.Linq; using osu.Framework.Localisation; using osu.Game.Rulesets.Mania.UI; using osu.Framework.Bindables; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModHidden : ManiaModPlayfieldCover { + /// + /// osu!stable is referenced to 480px. + /// + private const float playfield_height = 480; + + private const float min_coverage = 160f / playfield_height; + private const float max_coverage = 400f / playfield_height; + private const float coverage_increase_per_combo = 0.5f / playfield_height; + public override LocalisableString Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; - - public override BindableNumber Coverage { get; } = new BindableFloat(0.5f) - { - Precision = 0.1f, - MinValue = 0.2f, - MaxValue = 0.8f, - Default = 0.5f, - }; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModFadeIn)).ToArray(); + public override BindableNumber Coverage { get; } = new BindableFloat(min_coverage); protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AgainstScroll; + + private readonly BindableInt combo = new BindableInt(); + + public override void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + { + base.ApplyToScoreProcessor(scoreProcessor); + + combo.UnbindAll(); + combo.BindTo(scoreProcessor.Combo); + combo.BindValueChanged(c => Coverage.Value = Math.Min(max_coverage, min_coverage + c.NewValue * coverage_increase_per_combo), true); + } } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs index 18c3ecc073..aadb9b5717 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Configuration; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; @@ -24,7 +23,6 @@ namespace osu.Game.Rulesets.Mania.Mods /// protected abstract CoverExpandDirection ExpandDirection { get; } - [SettingSource("Coverage", "The proportion of playfield height that notes will be hidden for.")] public abstract BindableNumber Coverage { get; } public virtual void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) diff --git a/osu.Game/Rulesets/Mods/ModHidden.cs b/osu.Game/Rulesets/Mods/ModHidden.cs index 5a1abf115f..2915cb9bea 100644 --- a/osu.Game/Rulesets/Mods/ModHidden.cs +++ b/osu.Game/Rulesets/Mods/ModHidden.cs @@ -16,11 +16,11 @@ namespace osu.Game.Rulesets.Mods public override ModType Type => ModType.DifficultyIncrease; public override bool Ranked => UsesDefaultConfiguration; - public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) + public virtual void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) { } - public ScoreRank AdjustRank(ScoreRank rank, double accuracy) + public virtual ScoreRank AdjustRank(ScoreRank rank, double accuracy) { switch (rank) { From bacb1d0dc7cf484a0a6b70f5ecdd0f4ec28bd350 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 6 Feb 2024 23:58:27 +0900 Subject: [PATCH 057/223] Add easing to make the transition less awkward --- .../UI/PlayfieldCoveringWrapper.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs index 0956b2f98f..f0ac18d7ca 100644 --- a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs +++ b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -8,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; using osu.Game.Rulesets.UI.Scrolling; using osuTK; using osuTK.Graphics; @@ -103,11 +105,20 @@ namespace osu.Game.Rulesets.Mania.UI { base.LoadComplete(); - Coverage.BindValueChanged(c => - { - filled.Height = c.NewValue; - gradient.Y = -c.NewValue; - }, true); + updateHeight(Coverage.Value); + } + + protected override void Update() + { + base.Update(); + + updateHeight((float)Interpolation.DampContinuously(filled.Height, Coverage.Value, 25, Math.Abs(Time.Elapsed))); + } + + private void updateHeight(float height) + { + filled.Height = height; + gradient.Y = -height; } private void onScrollDirectionChanged(ValueChangedEvent direction) From 69db1b2778035b0d02ce94b842f8bedc3b88971c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Feb 2024 00:15:06 +0900 Subject: [PATCH 058/223] Add ManiaModCover to take over old roles of the mods --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- osu.Game.Rulesets.Mania/Mods/ManiaModCover.cs | 44 +++++++++++++++++++ .../Mods/ManiaModFadeIn.cs | 6 ++- .../Mods/ManiaModHidden.cs | 9 +++- ...Cover.cs => ManiaModWithPlayfieldCover.cs} | 5 ++- 5 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Mods/ManiaModCover.cs rename osu.Game.Rulesets.Mania/Mods/{ManiaModPlayfieldCover.cs => ManiaModWithPlayfieldCover.cs} (88%) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index c38d6519bd..f19d43826f 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -247,7 +247,7 @@ namespace osu.Game.Rulesets.Mania new ManiaModHardRock(), new MultiMod(new ManiaModSuddenDeath(), new ManiaModPerfect()), new MultiMod(new ManiaModDoubleTime(), new ManiaModNightcore()), - new MultiMod(new ManiaModFadeIn(), new ManiaModHidden()), + new MultiMod(new ManiaModFadeIn(), new ManiaModHidden(), new ManiaModCover()), new ManiaModFlashlight(), new ModAccuracyChallenge(), }; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModCover.cs new file mode 100644 index 0000000000..eb243bfab7 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModCover.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 System; +using System.Linq; +using osu.Framework.Bindables; +using osu.Framework.Localisation; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mania.UI; + +namespace osu.Game.Rulesets.Mania.Mods +{ + public class ManiaModCover : ManiaModWithPlayfieldCover + { + public override string Name => "Cover"; + public override string Acronym => "CO"; + + public override LocalisableString Description => @"Decrease the playfield's viewing area."; + + public override double ScoreMultiplier => 1; + + protected override CoverExpandDirection ExpandDirection => Direction.Value; + + public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] + { + typeof(ManiaModHidden), + typeof(ManiaModFadeIn) + }).ToArray(); + + public override bool Ranked => false; + + [SettingSource("Coverage", "The proportion of playfield height that notes will be hidden for.")] + public override BindableNumber Coverage { get; } = new BindableFloat(0.5f) + { + Precision = 0.1f, + MinValue = 0.2f, + MaxValue = 0.8f, + Default = 0.5f, + }; + + [SettingSource("Direction", "The direction on which the cover is applied")] + public Bindable Direction { get; } = new Bindable(); + } +} diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs index d436f22cdd..54a0b8f36d 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs @@ -15,7 +15,11 @@ namespace osu.Game.Rulesets.Mania.Mods public override LocalisableString Description => @"Keys appear out of nowhere!"; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModHidden)).ToArray(); + public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] + { + typeof(ManiaModHidden), + typeof(ManiaModCover) + }).ToArray(); protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AlongScroll; } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 7dcd5816a9..f4d5386d70 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModHidden : ManiaModPlayfieldCover + public class ManiaModHidden : ManiaModWithPlayfieldCover { /// /// osu!stable is referenced to 480px. @@ -23,7 +23,12 @@ namespace osu.Game.Rulesets.Mania.Mods public override LocalisableString Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModFadeIn)).ToArray(); + + public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] + { + typeof(ManiaModFadeIn), + typeof(ManiaModCover) + }).ToArray(); public override BindableNumber Coverage { get; } = new BindableFloat(min_coverage); protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AgainstScroll; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModWithPlayfieldCover.cs similarity index 88% rename from osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs rename to osu.Game.Rulesets.Mania/Mods/ManiaModWithPlayfieldCover.cs index aadb9b5717..bb5807269a 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModWithPlayfieldCover.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania.Mods { - public abstract class ManiaModPlayfieldCover : ModHidden, IApplicableToDrawableRuleset + public abstract class ManiaModWithPlayfieldCover : ModHidden, IApplicableToDrawableRuleset { public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; @@ -23,6 +23,9 @@ namespace osu.Game.Rulesets.Mania.Mods /// protected abstract CoverExpandDirection ExpandDirection { get; } + /// + /// The relative area that should be completely covered. This does not include the fade. + /// public abstract BindableNumber Coverage { get; } public virtual void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) From af20eacc82747661f2408b4540d221814ea5e1d8 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Feb 2024 00:25:22 +0900 Subject: [PATCH 059/223] Fix coordinate space --- osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index f4d5386d70..9def29f82b 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -13,9 +13,9 @@ namespace osu.Game.Rulesets.Mania.Mods public class ManiaModHidden : ManiaModWithPlayfieldCover { /// - /// osu!stable is referenced to 480px. + /// osu!stable is referenced to 768px. /// - private const float playfield_height = 480; + private const float playfield_height = 768; private const float min_coverage = 160f / playfield_height; private const float max_coverage = 400f / playfield_height; From ff7cd67909d72c520ec2aabaf7ac96083d812cd3 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 6 Feb 2024 21:14:36 +0300 Subject: [PATCH 060/223] Move all the circles into their own container --- .../Expanded/Accuracy/GradedCircles.cs | 66 +++++++++---------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs index 57b6d8e4ac..33b71c53a7 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/GradedCircles.cs @@ -20,49 +20,45 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy set { progress = value; - dProgress.RevealProgress = value; - cProgress.RevealProgress = value; - bProgress.RevealProgress = value; - aProgress.RevealProgress = value; - sProgress.RevealProgress = value; - xProgress.RevealProgress = value; + + foreach (var circle in circles) + circle.RevealProgress = value; } } - private readonly GradedCircle dProgress; - private readonly GradedCircle cProgress; - private readonly GradedCircle bProgress; - private readonly GradedCircle aProgress; - private readonly GradedCircle sProgress; - private readonly GradedCircle xProgress; + private readonly Container circles; public GradedCircles(double accuracyC, double accuracyB, double accuracyA, double accuracyS, double accuracyX) { - InternalChildren = new Drawable[] + InternalChild = circles = new Container { - dProgress = new GradedCircle(0.0, accuracyC) + RelativeSizeAxes = Axes.Both, + Children = new[] { - Colour = OsuColour.ForRank(ScoreRank.D), - }, - cProgress = new GradedCircle(accuracyC, accuracyB) - { - Colour = OsuColour.ForRank(ScoreRank.C), - }, - bProgress = new GradedCircle(accuracyB, accuracyA) - { - Colour = OsuColour.ForRank(ScoreRank.B), - }, - aProgress = new GradedCircle(accuracyA, accuracyS) - { - Colour = OsuColour.ForRank(ScoreRank.A), - }, - sProgress = new GradedCircle(accuracyS, accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE) - { - Colour = OsuColour.ForRank(ScoreRank.S), - }, - xProgress = new GradedCircle(accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE, 1.0) - { - Colour = OsuColour.ForRank(ScoreRank.X) + new GradedCircle(0.0, accuracyC) + { + Colour = OsuColour.ForRank(ScoreRank.D), + }, + new GradedCircle(accuracyC, accuracyB) + { + Colour = OsuColour.ForRank(ScoreRank.C), + }, + new GradedCircle(accuracyB, accuracyA) + { + Colour = OsuColour.ForRank(ScoreRank.B), + }, + new GradedCircle(accuracyA, accuracyS) + { + Colour = OsuColour.ForRank(ScoreRank.A), + }, + new GradedCircle(accuracyS, accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE) + { + Colour = OsuColour.ForRank(ScoreRank.S), + }, + new GradedCircle(accuracyX - AccuracyCircle.VIRTUAL_SS_PERCENTAGE, 1.0) + { + Colour = OsuColour.ForRank(ScoreRank.X) + } } }; } From 9a3c947319c93e19299424a40b9aa982dffe11c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Feb 2024 13:35:12 +0100 Subject: [PATCH 061/223] Remove unnecessary `#nullable disable` --- .../Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs b/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs index 4c44def1ee..025977e745 100644 --- a/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs +++ b/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; From f22828bc50db359957c13abceee296ac7b3b95fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Feb 2024 13:36:46 +0100 Subject: [PATCH 062/223] Flip `if`s to reduce nesting --- .../Sections/Ranks/DrawableProfileScore.cs | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index c7d7af0bd7..d1988956be 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -213,22 +213,36 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks private Drawable createDrawablePerformance() { - if (!Score.PP.HasValue) + if (Score.PP.HasValue) { - if (Score.Beatmap?.Status.GrantsPerformancePoints() == true) + return new FillFlowContainer { - if (!Score.Ranked) + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new[] { - return new UnrankedPerformancePointsPlaceholder + new OsuSpriteText { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, Font = OsuFont.GetFont(weight: FontWeight.Bold), + Text = $"{Score.PP:0}", Colour = colourProvider.Highlight1 - }; + }, + new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Text = "pp", + Colour = colourProvider.Light3 + } } + }; + } - return new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(16), Colour = colourProvider.Highlight1 }; - } - + if (Score.Beatmap?.Status.GrantsPerformancePoints() != true) + { return new OsuSpriteText { Font = OsuFont.GetFont(weight: FontWeight.Bold), @@ -237,30 +251,16 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }; } - return new FillFlowContainer + if (!Score.Ranked) { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new[] + return new UnrankedPerformancePointsPlaceholder { - new OsuSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Font = OsuFont.GetFont(weight: FontWeight.Bold), - Text = $"{Score.PP:0}", - Colour = colourProvider.Highlight1 - }, - new OsuSpriteText - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), - Text = "pp", - Colour = colourProvider.Light3 - } - } - }; + Font = OsuFont.GetFont(weight: FontWeight.Bold), + Colour = colourProvider.Highlight1 + }; + } + + return new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(16), Colour = colourProvider.Highlight1 }; } private partial class ScoreBeatmapMetadataContainer : BeatmapMetadataContainer From 3f51148719918f0b5d8d91b1575a87319d21a3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Feb 2024 13:37:37 +0100 Subject: [PATCH 063/223] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 935b759e4d..db41b04e44 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + From 706a16677c1e86b921301d8d499487c7b954c354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Feb 2024 13:38:05 +0100 Subject: [PATCH 064/223] Use localised string --- .../Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs b/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs index 025977e745..c5c190e1a1 100644 --- a/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs +++ b/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Scoring.Drawables { @@ -13,7 +14,7 @@ namespace osu.Game.Scoring.Drawables /// public partial class UnrankedPerformancePointsPlaceholder : SpriteText, IHasTooltip { - public LocalisableString TooltipText => "pp is not awarded for this score"; // todo: replace with localised string ScoresStrings.StatusNoPp. + public LocalisableString TooltipText => ScoresStrings.StatusNoPp; public UnrankedPerformancePointsPlaceholder() { From 8f995a30af27f3cd90df67d1c45e434e028daf5d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 8 Feb 2024 00:20:32 +0900 Subject: [PATCH 065/223] Fix legacy coverage metrics --- .../Mods/ManiaModHidden.cs | 29 +++++++++++++++---- .../Mods/ManiaModWithPlayfieldCover.cs | 4 ++- .../UI/PlayfieldCoveringWrapper.cs | 14 ++++++--- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 9def29f82b..211f21513d 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -6,20 +6,21 @@ using System.Linq; using osu.Framework.Localisation; using osu.Game.Rulesets.Mania.UI; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModHidden : ManiaModWithPlayfieldCover + public partial class ManiaModHidden : ManiaModWithPlayfieldCover { /// /// osu!stable is referenced to 768px. /// - private const float playfield_height = 768; + private const float reference_playfield_height = 768; - private const float min_coverage = 160f / playfield_height; - private const float max_coverage = 400f / playfield_height; - private const float coverage_increase_per_combo = 0.5f / playfield_height; + private const float min_coverage = 160 / reference_playfield_height; + private const float max_coverage = 400f / reference_playfield_height; + private const float coverage_increase_per_combo = 0.5f / reference_playfield_height; public override LocalisableString Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; @@ -43,5 +44,23 @@ namespace osu.Game.Rulesets.Mania.Mods combo.BindTo(scoreProcessor.Combo); combo.BindValueChanged(c => Coverage.Value = Math.Min(max_coverage, min_coverage + c.NewValue * coverage_increase_per_combo), true); } + + protected override PlayfieldCoveringWrapper CreateCover(Drawable content) => new LegacyPlayfieldCover(content); + + private partial class LegacyPlayfieldCover : PlayfieldCoveringWrapper + { + public LegacyPlayfieldCover(Drawable content) + : base(content) + { + } + + protected override float GetHeight(float coverage) + { + if (DrawHeight == 0) + return base.GetHeight(coverage); + + return base.GetHeight(coverage) * reference_playfield_height / DrawHeight; + } + } } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModWithPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModWithPlayfieldCover.cs index bb5807269a..864ef6c3d6 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModWithPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModWithPlayfieldCover.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Mods Container hocParent = (Container)hoc.Parent!; hocParent.Remove(hoc, false); - hocParent.Add(new PlayfieldCoveringWrapper(hoc).With(c => + hocParent.Add(CreateCover(hoc).With(c => { c.RelativeSizeAxes = Axes.Both; c.Direction = ExpandDirection; @@ -47,6 +47,8 @@ namespace osu.Game.Rulesets.Mania.Mods } } + protected virtual PlayfieldCoveringWrapper CreateCover(Drawable content) => new PlayfieldCoveringWrapper(content); + protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) { } diff --git a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs index f0ac18d7ca..2b70c527ae 100644 --- a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs +++ b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs @@ -43,6 +43,8 @@ namespace osu.Game.Rulesets.Mania.UI private readonly IBindable scrollDirection = new Bindable(); + private float currentCoverage; + public PlayfieldCoveringWrapper(Drawable content) { InternalChild = new BufferedContainer @@ -112,15 +114,19 @@ namespace osu.Game.Rulesets.Mania.UI { base.Update(); - updateHeight((float)Interpolation.DampContinuously(filled.Height, Coverage.Value, 25, Math.Abs(Time.Elapsed))); + updateHeight((float)Interpolation.DampContinuously(currentCoverage, Coverage.Value, 25, Math.Abs(Time.Elapsed))); } - private void updateHeight(float height) + private void updateHeight(float coverage) { - filled.Height = height; - gradient.Y = -height; + filled.Height = GetHeight(coverage); + gradient.Y = -GetHeight(coverage); + + currentCoverage = coverage; } + protected virtual float GetHeight(float coverage) => coverage; + private void onScrollDirectionChanged(ValueChangedEvent direction) => cover.Rotation = direction.NewValue == ScrollingDirection.Up ? 0 : 180f; From c500264306adceec5edbbab0baa40a7bc13c65c4 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 9 Feb 2024 23:20:31 +0300 Subject: [PATCH 066/223] Cache created judgement in HitObject --- .../TestSceneCatchSkinConfiguration.cs | 2 +- osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs | 2 +- osu.Game.Rulesets.Catch/Objects/Banana.cs | 2 +- osu.Game.Rulesets.Catch/Objects/BananaShower.cs | 2 +- osu.Game.Rulesets.Catch/Objects/Droplet.cs | 2 +- osu.Game.Rulesets.Catch/Objects/Fruit.cs | 2 +- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 2 +- osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs | 2 +- osu.Game.Rulesets.Mania/Objects/BarLine.cs | 2 +- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 2 +- osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs | 2 +- osu.Game.Rulesets.Mania/Objects/Note.cs | 2 +- osu.Game.Rulesets.Mania/Objects/TailNote.cs | 2 +- .../TestSceneSpinnerRotation.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs | 2 +- osu.Game.Rulesets.Osu/Objects/HitCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderTick.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs | 2 +- .../TaikoHealthProcessorTest.cs | 8 ++++---- osu.Game.Rulesets.Taiko/Objects/BarLine.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 4 ++-- osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs | 2 +- .../Objects/StrongNestedHitObject.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/SwellTick.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs | 2 +- osu.Game/Beatmaps/IBeatmap.cs | 2 +- osu.Game/Database/StandardisedScoreMigrationTools.cs | 2 +- .../Difficulty/PerformanceBreakdownCalculator.cs | 4 ++-- .../Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- osu.Game/Rulesets/Objects/HitObject.cs | 10 +++++++++- osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs | 2 +- osu.Game/Rulesets/Scoring/JudgementProcessor.cs | 2 +- .../Rulesets/Scoring/LegacyDrainingHealthProcessor.cs | 2 +- 41 files changed, 54 insertions(+), 46 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs index e2fc31d869..0d7aa6af10 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs @@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Catch.Tests { fruit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); var drawableFruit = new DrawableFruit(fruit) { X = x }; - var judgement = fruit.CreateJudgement(); + var judgement = fruit.Judgement; catcher.OnNewResult(drawableFruit, new CatchJudgementResult(fruit, judgement) { Type = judgement.MaxResult diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index f60ae29f77..b03fa00f76 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -293,7 +293,7 @@ namespace osu.Game.Rulesets.Catch.Tests private JudgementResult createResult(CatchHitObject hitObject) { - return new CatchJudgementResult(hitObject, hitObject.CreateJudgement()) + return new CatchJudgementResult(hitObject, hitObject.Judgement) { Type = catcher.CanCatch(hitObject) ? HitResult.Great : HitResult.Miss }; diff --git a/osu.Game.Rulesets.Catch/Objects/Banana.cs b/osu.Game.Rulesets.Catch/Objects/Banana.cs index b80527f379..30bdb24b14 100644 --- a/osu.Game.Rulesets.Catch/Objects/Banana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Banana.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Catch.Objects /// public int BananaIndex; - public override Judgement CreateJudgement() => new CatchBananaJudgement(); + protected override Judgement CreateJudgement() => new CatchBananaJudgement(); private static readonly IList default_banana_samples = new List { new BananaHitSampleInfo() }.AsReadOnly(); diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs index 328cc2b52a..86c41fce90 100644 --- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects { public override bool LastInCombo => true; - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { diff --git a/osu.Game.Rulesets.Catch/Objects/Droplet.cs b/osu.Game.Rulesets.Catch/Objects/Droplet.cs index 9c1004a04b..107c6c3979 100644 --- a/osu.Game.Rulesets.Catch/Objects/Droplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Droplet.cs @@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.Catch.Objects { public class Droplet : PalpableCatchHitObject { - public override Judgement CreateJudgement() => new CatchDropletJudgement(); + protected override Judgement CreateJudgement() => new CatchDropletJudgement(); } } diff --git a/osu.Game.Rulesets.Catch/Objects/Fruit.cs b/osu.Game.Rulesets.Catch/Objects/Fruit.cs index 4818fe2cad..17270b803c 100644 --- a/osu.Game.Rulesets.Catch/Objects/Fruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Fruit.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Catch.Objects { public class Fruit : PalpableCatchHitObject { - public override Judgement CreateJudgement() => new CatchJudgement(); + protected override Judgement CreateJudgement() => new CatchJudgement(); public static FruitVisualRepresentation GetVisualRepresentation(int indexInBeatmap) => (FruitVisualRepresentation)(indexInBeatmap % 4); } diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 671291ef0e..49c24df5b9 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Objects /// private const float base_scoring_distance = 100; - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); public int RepeatCount { get; set; } diff --git a/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs index 1bf160b5a6..ddcb92875f 100644 --- a/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs @@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.Catch.Objects { public class TinyDroplet : Droplet { - public override Judgement CreateJudgement() => new CatchTinyDropletJudgement(); + protected override Judgement CreateJudgement() => new CatchTinyDropletJudgement(); } } diff --git a/osu.Game.Rulesets.Mania/Objects/BarLine.cs b/osu.Game.Rulesets.Mania/Objects/BarLine.cs index cf576239ed..742b5e4b0d 100644 --- a/osu.Game.Rulesets.Mania/Objects/BarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/BarLine.cs @@ -19,6 +19,6 @@ namespace osu.Game.Rulesets.Mania.Objects set => major.Value = value; } - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); } } diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 3f930a310b..4aac455bc5 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Mania.Objects }); } - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs b/osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs index 47163d0d81..92b649c174 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Objects /// public class HoldNoteBody : ManiaHitObject { - public override Judgement CreateJudgement() => new HoldNoteBodyJudgement(); + protected override Judgement CreateJudgement() => new HoldNoteBodyJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Mania/Objects/Note.cs b/osu.Game.Rulesets.Mania/Objects/Note.cs index 0035960c63..b0f2991918 100644 --- a/osu.Game.Rulesets.Mania/Objects/Note.cs +++ b/osu.Game.Rulesets.Mania/Objects/Note.cs @@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Mania.Objects /// public class Note : ManiaHitObject { - public override Judgement CreateJudgement() => new ManiaJudgement(); + protected override Judgement CreateJudgement() => new ManiaJudgement(); } } diff --git a/osu.Game.Rulesets.Mania/Objects/TailNote.cs b/osu.Game.Rulesets.Mania/Objects/TailNote.cs index def32880f1..bddb4630cb 100644 --- a/osu.Game.Rulesets.Mania/Objects/TailNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/TailNote.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Objects /// public const double RELEASE_WINDOW_LENIENCE = 1.5; - public override Judgement CreateJudgement() => new ManiaJudgement(); + protected override Judgement CreateJudgement() => new ManiaJudgement(); public override double MaximumJudgementOffset => base.MaximumJudgementOffset * RELEASE_WINDOW_LENIENCE; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index 6706d20080..8d81fe3017 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Osu.Tests // multipled by 2 to nullify the score multiplier. (autoplay mod selected) long totalScore = scoreProcessor.TotalScore.Value * 2; - return totalScore == (int)(drawableSpinner.Result.TotalRotation / 360) * scoreProcessor.GetBaseScoreForResult(new SpinnerTick().CreateJudgement().MaxResult); + return totalScore == (int)(drawableSpinner.Result.TotalRotation / 360) * scoreProcessor.GetBaseScoreForResult(new SpinnerTick().Judgement.MaxResult); }); addSeekStep(0); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index 2c9292c58b..f07a1e930b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Osu.Mods { } - public override Judgement CreateJudgement() => new OsuJudgement(); + protected override Judgement CreateJudgement() => new OsuJudgement(); } private partial class StrictTrackingDrawableSliderTail : DrawableSliderTail diff --git a/osu.Game.Rulesets.Osu/Objects/HitCircle.cs b/osu.Game.Rulesets.Osu/Objects/HitCircle.cs index d652db0fd4..6336482ccc 100644 --- a/osu.Game.Rulesets.Osu/Objects/HitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/HitCircle.cs @@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.Osu.Objects { public class HitCircle : OsuHitObject { - public override Judgement CreateJudgement() => new OsuJudgement(); + protected override Judgement CreateJudgement() => new OsuJudgement(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 506145568e..fc0248cbbd 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -275,7 +275,7 @@ namespace osu.Game.Rulesets.Osu.Objects TailSamples = this.GetNodeSamples(repeatCount + 1); } - public override Judgement CreateJudgement() => ClassicSliderBehaviour + protected override Judgement CreateJudgement() => ClassicSliderBehaviour // Final combo is provided by the slider itself - see logic in `DrawableSlider.CheckForResult()` ? new OsuJudgement() // Final combo is provided by the tail circle - see `SliderTailCircle` diff --git a/osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs index 2d5a5b7727..8d60864f0b 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Objects protected override HitWindows CreateHitWindows() => HitWindows.Empty; - public override Judgement CreateJudgement() => new SliderEndJudgement(); + protected override Judgement CreateJudgement() => new SliderEndJudgement(); public class SliderEndJudgement : OsuJudgement { diff --git a/osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs index 8305481788..4760135081 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Osu.Objects /// public bool ClassicSliderBehaviour; - public override Judgement CreateJudgement() => ClassicSliderBehaviour ? new SliderTickJudgement() : base.CreateJudgement(); + protected override Judgement CreateJudgement() => ClassicSliderBehaviour ? new SliderTickJudgement() : base.CreateJudgement(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index ee2490439f..42d8d895e4 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Objects { } - public override Judgement CreateJudgement() => ClassicSliderBehaviour ? new LegacyTailJudgement() : new TailJudgement(); + protected override Judgement CreateJudgement() => ClassicSliderBehaviour ? new LegacyTailJudgement() : new TailJudgement(); public class LegacyTailJudgement : OsuJudgement { diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs index 74ec4d6eb3..1d7ba2fbaf 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs @@ -32,6 +32,6 @@ namespace osu.Game.Rulesets.Osu.Objects protected override HitWindows CreateHitWindows() => HitWindows.Empty; - public override Judgement CreateJudgement() => new SliderTickJudgement(); + protected override Judgement CreateJudgement() => new SliderTickJudgement(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index e3dfe8e69a..9baa645b3c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Osu.Objects } } - public override Judgement CreateJudgement() => new OsuJudgement(); + protected override Judgement CreateJudgement() => new OsuJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs b/osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs index 8d53100529..57db29ef0c 100644 --- a/osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Osu.Objects { public class SpinnerBonusTick : SpinnerTick { - public override Judgement CreateJudgement() => new OsuSpinnerBonusTickJudgement(); + protected override Judgement CreateJudgement() => new OsuSpinnerBonusTickJudgement(); public class OsuSpinnerBonusTickJudgement : OsuSpinnerTickJudgement { diff --git a/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs b/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs index 7989c9b7ff..cb59014909 100644 --- a/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Objects /// public double SpinnerDuration { get; set; } - public override Judgement CreateJudgement() => new OsuSpinnerTickJudgement(); + protected override Judgement CreateJudgement() => new OsuSpinnerTickJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoHealthProcessorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoHealthProcessorTest.cs index f4a1e888c9..b28e870481 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoHealthProcessorTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoHealthProcessorTest.cs @@ -126,11 +126,11 @@ namespace osu.Game.Rulesets.Taiko.Tests foreach (var nested in beatmap.HitObjects[0].NestedHitObjects) { - var nestedJudgement = nested.CreateJudgement(); + var nestedJudgement = nested.Judgement; healthProcessor.ApplyResult(new JudgementResult(nested, nestedJudgement) { Type = nestedJudgement.MaxResult }); } - var judgement = beatmap.HitObjects[0].CreateJudgement(); + var judgement = beatmap.HitObjects[0].Judgement; healthProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], judgement) { Type = judgement.MaxResult }); Assert.Multiple(() => @@ -159,11 +159,11 @@ namespace osu.Game.Rulesets.Taiko.Tests foreach (var nested in beatmap.HitObjects[0].NestedHitObjects) { - var nestedJudgement = nested.CreateJudgement(); + var nestedJudgement = nested.Judgement; healthProcessor.ApplyResult(new JudgementResult(nested, nestedJudgement) { Type = nestedJudgement.MaxResult }); } - var judgement = beatmap.HitObjects[0].CreateJudgement(); + var judgement = beatmap.HitObjects[0].Judgement; healthProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], judgement) { Type = judgement.MaxResult }); Assert.Multiple(() => diff --git a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs index 46b3f13501..d87f8b3232 100644 --- a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs +++ b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs @@ -19,6 +19,6 @@ namespace osu.Game.Rulesets.Taiko.Objects set => major.Value = value; } - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index f3143de345..50cd722a3f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } } - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Taiko.Objects public class StrongNestedHit : StrongNestedHitObject { // The strong hit of the drum roll doesn't actually provide any score. - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); public StrongNestedHit(TaikoHitObject parent) : base(parent) diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs index dc082ffd21..c1d4102042 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Objects Parent = parent; } - public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement(); + protected override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs b/osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs index 302f940ef4..44cd700faf 100644 --- a/osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs @@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public class IgnoreHit : Hit { - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/StrongNestedHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/StrongNestedHitObject.cs index 14cbe338ed..227ab4ab52 100644 --- a/osu.Game.Rulesets.Taiko/Objects/StrongNestedHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/StrongNestedHitObject.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Objects Parent = parent; } - public override Judgement CreateJudgement() => new TaikoStrongJudgement(); + protected override Judgement CreateJudgement() => new TaikoStrongJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index a8db8df021..76d106f924 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } } - public override Judgement CreateJudgement() => new TaikoSwellJudgement(); + protected override Judgement CreateJudgement() => new TaikoSwellJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs index 41fb9cac7e..be1c1101de 100644 --- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Taiko.Objects { public class SwellTick : TaikoHitObject { - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs index 1a1fde1990..697c23addf 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public const float DEFAULT_SIZE = 0.475f; - public override Judgement CreateJudgement() => new TaikoJudgement(); + protected override Judgement CreateJudgement() => new TaikoJudgement(); protected override HitWindows CreateHitWindows() => new TaikoHitWindows(); } diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index d97eb00d7e..b5bb6ccafc 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -94,7 +94,7 @@ namespace osu.Game.Beatmaps static void addCombo(HitObject hitObject, ref int combo) { - if (hitObject.CreateJudgement().MaxResult.AffectsCombo()) + if (hitObject.Judgement.MaxResult.AffectsCombo()) combo++; foreach (var nested in hitObject.NestedHitObjects) diff --git a/osu.Game/Database/StandardisedScoreMigrationTools.cs b/osu.Game/Database/StandardisedScoreMigrationTools.cs index 403e73ab77..576d08f491 100644 --- a/osu.Game/Database/StandardisedScoreMigrationTools.cs +++ b/osu.Game/Database/StandardisedScoreMigrationTools.cs @@ -655,7 +655,7 @@ namespace osu.Game.Database { private readonly Judgement judgement; - public override Judgement CreateJudgement() => judgement; + protected override Judgement CreateJudgement() => judgement; public FakeHit(Judgement judgement) { diff --git a/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs b/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs index 4563c264f7..946d83b14b 100644 --- a/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs @@ -113,9 +113,9 @@ namespace osu.Game.Rulesets.Difficulty private IEnumerable getPerfectHitResults(HitObject hitObject) { foreach (HitObject nested in hitObject.NestedHitObjects) - yield return nested.CreateJudgement().MaxResult; + yield return nested.Judgement.MaxResult; - yield return hitObject.CreateJudgement().MaxResult; + yield return hitObject.Judgement.MaxResult; } } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index c9192ae3eb..16bd4b565c 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -770,7 +770,7 @@ namespace osu.Game.Rulesets.Objects.Drawables private void ensureEntryHasResult() { Debug.Assert(Entry != null); - Entry.Result ??= CreateResult(HitObject.CreateJudgement()) + Entry.Result ??= CreateResult(HitObject.Judgement) ?? throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}."); } diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index ef8bd08bf4..aed821332d 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -162,11 +162,19 @@ namespace osu.Game.Rulesets.Objects protected void AddNested(HitObject hitObject) => nestedHitObjects.Add(hitObject); + /// + /// The that represents the scoring information for this . + /// + [JsonIgnore] + public Judgement Judgement => judgement ??= CreateJudgement(); + + private Judgement judgement; + /// /// Creates the that represents the scoring information for this . /// [NotNull] - public virtual Judgement CreateJudgement() => new Judgement(); + protected virtual Judgement CreateJudgement() => new Judgement(); /// /// Creates the for this . diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs index bb36aab0b3..499953dab9 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Objects.Legacy public int ComboOffset { get; set; } - public override Judgement CreateJudgement() => new IgnoreJudgement(); + protected override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs index e9f3bcb949..0e90330651 100644 --- a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs +++ b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs @@ -149,7 +149,7 @@ namespace osu.Game.Rulesets.Scoring foreach (var obj in EnumerateHitObjects(beatmap)) { - var judgement = obj.CreateJudgement(); + var judgement = obj.Judgement; var result = CreateResult(obj, judgement); if (result == null) diff --git a/osu.Game/Rulesets/Scoring/LegacyDrainingHealthProcessor.cs b/osu.Game/Rulesets/Scoring/LegacyDrainingHealthProcessor.cs index ce2f7d5624..2bc3ea80ec 100644 --- a/osu.Game/Rulesets/Scoring/LegacyDrainingHealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/LegacyDrainingHealthProcessor.cs @@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Scoring void increaseHp(HitObject hitObject) { - double amount = GetHealthIncreaseFor(hitObject, hitObject.CreateJudgement().MaxResult); + double amount = GetHealthIncreaseFor(hitObject, hitObject.Judgement.MaxResult); currentHpUncapped += amount; currentHp = Math.Max(0, Math.Min(1, currentHp + amount)); } From c9c39ecb2f616b27b088bb455d5c122323127b10 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 9 Feb 2024 15:15:27 -0800 Subject: [PATCH 067/223] Add `RankHighest` to `APIUser` --- .../Visual/Online/TestSceneUserProfileOverlay.cs | 5 +++++ osu.Game/Online/API/Requests/Responses/APIUser.cs | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index bc8f75d4ce..020e020b10 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -137,6 +137,11 @@ namespace osu.Game.Tests.Visual.Online @"top_ranks", @"medals" }, + RankHighest = new APIUser.UserRankHighest + { + Rank = 1, + UpdatedAt = DateTimeOffset.Now, + }, Statistics = new UserStatistics { IsRanked = true, diff --git a/osu.Game/Online/API/Requests/Responses/APIUser.cs b/osu.Game/Online/API/Requests/Responses/APIUser.cs index 56eec19fa1..4a31718f28 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUser.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUser.cs @@ -34,6 +34,19 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"previous_usernames")] public string[] PreviousUsernames; + [JsonProperty(@"rank_highest")] + [CanBeNull] + public UserRankHighest RankHighest; + + public class UserRankHighest + { + [JsonProperty(@"rank")] + public int Rank; + + [JsonProperty(@"updated_at")] + public DateTimeOffset UpdatedAt; + } + [JsonProperty(@"country_code")] private string countryCodeString; From 8d1d65a469c717f29115743ab231ce791930668d Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 9 Feb 2024 15:17:34 -0800 Subject: [PATCH 068/223] Add `ContentTooltipText` to `ProfileValueDisplay` --- .../Header/Components/ProfileValueDisplay.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileValueDisplay.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileValueDisplay.cs index 4b1a0409a3..b2c23458b1 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileValueDisplay.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileValueDisplay.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -13,7 +14,7 @@ namespace osu.Game.Overlays.Profile.Header.Components public partial class ProfileValueDisplay : CompositeDrawable { private readonly OsuSpriteText title; - private readonly OsuSpriteText content; + private readonly ContentText content; public LocalisableString Title { @@ -25,6 +26,11 @@ namespace osu.Game.Overlays.Profile.Header.Components set => content.Text = value; } + public LocalisableString ContentTooltipText + { + set => content.TooltipText = value; + } + public ProfileValueDisplay(bool big = false, int minimumWidth = 60) { AutoSizeAxes = Axes.Both; @@ -38,9 +44,9 @@ namespace osu.Game.Overlays.Profile.Header.Components { Font = OsuFont.GetFont(size: 12) }, - content = new OsuSpriteText + content = new ContentText { - Font = OsuFont.GetFont(size: big ? 30 : 20, weight: FontWeight.Light) + Font = OsuFont.GetFont(size: big ? 30 : 20, weight: FontWeight.Light), }, new Container // Add a minimum size to the FillFlowContainer { @@ -56,5 +62,10 @@ namespace osu.Game.Overlays.Profile.Header.Components title.Colour = colourProvider.Content1; content.Colour = colourProvider.Content2; } + + private partial class ContentText : OsuSpriteText, IHasTooltip + { + public LocalisableString TooltipText { get; set; } + } } } From ae89b89928af680dc921cfc4880241aa787e44ce Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 9 Feb 2024 15:33:49 -0800 Subject: [PATCH 069/223] Centralise global rank display logic to new class --- .../Header/Components/GlobalRankDisplay.cs | 32 +++++++++++++++++++ .../Profile/Header/Components/MainDetails.cs | 9 ++---- osu.Game/Users/UserRankPanel.cs | 6 ++-- 3 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs diff --git a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs new file mode 100644 index 0000000000..290b052e27 --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Users; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public partial class GlobalRankDisplay : ProfileValueDisplay + { + public readonly Bindable UserStatistics = new Bindable(); + + public GlobalRankDisplay() + : base(true) + { + Title = UsersStrings.ShowRankGlobalSimple; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + UserStatistics.BindValueChanged(s => + { + Content = s.NewValue?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + }, true); + } + } +} diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs index b89973c5e5..2aea897451 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private readonly Dictionary scoreRankInfos = new Dictionary(); private ProfileValueDisplay medalInfo = null!; private ProfileValueDisplay ppInfo = null!; - private ProfileValueDisplay detailGlobalRank = null!; + private GlobalRankDisplay detailGlobalRank = null!; private ProfileValueDisplay detailCountryRank = null!; private RankGraph rankGraph = null!; @@ -52,10 +52,7 @@ namespace osu.Game.Overlays.Profile.Header.Components Spacing = new Vector2(20), Children = new Drawable[] { - detailGlobalRank = new ProfileValueDisplay(true) - { - Title = UsersStrings.ShowRankGlobalSimple, - }, + detailGlobalRank = new GlobalRankDisplay(), detailCountryRank = new ProfileValueDisplay(true) { Title = UsersStrings.ShowRankCountrySimple, @@ -142,7 +139,7 @@ namespace osu.Game.Overlays.Profile.Header.Components foreach (var scoreRankInfo in scoreRankInfos) scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; - detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + detailGlobalRank.UserStatistics.Value = user?.Statistics; detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; rankGraph.Statistics.Value = user?.Statistics; diff --git a/osu.Game/Users/UserRankPanel.cs b/osu.Game/Users/UserRankPanel.cs index 84ff3114fc..ba9ef1eee4 100644 --- a/osu.Game/Users/UserRankPanel.cs +++ b/osu.Game/Users/UserRankPanel.cs @@ -27,7 +27,6 @@ namespace osu.Game.Users [Resolved] private IAPIProvider api { get; set; } = null!; - private ProfileValueDisplay globalRankDisplay = null!; private ProfileValueDisplay countryRankDisplay = null!; private readonly IBindable statistics = new Bindable(); @@ -47,7 +46,6 @@ namespace osu.Game.Users statistics.BindTo(api.Statistics); statistics.BindValueChanged(stats => { - globalRankDisplay.Content = stats.NewValue?.GlobalRank?.ToLocalisableString("\\##,##0") ?? "-"; countryRankDisplay.Content = stats.NewValue?.CountryRank?.ToLocalisableString("\\##,##0") ?? "-"; }, true); } @@ -163,9 +161,9 @@ namespace osu.Game.Users { new Drawable[] { - globalRankDisplay = new ProfileValueDisplay(true) + new GlobalRankDisplay { - Title = UsersStrings.ShowRankGlobalSimple, + UserStatistics = { BindTarget = statistics }, }, countryRankDisplay = new ProfileValueDisplay(true) { From ffd0d9bb3994f7471746921f63a3594efc16c49d Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 9 Feb 2024 15:36:15 -0800 Subject: [PATCH 070/223] Add highest rank tooltip to global rank display --- .../Profile/Header/Components/GlobalRankDisplay.cs | 12 ++++++++++++ .../Profile/Header/Components/MainDetails.cs | 1 + osu.Game/Users/UserRankPanel.cs | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs index 290b052e27..dcd4129b45 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs @@ -4,6 +4,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; using osu.Game.Users; @@ -12,6 +13,7 @@ namespace osu.Game.Overlays.Profile.Header.Components public partial class GlobalRankDisplay : ProfileValueDisplay { public readonly Bindable UserStatistics = new Bindable(); + public readonly Bindable User = new Bindable(); public GlobalRankDisplay() : base(true) @@ -27,6 +29,16 @@ namespace osu.Game.Overlays.Profile.Header.Components { Content = s.NewValue?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; }, true); + + // needed as statistics doesn't populate User + User.BindValueChanged(u => + { + var rankHighest = u.NewValue?.RankHighest; + + ContentTooltipText = rankHighest != null + ? UsersStrings.ShowRankHighest(rankHighest.Rank.ToLocalisableString("\\##,##0"), rankHighest.UpdatedAt.ToLocalisableString(@"d MMM yyyy")) + : string.Empty; + }, true); } } } diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs index 2aea897451..ffdf8edc21 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -140,6 +140,7 @@ namespace osu.Game.Overlays.Profile.Header.Components scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; detailGlobalRank.UserStatistics.Value = user?.Statistics; + detailGlobalRank.User.Value = user; detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; rankGraph.Statistics.Value = user?.Statistics; diff --git a/osu.Game/Users/UserRankPanel.cs b/osu.Game/Users/UserRankPanel.cs index ba9ef1eee4..4a00583094 100644 --- a/osu.Game/Users/UserRankPanel.cs +++ b/osu.Game/Users/UserRankPanel.cs @@ -30,6 +30,7 @@ namespace osu.Game.Users private ProfileValueDisplay countryRankDisplay = null!; private readonly IBindable statistics = new Bindable(); + private readonly IBindable user = new Bindable(); public UserRankPanel(APIUser user) : base(user) @@ -48,6 +49,8 @@ namespace osu.Game.Users { countryRankDisplay.Content = stats.NewValue?.CountryRank?.ToLocalisableString("\\##,##0") ?? "-"; }, true); + + user.BindTo(api.LocalUser!); } protected override Drawable CreateLayout() @@ -164,6 +167,9 @@ namespace osu.Game.Users new GlobalRankDisplay { UserStatistics = { BindTarget = statistics }, + // TODO: make highest rank update, as api.LocalUser doesn't update + // maybe move to statistics in api, so `SoloStatisticsWatcher` can update the value + User = { BindTarget = user }, }, countryRankDisplay = new ProfileValueDisplay(true) { From 7b0b39dbaa515e5d2455de0da7e9884d222fc601 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 9 Feb 2024 15:46:14 -0800 Subject: [PATCH 071/223] Fix total play time tooltip area including label --- .../Profile/Header/Components/TotalPlayTime.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/TotalPlayTime.cs b/osu.Game/Overlays/Profile/Header/Components/TotalPlayTime.cs index 08ca59d89b..a3c22d61d2 100644 --- a/osu.Game/Overlays/Profile/Header/Components/TotalPlayTime.cs +++ b/osu.Game/Overlays/Profile/Header/Components/TotalPlayTime.cs @@ -5,25 +5,19 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Header.Components { - public partial class TotalPlayTime : CompositeDrawable, IHasTooltip + public partial class TotalPlayTime : CompositeDrawable { public readonly Bindable User = new Bindable(); - public LocalisableString TooltipText { get; set; } - private ProfileValueDisplay info = null!; public TotalPlayTime() { AutoSizeAxes = Axes.Both; - - TooltipText = "0 hours"; } [BackgroundDependencyLoader] @@ -32,6 +26,7 @@ namespace osu.Game.Overlays.Profile.Header.Components InternalChild = info = new ProfileValueDisplay(minimumWidth: 140) { Title = UsersStrings.ShowStatsPlayTime, + ContentTooltipText = "0 hours", }; User.BindValueChanged(updateTime, true); @@ -40,7 +35,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private void updateTime(ValueChangedEvent user) { int? playTime = user.NewValue?.User.Statistics?.PlayTime; - TooltipText = (playTime ?? 0) / 3600 + " hours"; + info.ContentTooltipText = (playTime ?? 0) / 3600 + " hours"; info.Content = formatTime(playTime); } From 7c04e8bfba9da67118ae3ffc28abe6e2de04191b Mon Sep 17 00:00:00 2001 From: Stoppedpuma <58333920+Stoppedpuma@users.noreply.github.com> Date: Sat, 10 Feb 2024 07:48:24 +0100 Subject: [PATCH 072/223] Alias author to creator Allows "author" to show the results of "creator" --- osu.Game/Screens/Select/FilterQueryParser.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 0d8905347b..f6023c0b61 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -68,6 +68,7 @@ namespace osu.Game.Screens.Select return TryUpdateCriteriaRange(ref criteria.OnlineStatus, op, value, tryParseEnum); case "creator": + case "author": return TryUpdateCriteriaText(ref criteria.Creator, op, value); case "artist": From 5fa54c8c6355aeb85df2daa905d4c02d66995132 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 10 Feb 2024 14:16:45 +0300 Subject: [PATCH 073/223] Fix remaining use cases --- .../Objects/EmptyFreeformHitObject.cs | 2 +- .../Objects/PippidonHitObject.cs | 2 +- .../Objects/EmptyScrollingHitObject.cs | 2 +- .../Objects/PippidonHitObject.cs | 2 +- .../Gameplay/TestSceneDrainingHealthProcessor.cs | 2 +- .../Gameplay/TestSceneDrawableHitObject.cs | 2 +- .../Gameplay/TestSceneScoreProcessor.cs | 14 +++++++------- .../Rulesets/Scoring/ScoreProcessorTest.cs | 15 ++++++--------- 8 files changed, 19 insertions(+), 22 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/EmptyFreeformHitObject.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/EmptyFreeformHitObject.cs index 9cd18d2d9f..e166d09f84 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/EmptyFreeformHitObject.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/EmptyFreeformHitObject.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.EmptyFreeform.Objects { public class EmptyFreeformHitObject : HitObject, IHasPosition { - public override Judgement CreateJudgement() => new Judgement(); + protected override Judgement CreateJudgement() => new Judgement(); public Vector2 Position { get; set; } diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs index 0c22554e82..748e6d3b53 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Pippidon.Objects { public class PippidonHitObject : HitObject, IHasPosition { - public override Judgement CreateJudgement() => new Judgement(); + protected override Judgement CreateJudgement() => new Judgement(); public Vector2 Position { get; set; } diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/EmptyScrollingHitObject.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/EmptyScrollingHitObject.cs index 9b469be496..4564bd1e09 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/EmptyScrollingHitObject.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/EmptyScrollingHitObject.cs @@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.EmptyScrolling.Objects { public class EmptyScrollingHitObject : HitObject { - public override Judgement CreateJudgement() => new Judgement(); + protected override Judgement CreateJudgement() => new Judgement(); } } diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs index 9dd135479f..ed16bce9f6 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs @@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Pippidon.Objects /// public int Lane; - public override Judgement CreateJudgement() => new Judgement(); + protected override Judgement CreateJudgement() => new Judgement(); } } diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs index 584a9e09c0..f0f93f59b5 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs @@ -358,7 +358,7 @@ namespace osu.Game.Tests.Gameplay this.maxResult = maxResult; } - public override Judgement CreateJudgement() => new TestJudgement(maxResult); + protected override Judgement CreateJudgement() => new TestJudgement(maxResult); protected override HitWindows CreateHitWindows() => new HitWindows(); private class TestJudgement : Judgement diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index 73177e36e1..22643feebb 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -175,7 +175,7 @@ namespace osu.Game.Tests.Gameplay var hitObject = new HitObject { StartTime = Time.Current }; lifetimeEntry = new HitObjectLifetimeEntry(hitObject) { - Result = new JudgementResult(hitObject, hitObject.CreateJudgement()) + Result = new JudgementResult(hitObject, hitObject.Judgement) { Type = HitResult.Great } diff --git a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs index 1a644ad600..a428979015 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs @@ -129,10 +129,10 @@ namespace osu.Game.Tests.Gameplay var scoreProcessor = new ScoreProcessor(new OsuRuleset()); scoreProcessor.ApplyBeatmap(beatmap); - scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], beatmap.HitObjects[0].CreateJudgement()) { Type = HitResult.Ok }); - scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[1], beatmap.HitObjects[1].CreateJudgement()) { Type = HitResult.LargeTickHit }); - scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[2], beatmap.HitObjects[2].CreateJudgement()) { Type = HitResult.SmallTickMiss }); - scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[3], beatmap.HitObjects[3].CreateJudgement()) { Type = HitResult.SmallBonus }); + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], beatmap.HitObjects[0].Judgement) { Type = HitResult.Ok }); + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[1], beatmap.HitObjects[1].Judgement) { Type = HitResult.LargeTickHit }); + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[2], beatmap.HitObjects[2].Judgement) { Type = HitResult.SmallTickMiss }); + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[3], beatmap.HitObjects[3].Judgement) { Type = HitResult.SmallBonus }); var score = new ScoreInfo { Ruleset = new OsuRuleset().RulesetInfo }; scoreProcessor.FailScore(score); @@ -169,8 +169,8 @@ namespace osu.Game.Tests.Gameplay Assert.That(scoreProcessor.MinimumAccuracy.Value, Is.EqualTo(0)); Assert.That(scoreProcessor.MaximumAccuracy.Value, Is.EqualTo(1)); - scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], beatmap.HitObjects[0].CreateJudgement()) { Type = HitResult.Ok }); - scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[1], beatmap.HitObjects[1].CreateJudgement()) { Type = HitResult.Great }); + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], beatmap.HitObjects[0].Judgement) { Type = HitResult.Ok }); + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[1], beatmap.HitObjects[1].Judgement) { Type = HitResult.Great }); Assert.That(scoreProcessor.Accuracy.Value, Is.EqualTo((double)(100 + 300) / (2 * 300)).Within(Precision.DOUBLE_EPSILON)); Assert.That(scoreProcessor.MinimumAccuracy.Value, Is.EqualTo((double)(100 + 300) / (4 * 300)).Within(Precision.DOUBLE_EPSILON)); @@ -196,7 +196,7 @@ namespace osu.Game.Tests.Gameplay this.maxResult = maxResult; } - public override Judgement CreateJudgement() => new TestJudgement(maxResult); + protected override Judgement CreateJudgement() => new TestJudgement(maxResult); } } } diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index a3f91fffba..ea43a65825 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -112,7 +112,7 @@ namespace osu.Game.Tests.Rulesets.Scoring for (int i = 0; i < 4; i++) { - var judgementResult = new JudgementResult(fourObjectBeatmap.HitObjects[i], fourObjectBeatmap.HitObjects[i].CreateJudgement()) + var judgementResult = new JudgementResult(fourObjectBeatmap.HitObjects[i], fourObjectBeatmap.HitObjects[i].Judgement) { Type = i == 2 ? minResult : hitResult }; @@ -141,7 +141,7 @@ namespace osu.Game.Tests.Rulesets.Scoring for (int i = 0; i < object_count; ++i) { - var judgementResult = new JudgementResult(largeBeatmap.HitObjects[i], largeBeatmap.HitObjects[i].CreateJudgement()) + var judgementResult = new JudgementResult(largeBeatmap.HitObjects[i], largeBeatmap.HitObjects[i].Judgement) { Type = HitResult.Great }; @@ -325,11 +325,11 @@ namespace osu.Game.Tests.Rulesets.Scoring scoreProcessor = new TestScoreProcessor(); scoreProcessor.ApplyBeatmap(beatmap); - scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], beatmap.HitObjects[0].CreateJudgement()) { Type = HitResult.Great }); + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], beatmap.HitObjects[0].Judgement) { Type = HitResult.Great }); Assert.That(scoreProcessor.Combo.Value, Is.EqualTo(1)); Assert.That(scoreProcessor.Accuracy.Value, Is.EqualTo(1)); - scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[1], beatmap.HitObjects[1].CreateJudgement()) { Type = HitResult.ComboBreak }); + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[1], beatmap.HitObjects[1].Judgement) { Type = HitResult.ComboBreak }); Assert.That(scoreProcessor.Combo.Value, Is.EqualTo(0)); Assert.That(scoreProcessor.Accuracy.Value, Is.EqualTo(1)); } @@ -350,7 +350,7 @@ namespace osu.Game.Tests.Rulesets.Scoring for (int i = 0; i < beatmap.HitObjects.Count; i++) { - scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[i], beatmap.HitObjects[i].CreateJudgement()) + scoreProcessor.ApplyResult(new JudgementResult(beatmap.HitObjects[i], beatmap.HitObjects[i].Judgement) { Type = i == 0 ? HitResult.Miss : HitResult.Great }); @@ -441,10 +441,7 @@ namespace osu.Game.Tests.Rulesets.Scoring private readonly HitResult maxResult; private readonly HitResult? minResult; - public override Judgement CreateJudgement() - { - return new TestJudgement(maxResult, minResult); - } + protected override Judgement CreateJudgement() => new TestJudgement(maxResult, minResult); public TestHitObject(HitResult maxResult, HitResult? minResult = null) { From c5f392c17d92ef061d480782ee195726099dab2e Mon Sep 17 00:00:00 2001 From: tsunyoku Date: Sat, 10 Feb 2024 15:25:03 +0000 Subject: [PATCH 074/223] only compute flashlight in osu! difficulty calculations when required --- .../Difficulty/OsuDifficultyCalculator.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 3b580a5b59..007cd977e5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -40,7 +40,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier; double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier; double speedNotes = ((Speed)skills[2]).RelevantNoteCount(); - double flashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier; + + double flashlightRating = 0.0; + + if (mods.Any(h => h is OsuModFlashlight)) + flashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier; double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; @@ -126,13 +130,17 @@ namespace osu.Game.Rulesets.Osu.Difficulty protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) { - return new Skill[] + var skills = new List { new Aim(mods, true), new Aim(mods, false), - new Speed(mods), - new Flashlight(mods) + new Speed(mods) }; + + if (mods.Any(h => h is OsuModFlashlight)) + skills.Add(new Flashlight(mods)); + + return skills.ToArray(); } protected override Mod[] DifficultyAdjustmentMods => new Mod[] From ca0819cf7a4529fc27a71d9e9e6ff4ff3a25ff3f Mon Sep 17 00:00:00 2001 From: Stoppedpuma <58333920+Stoppedpuma@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:28:16 +0100 Subject: [PATCH 075/223] Alias "mapper" as well --- osu.Game/Screens/Select/FilterQueryParser.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index f6023c0b61..5d3ff1261f 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -69,6 +69,7 @@ namespace osu.Game.Screens.Select case "creator": case "author": + case "mapper": return TryUpdateCriteriaText(ref criteria.Creator, op, value); case "artist": From 36005a5449d4169edf7d77d948d1b0c0b38e2abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Feb 2024 08:33:08 +0100 Subject: [PATCH 076/223] Fix selected legacy skins crashing on zero-length hold notes Closes https://github.com/ppy/osu/issues/27134. --- osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index 07045b76ca..a8200e0144 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -243,7 +243,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy bodySprite.FillMode = FillMode.Stretch; // i dunno this looks about right?? - bodySprite.Scale = new Vector2(1, scaleDirection * 32800 / sprite.DrawHeight); + // the guard against zero draw height is intended for zero-length hold notes. yes, such cases have been spotted in the wild. + if (sprite.DrawHeight > 0) + bodySprite.Scale = new Vector2(1, scaleDirection * 32800 / sprite.DrawHeight); } break; From 2ae616a88ea17cc1dc03ab6c0dfa46aeb20f93ee Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 12 Feb 2024 12:29:31 +0300 Subject: [PATCH 077/223] Combine other cases of displaying dash in scores PP --- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 2 +- .../BeatmapSet/Scores/TopScoreStatisticsSection.cs | 2 +- .../Profile/Sections/Ranks/DrawableProfileScore.cs | 10 +++++----- .../Drawables/UnrankedPerformancePointsPlaceholder.cs | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index c8ecb38c86..9dd0e26da2 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -181,7 +181,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores if (showPerformancePoints) { if (!score.Ranked) - content.Add(new UnrankedPerformancePointsPlaceholder { Font = OsuFont.GetFont(size: text_size) }); + content.Add(new UnrankedPerformancePointsPlaceholder(ScoresStrings.StatusNoPp) { Font = OsuFont.GetFont(size: text_size) }); else if (score.PP == null) content.Add(new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(text_size) }); else diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs index 488b99d620..4aad3cf953 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores ppColumn.Alpha = value.BeatmapInfo!.Status.GrantsPerformancePoints() ? 1 : 0; if (!value.Ranked) - ppColumn.Drawable = new UnrankedPerformancePointsPlaceholder { Font = smallFont }; + ppColumn.Drawable = new UnrankedPerformancePointsPlaceholder(ScoresStrings.StatusNoPp) { Font = smallFont }; else if (value.PP is not double pp) ppColumn.Drawable = new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(smallFont.Size) }; else diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index d1988956be..1211d65816 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -14,6 +14,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; @@ -243,20 +244,19 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks if (Score.Beatmap?.Status.GrantsPerformancePoints() != true) { - return new OsuSpriteText + return new UnrankedPerformancePointsPlaceholder(UsersStrings.ShowExtraTopRanksNotRanked) { Font = OsuFont.GetFont(weight: FontWeight.Bold), - Text = "-", - Colour = colourProvider.Highlight1 + Colour = colourProvider.Highlight1, }; } if (!Score.Ranked) { - return new UnrankedPerformancePointsPlaceholder + return new UnrankedPerformancePointsPlaceholder(ScoresStrings.StatusNoPp) { Font = OsuFont.GetFont(weight: FontWeight.Bold), - Colour = colourProvider.Highlight1 + Colour = colourProvider.Highlight1, }; } diff --git a/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs b/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs index c5c190e1a1..0097497ef1 100644 --- a/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs +++ b/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs @@ -5,22 +5,22 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Resources.Localisation.Web; namespace osu.Game.Scoring.Drawables { /// - /// A placeholder used in PP columns for scores that do not award PP. + /// A placeholder used in PP columns for scores that do not award PP due to a reason specified by . /// public partial class UnrankedPerformancePointsPlaceholder : SpriteText, IHasTooltip { - public LocalisableString TooltipText => ScoresStrings.StatusNoPp; + public LocalisableString TooltipText { get; } - public UnrankedPerformancePointsPlaceholder() + public UnrankedPerformancePointsPlaceholder(LocalisableString tooltipText) { Anchor = Anchor.Centre; Origin = Anchor.Centre; Text = "-"; + TooltipText = tooltipText; } } } From 80b14f1aaef3627935873cdc0be2649d588d4f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 7 May 2023 20:06:07 +0200 Subject: [PATCH 078/223] Add test coverage for beatmap confusion scenarios --- .../BeatmapUpdaterMetadataLookupTest.cs | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs b/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs index 84195f1e7c..e6c06f7aec 100644 --- a/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs +++ b/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs @@ -193,5 +193,110 @@ namespace osu.Game.Tests.Beatmaps Assert.That(beatmap.OnlineID, Is.EqualTo(123456)); } + + [Test] + public void TestReturnedMetadataHasDifferentOnlineID([Values] bool preferOnlineFetch) + { + var lookupResult = new OnlineBeatmapMetadata { BeatmapID = 654321, BeatmapStatus = BeatmapOnlineStatus.Ranked }; + + var targetMock = preferOnlineFetch ? apiMetadataSourceMock : localCachedMetadataSourceMock; + targetMock.Setup(src => src.Available).Returns(true); + targetMock.Setup(src => src.TryLookup(It.IsAny(), out lookupResult)) + .Returns(true); + + var beatmap = new BeatmapInfo { OnlineID = 123456 }; + var beatmapSet = new BeatmapSetInfo(beatmap.Yield()); + beatmap.BeatmapSet = beatmapSet; + + metadataLookup.Update(beatmapSet, preferOnlineFetch); + + Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.None)); + Assert.That(beatmap.OnlineID, Is.EqualTo(-1)); + } + + [Test] + public void TestMetadataLookupForBeatmapWithoutPopulatedIDAndCorrectHash([Values] bool preferOnlineFetch) + { + var lookupResult = new OnlineBeatmapMetadata + { + BeatmapID = 654321, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + MD5Hash = @"deadbeef", + }; + + var targetMock = preferOnlineFetch ? apiMetadataSourceMock : localCachedMetadataSourceMock; + targetMock.Setup(src => src.Available).Returns(true); + targetMock.Setup(src => src.TryLookup(It.IsAny(), out lookupResult)) + .Returns(true); + + var beatmap = new BeatmapInfo + { + MD5Hash = @"deadbeef" + }; + var beatmapSet = new BeatmapSetInfo(beatmap.Yield()); + beatmap.BeatmapSet = beatmapSet; + + metadataLookup.Update(beatmapSet, preferOnlineFetch); + + Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.Ranked)); + Assert.That(beatmap.OnlineID, Is.EqualTo(654321)); + } + + [Test] + public void TestMetadataLookupForBeatmapWithoutPopulatedIDAndIncorrectHash([Values] bool preferOnlineFetch) + { + var lookupResult = new OnlineBeatmapMetadata + { + BeatmapID = 654321, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + MD5Hash = @"cafebabe", + }; + + var targetMock = preferOnlineFetch ? apiMetadataSourceMock : localCachedMetadataSourceMock; + targetMock.Setup(src => src.Available).Returns(true); + targetMock.Setup(src => src.TryLookup(It.IsAny(), out lookupResult)) + .Returns(true); + + var beatmap = new BeatmapInfo + { + MD5Hash = @"deadbeef" + }; + var beatmapSet = new BeatmapSetInfo(beatmap.Yield()); + beatmap.BeatmapSet = beatmapSet; + + metadataLookup.Update(beatmapSet, preferOnlineFetch); + + Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.None)); + Assert.That(beatmap.OnlineID, Is.EqualTo(-1)); + } + + [Test] + public void TestReturnedMetadataHasDifferentHash([Values] bool preferOnlineFetch) + { + var lookupResult = new OnlineBeatmapMetadata + { + BeatmapID = 654321, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + MD5Hash = @"deadbeef" + }; + + var targetMock = preferOnlineFetch ? apiMetadataSourceMock : localCachedMetadataSourceMock; + targetMock.Setup(src => src.Available).Returns(true); + targetMock.Setup(src => src.TryLookup(It.IsAny(), out lookupResult)) + .Returns(true); + + var beatmap = new BeatmapInfo + { + OnlineID = 654321, + MD5Hash = @"cafebabe", + }; + var beatmapSet = new BeatmapSetInfo(beatmap.Yield()); + beatmap.BeatmapSet = beatmapSet; + + metadataLookup.Update(beatmapSet, preferOnlineFetch); + + Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.None)); + Assert.That(beatmap.OnlineID, Is.EqualTo(654321)); + } } } From 834db989f721a38bb03cf8f8c1f9d24e4e5f0ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Feb 2024 11:03:08 +0100 Subject: [PATCH 079/223] Add more test coverage for more failure --- .../BeatmapUpdaterMetadataLookupTest.cs | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs b/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs index e6c06f7aec..fe9d15a89d 100644 --- a/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs +++ b/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs @@ -298,5 +298,59 @@ namespace osu.Game.Tests.Beatmaps Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.None)); Assert.That(beatmap.OnlineID, Is.EqualTo(654321)); } + + [Test] + public void TestPartiallyModifiedSet([Values] bool preferOnlineFetch) + { + var firstResult = new OnlineBeatmapMetadata + { + BeatmapID = 654321, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + BeatmapSetStatus = BeatmapOnlineStatus.Ranked, + MD5Hash = @"cafebabe" + }; + var secondResult = new OnlineBeatmapMetadata + { + BeatmapID = 666666, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + BeatmapSetStatus = BeatmapOnlineStatus.Ranked, + MD5Hash = @"dededede" + }; + + var targetMock = preferOnlineFetch ? apiMetadataSourceMock : localCachedMetadataSourceMock; + targetMock.Setup(src => src.Available).Returns(true); + targetMock.Setup(src => src.TryLookup(It.Is(bi => bi.OnlineID == 654321), out firstResult)) + .Returns(true); + targetMock.Setup(src => src.TryLookup(It.Is(bi => bi.OnlineID == 666666), out secondResult)) + .Returns(true); + + var firstBeatmap = new BeatmapInfo + { + OnlineID = 654321, + MD5Hash = @"cafebabe", + }; + var secondBeatmap = new BeatmapInfo + { + OnlineID = 666666, + MD5Hash = @"deadbeef" + }; + var beatmapSet = new BeatmapSetInfo(new[] + { + firstBeatmap, + secondBeatmap + }); + firstBeatmap.BeatmapSet = beatmapSet; + secondBeatmap.BeatmapSet = beatmapSet; + + metadataLookup.Update(beatmapSet, preferOnlineFetch); + + Assert.That(firstBeatmap.Status, Is.EqualTo(BeatmapOnlineStatus.Ranked)); + Assert.That(firstBeatmap.OnlineID, Is.EqualTo(654321)); + + Assert.That(secondBeatmap.Status, Is.EqualTo(BeatmapOnlineStatus.None)); + Assert.That(secondBeatmap.OnlineID, Is.EqualTo(666666)); + + Assert.That(beatmapSet.Status, Is.EqualTo(BeatmapOnlineStatus.None)); + } } } From 4f0ae4197a456dde07cf4aa9868026ef0d9d0918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Feb 2024 11:12:01 +0100 Subject: [PATCH 080/223] Refuse to apply online metadata in the most dodgy scenarios --- osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index b32310990c..13823147b0 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -43,7 +43,7 @@ namespace osu.Game.Beatmaps if (!tryLookup(beatmapInfo, preferOnlineFetch, out var res)) continue; - if (res == null) + if (res == null || shouldDiscardLookupResult(res, beatmapInfo)) { beatmapInfo.ResetOnlineInfo(); continue; @@ -72,6 +72,17 @@ namespace osu.Game.Beatmaps } } + private bool shouldDiscardLookupResult(OnlineBeatmapMetadata result, BeatmapInfo beatmapInfo) + { + if (beatmapInfo.OnlineID > 0 && result.BeatmapID != beatmapInfo.OnlineID) + return true; + + if (beatmapInfo.OnlineID == -1 && result.MD5Hash != beatmapInfo.MD5Hash) + return true; + + return false; + } + /// /// Attempts to retrieve the for the given . /// From 87702b331271d1291ad65d0b4399408dbbf5244e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Feb 2024 11:35:11 +0100 Subject: [PATCH 081/223] Only check online matching when determining whether to save online metadata After https://github.com/ppy/osu/pull/23362 I'm not sure the `LocallyModified` check is doing anything useful. It was confusing me really hard when trying to parse this logic, and it can misbehave (as `None` will also pass the check). --- osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index 13823147b0..f46ce11663 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -57,13 +57,13 @@ namespace osu.Game.Beatmaps beatmapInfo.BeatmapSet.OnlineID = res.BeatmapSetID; // Some metadata should only be applied if there's no local changes. - if (shouldSaveOnlineMetadata(beatmapInfo)) + if (beatmapInfo.MatchesOnlineVersion) { beatmapInfo.Status = res.BeatmapStatus; beatmapInfo.Metadata.Author.OnlineID = res.AuthorID; } - if (beatmapInfo.BeatmapSet.Beatmaps.All(shouldSaveOnlineMetadata)) + if (beatmapInfo.BeatmapSet.Beatmaps.All(b => b.MatchesOnlineVersion)) { beatmapInfo.BeatmapSet.Status = res.BeatmapSetStatus ?? BeatmapOnlineStatus.None; beatmapInfo.BeatmapSet.DateRanked = res.DateRanked; @@ -115,12 +115,6 @@ namespace osu.Game.Beatmaps return false; } - /// - /// Check whether the provided beatmap is in a state where online "ranked" status metadata should be saved against it. - /// Handles the case where a user may have locally modified a beatmap in the editor and expects the local status to stick. - /// - private static bool shouldSaveOnlineMetadata(BeatmapInfo beatmapInfo) => beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified; - public void Dispose() { apiMetadataSource.Dispose(); From 133e61a1b223156b986eb45c45fa7e1b16aefefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Feb 2024 11:38:13 +0100 Subject: [PATCH 082/223] Add another test for even more failure --- .../BeatmapUpdaterMetadataLookupTest.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs b/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs index fe9d15a89d..74812236bf 100644 --- a/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs +++ b/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs @@ -352,5 +352,58 @@ namespace osu.Game.Tests.Beatmaps Assert.That(beatmapSet.Status, Is.EqualTo(BeatmapOnlineStatus.None)); } + + [Test] + public void TestPartiallyMaliciousSet([Values] bool preferOnlineFetch) + { + var firstResult = new OnlineBeatmapMetadata + { + BeatmapID = 654321, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + BeatmapSetStatus = BeatmapOnlineStatus.Ranked, + MD5Hash = @"cafebabe" + }; + var secondResult = new OnlineBeatmapMetadata + { + BeatmapStatus = BeatmapOnlineStatus.Ranked, + BeatmapSetStatus = BeatmapOnlineStatus.Ranked, + MD5Hash = @"dededede" + }; + + var targetMock = preferOnlineFetch ? apiMetadataSourceMock : localCachedMetadataSourceMock; + targetMock.Setup(src => src.Available).Returns(true); + targetMock.Setup(src => src.TryLookup(It.Is(bi => bi.OnlineID == 654321), out firstResult)) + .Returns(true); + targetMock.Setup(src => src.TryLookup(It.Is(bi => bi.OnlineID == 666666), out secondResult)) + .Returns(true); + + var firstBeatmap = new BeatmapInfo + { + OnlineID = 654321, + MD5Hash = @"cafebabe", + }; + var secondBeatmap = new BeatmapInfo + { + OnlineID = 666666, + MD5Hash = @"deadbeef" + }; + var beatmapSet = new BeatmapSetInfo(new[] + { + firstBeatmap, + secondBeatmap + }); + firstBeatmap.BeatmapSet = beatmapSet; + secondBeatmap.BeatmapSet = beatmapSet; + + metadataLookup.Update(beatmapSet, preferOnlineFetch); + + Assert.That(firstBeatmap.Status, Is.EqualTo(BeatmapOnlineStatus.Ranked)); + Assert.That(firstBeatmap.OnlineID, Is.EqualTo(654321)); + + Assert.That(secondBeatmap.Status, Is.EqualTo(BeatmapOnlineStatus.None)); + Assert.That(secondBeatmap.OnlineID, Is.EqualTo(-1)); + + Assert.That(beatmapSet.Status, Is.EqualTo(BeatmapOnlineStatus.None)); + } } } From 138fea8c387190605ba5099b9d3385f4bb6903ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Feb 2024 11:47:30 +0100 Subject: [PATCH 083/223] Only apply set-level metadata after all difficulties have been processed --- .../Beatmaps/BeatmapUpdaterMetadataLookup.cs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index f46ce11663..f395718a93 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using osu.Framework.Platform; @@ -38,6 +39,8 @@ namespace osu.Game.Beatmaps /// Whether metadata from an online source should be preferred. If true, the local cache will be skipped to ensure the freshest data state possible. public void Update(BeatmapSetInfo beatmapSet, bool preferOnlineFetch) { + var lookupResults = new List(); + foreach (var beatmapInfo in beatmapSet.Beatmaps) { if (!tryLookup(beatmapInfo, preferOnlineFetch, out var res)) @@ -46,9 +49,12 @@ namespace osu.Game.Beatmaps if (res == null || shouldDiscardLookupResult(res, beatmapInfo)) { beatmapInfo.ResetOnlineInfo(); + lookupResults.Add(null); // mark lookup failure continue; } + lookupResults.Add(res); + beatmapInfo.OnlineID = res.BeatmapID; beatmapInfo.OnlineMD5Hash = res.MD5Hash; beatmapInfo.LastOnlineUpdate = res.LastUpdated; @@ -62,13 +68,17 @@ namespace osu.Game.Beatmaps beatmapInfo.Status = res.BeatmapStatus; beatmapInfo.Metadata.Author.OnlineID = res.AuthorID; } + } - if (beatmapInfo.BeatmapSet.Beatmaps.All(b => b.MatchesOnlineVersion)) - { - beatmapInfo.BeatmapSet.Status = res.BeatmapSetStatus ?? BeatmapOnlineStatus.None; - beatmapInfo.BeatmapSet.DateRanked = res.DateRanked; - beatmapInfo.BeatmapSet.DateSubmitted = res.DateSubmitted; - } + if (beatmapSet.Beatmaps.All(b => b.MatchesOnlineVersion) + && lookupResults.All(r => r != null) + && lookupResults.Select(r => r!.BeatmapSetID).Distinct().Count() == 1) + { + var representative = lookupResults.First()!; + + beatmapSet.Status = representative.BeatmapSetStatus ?? BeatmapOnlineStatus.None; + beatmapSet.DateRanked = representative.DateRanked; + beatmapSet.DateSubmitted = representative.DateSubmitted; } } From e5e0b0e38585f292ce1775f0d4016e9ed55ebec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Feb 2024 11:55:30 +0100 Subject: [PATCH 084/223] Add test coverage for correct setting of beatmap set status --- .../BeatmapUpdaterMetadataLookupTest.cs | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs b/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs index 74812236bf..11c4c54ea6 100644 --- a/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs +++ b/osu.Game.Tests/Beatmaps/BeatmapUpdaterMetadataLookupTest.cs @@ -28,7 +28,12 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestLocalCacheQueriedFirst() { - var localLookupResult = new OnlineBeatmapMetadata { BeatmapID = 123456, BeatmapStatus = BeatmapOnlineStatus.Ranked }; + var localLookupResult = new OnlineBeatmapMetadata + { + BeatmapID = 123456, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + BeatmapSetStatus = BeatmapOnlineStatus.Ranked, + }; localCachedMetadataSourceMock.Setup(src => src.Available).Returns(true); localCachedMetadataSourceMock.Setup(src => src.TryLookup(It.IsAny(), out localLookupResult)) .Returns(true); @@ -42,6 +47,7 @@ namespace osu.Game.Tests.Beatmaps metadataLookup.Update(beatmapSet, preferOnlineFetch: false); Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.Ranked)); + Assert.That(beatmapSet.Status, Is.EqualTo(BeatmapOnlineStatus.Ranked)); localCachedMetadataSourceMock.Verify(src => src.TryLookup(beatmap, out It.Ref.IsAny!), Times.Once); apiMetadataSourceMock.Verify(src => src.TryLookup(It.IsAny(), out It.Ref.IsAny!), Times.Never); } @@ -54,7 +60,12 @@ namespace osu.Game.Tests.Beatmaps localCachedMetadataSourceMock.Setup(src => src.TryLookup(It.IsAny(), out localLookupResult)) .Returns(false); - var onlineLookupResult = new OnlineBeatmapMetadata { BeatmapID = 123456, BeatmapStatus = BeatmapOnlineStatus.Ranked }; + var onlineLookupResult = new OnlineBeatmapMetadata + { + BeatmapID = 123456, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + BeatmapSetStatus = BeatmapOnlineStatus.Ranked, + }; apiMetadataSourceMock.Setup(src => src.Available).Returns(true); apiMetadataSourceMock.Setup(src => src.TryLookup(It.IsAny(), out onlineLookupResult)) .Returns(true); @@ -66,6 +77,7 @@ namespace osu.Game.Tests.Beatmaps metadataLookup.Update(beatmapSet, preferOnlineFetch: false); Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.Ranked)); + Assert.That(beatmapSet.Status, Is.EqualTo(BeatmapOnlineStatus.Ranked)); localCachedMetadataSourceMock.Verify(src => src.TryLookup(beatmap, out It.Ref.IsAny!), Times.Once); apiMetadataSourceMock.Verify(src => src.TryLookup(beatmap, out It.Ref.IsAny!), Times.Once); } @@ -73,12 +85,22 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestPreferOnlineFetch() { - var localLookupResult = new OnlineBeatmapMetadata { BeatmapID = 123456, BeatmapStatus = BeatmapOnlineStatus.Ranked }; + var localLookupResult = new OnlineBeatmapMetadata + { + BeatmapID = 123456, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + BeatmapSetStatus = BeatmapOnlineStatus.Ranked, + }; localCachedMetadataSourceMock.Setup(src => src.Available).Returns(true); localCachedMetadataSourceMock.Setup(src => src.TryLookup(It.IsAny(), out localLookupResult)) .Returns(true); - var onlineLookupResult = new OnlineBeatmapMetadata { BeatmapID = 123456, BeatmapStatus = BeatmapOnlineStatus.Graveyard }; + var onlineLookupResult = new OnlineBeatmapMetadata + { + BeatmapID = 123456, + BeatmapStatus = BeatmapOnlineStatus.Graveyard, + BeatmapSetStatus = BeatmapOnlineStatus.Graveyard, + }; apiMetadataSourceMock.Setup(src => src.Available).Returns(true); apiMetadataSourceMock.Setup(src => src.TryLookup(It.IsAny(), out onlineLookupResult)) .Returns(true); @@ -90,6 +112,7 @@ namespace osu.Game.Tests.Beatmaps metadataLookup.Update(beatmapSet, preferOnlineFetch: true); Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.Graveyard)); + Assert.That(beatmapSet.Status, Is.EqualTo(BeatmapOnlineStatus.Graveyard)); localCachedMetadataSourceMock.Verify(src => src.TryLookup(beatmap, out It.Ref.IsAny!), Times.Never); apiMetadataSourceMock.Verify(src => src.TryLookup(beatmap, out It.Ref.IsAny!), Times.Once); } @@ -97,7 +120,12 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestPreferOnlineFetchFallsBackToLocalCacheIfOnlineSourceUnavailable() { - var localLookupResult = new OnlineBeatmapMetadata { BeatmapID = 123456, BeatmapStatus = BeatmapOnlineStatus.Ranked }; + var localLookupResult = new OnlineBeatmapMetadata + { + BeatmapID = 123456, + BeatmapStatus = BeatmapOnlineStatus.Ranked, + BeatmapSetStatus = BeatmapOnlineStatus.Ranked, + }; localCachedMetadataSourceMock.Setup(src => src.Available).Returns(true); localCachedMetadataSourceMock.Setup(src => src.TryLookup(It.IsAny(), out localLookupResult)) .Returns(true); @@ -111,6 +139,7 @@ namespace osu.Game.Tests.Beatmaps metadataLookup.Update(beatmapSet, preferOnlineFetch: true); Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.Ranked)); + Assert.That(beatmapSet.Status, Is.EqualTo(BeatmapOnlineStatus.Ranked)); localCachedMetadataSourceMock.Verify(src => src.TryLookup(beatmap, out It.Ref.IsAny!), Times.Once); apiMetadataSourceMock.Verify(src => src.TryLookup(beatmap, out It.Ref.IsAny!), Times.Never); } @@ -135,6 +164,7 @@ namespace osu.Game.Tests.Beatmaps metadataLookup.Update(beatmapSet, preferOnlineFetch: false); Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.None)); + Assert.That(beatmapSet.Status, Is.EqualTo(BeatmapOnlineStatus.None)); Assert.That(beatmap.OnlineID, Is.EqualTo(-1)); localCachedMetadataSourceMock.Verify(src => src.TryLookup(beatmap, out It.Ref.IsAny!), Times.Once); apiMetadataSourceMock.Verify(src => src.TryLookup(beatmap, out It.Ref.IsAny!), Times.Once); @@ -163,6 +193,7 @@ namespace osu.Game.Tests.Beatmaps metadataLookup.Update(beatmapSet, preferOnlineFetch); Assert.That(beatmap.Status, Is.EqualTo(BeatmapOnlineStatus.None)); + Assert.That(beatmapSet.Status, Is.EqualTo(BeatmapOnlineStatus.None)); Assert.That(beatmap.OnlineID, Is.EqualTo(123456)); } From 581ae2f679a00e98ea3e773a9c0c59494b9be8e5 Mon Sep 17 00:00:00 2001 From: tsunyoku Date: Mon, 12 Feb 2024 12:51:35 +0000 Subject: [PATCH 085/223] handle key presses when watching legacy relax replays --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 24 +++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 3679425389..55d8b6f55f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -38,12 +38,17 @@ namespace osu.Game.Rulesets.Osu.Mods private ReplayState state = null!; private double lastStateChangeTime; + private DrawableOsuRuleset ruleset = null!; + private bool hasReplay; + private bool legacyReplay; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { + ruleset = (DrawableOsuRuleset)drawableRuleset; + // grab the input manager for future use. - osuInputManager = ((DrawableOsuRuleset)drawableRuleset).KeyBindingInputManager; + osuInputManager = ruleset.KeyBindingInputManager; } public void ApplyToPlayer(Player player) @@ -51,6 +56,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (osuInputManager.ReplayInputHandler != null) { hasReplay = true; + legacyReplay = ruleset.ReplayScore.ScoreInfo.IsLegacyScore; return; } @@ -59,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void Update(Playfield playfield) { - if (hasReplay) + if (hasReplay && !legacyReplay) return; bool requiresHold = false; @@ -125,6 +131,20 @@ namespace osu.Game.Rulesets.Osu.Mods isDownState = down; lastStateChangeTime = time; + // legacy replays do not contain key-presses with Relax mod, so they need to be triggered by themselves. + if (legacyReplay) + { + if (!down) + { + osuInputManager.KeyBindingContainer.TriggerReleased(wasLeft ? OsuAction.RightButton : OsuAction.LeftButton); + return; + } + + osuInputManager.KeyBindingContainer.TriggerPressed(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + wasLeft = !wasLeft; + return; + } + state = new ReplayState { PressedActions = new List() From 96711eb185c0692868dc924b6b4368e8e1a8735d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 12 Feb 2024 18:02:34 +0100 Subject: [PATCH 086/223] Add test coverage --- .../NonVisual/Filtering/FilterQueryParserTest.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 739a72df08..899be1e06c 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -274,10 +274,12 @@ namespace osu.Game.Tests.NonVisual.Filtering Assert.IsTrue(filterCriteria.OnlineStatus.IsUpperInclusive); } - [Test] - public void TestApplyCreatorQueries() + [TestCase("creator")] + [TestCase("author")] + [TestCase("mapper")] + public void TestApplyCreatorQueries(string keyword) { - const string query = "beatmap specifically by creator=my_fav"; + string query = $"beatmap specifically by {keyword}=my_fav"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual("beatmap specifically by", filterCriteria.SearchText.Trim()); From 2a02566283f831b469a2b37a4a645aae2cb07bc3 Mon Sep 17 00:00:00 2001 From: tsunyoku Date: Mon, 12 Feb 2024 17:45:00 +0000 Subject: [PATCH 087/223] refactor `down` and `wasLeft` management into respective `PressHandler` classes --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 67 +++++++++++++++++------ 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 55d8b6f55f..47b7e543d8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -39,6 +39,7 @@ namespace osu.Game.Rulesets.Osu.Mods private double lastStateChangeTime; private DrawableOsuRuleset ruleset = null!; + private PressHandler pressHandler = null!; private bool hasReplay; private bool legacyReplay; @@ -56,10 +57,16 @@ namespace osu.Game.Rulesets.Osu.Mods if (osuInputManager.ReplayInputHandler != null) { hasReplay = true; + + Debug.Assert(ruleset.ReplayScore != null); legacyReplay = ruleset.ReplayScore.ScoreInfo.IsLegacyScore; + + pressHandler = new LegacyReplayPressHandler(this); + return; } + pressHandler = new PressHandler(this); osuInputManager.AllowGameplayInputs = false; } @@ -131,20 +138,6 @@ namespace osu.Game.Rulesets.Osu.Mods isDownState = down; lastStateChangeTime = time; - // legacy replays do not contain key-presses with Relax mod, so they need to be triggered by themselves. - if (legacyReplay) - { - if (!down) - { - osuInputManager.KeyBindingContainer.TriggerReleased(wasLeft ? OsuAction.RightButton : OsuAction.LeftButton); - return; - } - - osuInputManager.KeyBindingContainer.TriggerPressed(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); - wasLeft = !wasLeft; - return; - } - state = new ReplayState { PressedActions = new List() @@ -152,11 +145,53 @@ namespace osu.Game.Rulesets.Osu.Mods if (down) { - state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + pressHandler.HandlePress(wasLeft); wasLeft = !wasLeft; } + else + { + pressHandler.HandleRelease(wasLeft); + } + } + } - state.Apply(osuInputManager.CurrentState, osuInputManager); + private class PressHandler + { + protected readonly OsuModRelax Mod; + + public PressHandler(OsuModRelax mod) + { + Mod = mod; + } + + public virtual void HandlePress(bool wasLeft) + { + Mod.state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + Mod.state.Apply(Mod.osuInputManager.CurrentState, Mod.osuInputManager); + } + + public virtual void HandleRelease(bool wasLeft) + { + Mod.state.Apply(Mod.osuInputManager.CurrentState, Mod.osuInputManager); + } + } + + // legacy replays do not contain key-presses with Relax mod, so they need to be triggered by themselves. + private class LegacyReplayPressHandler : PressHandler + { + public LegacyReplayPressHandler(OsuModRelax mod) + : base(mod) + { + } + + public override void HandlePress(bool wasLeft) + { + Mod.osuInputManager.KeyBindingContainer.TriggerPressed(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + } + + public override void HandleRelease(bool wasLeft) + { + Mod.osuInputManager.KeyBindingContainer.TriggerReleased(wasLeft ? OsuAction.RightButton : OsuAction.LeftButton); } } } From cc733ea809f3eb1d0887bf8c92605581fd21a9b3 Mon Sep 17 00:00:00 2001 From: tsunyoku Date: Mon, 12 Feb 2024 18:00:05 +0000 Subject: [PATCH 088/223] add inline comment for supposedly backwards ternary --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 47b7e543d8..a5643e5b49 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -191,6 +191,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override void HandleRelease(bool wasLeft) { + // this intentionally releases right when `wasLeft` is true because `wasLeft` is set at point of press and not at point of release Mod.osuInputManager.KeyBindingContainer.TriggerReleased(wasLeft ? OsuAction.RightButton : OsuAction.LeftButton); } } From 4f0f07d55a45be5ff93e271d3adfde3b71945138 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 12 Feb 2024 21:30:10 +0300 Subject: [PATCH 089/223] Remove placeholder classes and inline everything --- .../Graphics/Sprites/SpriteIconWithTooltip.cs | 14 +++++++ .../Graphics/Sprites/SpriteTextWithTooltip.cs | 13 +++++++ .../Overlays/BeatmapSet/Scores/ScoreTable.cs | 20 ++++++++-- .../Scores/TopScoreStatisticsSection.cs | 19 +++++++-- .../Sections/Ranks/DrawableProfileScore.cs | 39 +++++++++++++++---- ...UnprocessedPerformancePointsPlaceholder.cs | 27 ------------- .../UnrankedPerformancePointsPlaceholder.cs | 26 ------------- 7 files changed, 91 insertions(+), 67 deletions(-) create mode 100644 osu.Game/Graphics/Sprites/SpriteIconWithTooltip.cs create mode 100644 osu.Game/Graphics/Sprites/SpriteTextWithTooltip.cs delete mode 100644 osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs delete mode 100644 osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs diff --git a/osu.Game/Graphics/Sprites/SpriteIconWithTooltip.cs b/osu.Game/Graphics/Sprites/SpriteIconWithTooltip.cs new file mode 100644 index 0000000000..572a17571b --- /dev/null +++ b/osu.Game/Graphics/Sprites/SpriteIconWithTooltip.cs @@ -0,0 +1,14 @@ +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; + +namespace osu.Game.Graphics.Sprites +{ + /// + /// A with a publicly settable tooltip text. + /// + public partial class SpriteIconWithTooltip : SpriteIcon, IHasTooltip + { + public LocalisableString TooltipText { get; set; } + } +} diff --git a/osu.Game/Graphics/Sprites/SpriteTextWithTooltip.cs b/osu.Game/Graphics/Sprites/SpriteTextWithTooltip.cs new file mode 100644 index 0000000000..db98e8ba57 --- /dev/null +++ b/osu.Game/Graphics/Sprites/SpriteTextWithTooltip.cs @@ -0,0 +1,13 @@ +using osu.Framework.Graphics.Cursor; +using osu.Framework.Localisation; + +namespace osu.Game.Graphics.Sprites +{ + /// + /// An with a publicly settable tooltip text. + /// + internal partial class SpriteTextWithTooltip : OsuSpriteText, IHasTooltip + { + public LocalisableString TooltipText { get; set; } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 9dd0e26da2..7a817c43eb 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -23,9 +23,9 @@ using osuTK.Graphics; using osu.Framework.Localisation; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; -using osu.Game.Scoring.Drawables; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -181,9 +181,23 @@ namespace osu.Game.Overlays.BeatmapSet.Scores if (showPerformancePoints) { if (!score.Ranked) - content.Add(new UnrankedPerformancePointsPlaceholder(ScoresStrings.StatusNoPp) { Font = OsuFont.GetFont(size: text_size) }); + { + content.Add(new SpriteTextWithTooltip + { + Text = "-", + Font = OsuFont.GetFont(size: text_size), + TooltipText = ScoresStrings.StatusNoPp + }); + } else if (score.PP == null) - content.Add(new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(text_size) }); + { + content.Add(new SpriteIconWithTooltip + { + Icon = FontAwesome.Solid.Sync, + Size = new Vector2(text_size), + TooltipText = ScoresStrings.StatusProcessing, + }); + } else content.Add(new StatisticText(score.PP, format: @"N0")); } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs index 4aad3cf953..17704f63ee 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs @@ -22,7 +22,6 @@ using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osu.Game.Scoring; -using osu.Game.Scoring.Drawables; using osuTK; namespace osu.Game.Overlays.BeatmapSet.Scores @@ -126,9 +125,23 @@ namespace osu.Game.Overlays.BeatmapSet.Scores ppColumn.Alpha = value.BeatmapInfo!.Status.GrantsPerformancePoints() ? 1 : 0; if (!value.Ranked) - ppColumn.Drawable = new UnrankedPerformancePointsPlaceholder(ScoresStrings.StatusNoPp) { Font = smallFont }; + { + ppColumn.Drawable = new SpriteTextWithTooltip + { + Text = "-", + Font = smallFont, + TooltipText = ScoresStrings.StatusNoPp + }; + } else if (value.PP is not double pp) - ppColumn.Drawable = new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(smallFont.Size) }; + { + ppColumn.Drawable = new SpriteIconWithTooltip + { + Icon = FontAwesome.Solid.Sync, + Size = new Vector2(smallFont.Size), + TooltipText = ScoresStrings.StatusProcessing, + }; + } else ppColumn.Text = pp.ToLocalisableString(@"N0"); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index 1211d65816..63afca8b74 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -8,6 +8,7 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; @@ -18,7 +19,6 @@ using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; -using osu.Game.Scoring.Drawables; using osu.Game.Utils; using osuTK; @@ -214,6 +214,8 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks private Drawable createDrawablePerformance() { + var font = OsuFont.GetFont(weight: FontWeight.Bold); + if (Score.PP.HasValue) { return new FillFlowContainer @@ -226,7 +228,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Font = OsuFont.GetFont(weight: FontWeight.Bold), + Font = font, Text = $"{Score.PP:0}", Colour = colourProvider.Highlight1 }, @@ -234,7 +236,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Font = font.With(size: 12), Text = "pp", Colour = colourProvider.Light3 } @@ -244,23 +246,44 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks if (Score.Beatmap?.Status.GrantsPerformancePoints() != true) { - return new UnrankedPerformancePointsPlaceholder(UsersStrings.ShowExtraTopRanksNotRanked) + if (Score.Beatmap?.Status == BeatmapOnlineStatus.Loved) { + return new SpriteIconWithTooltip + { + Icon = FontAwesome.Solid.Heart, + Size = new Vector2(font.Size), + TooltipText = UsersStrings.ShowExtraTopRanksNotRanked, + Colour = colourProvider.Highlight1 + }; + } + + return new SpriteTextWithTooltip + { + Text = "-", Font = OsuFont.GetFont(weight: FontWeight.Bold), - Colour = colourProvider.Highlight1, + TooltipText = UsersStrings.ShowExtraTopRanksNotRanked, + Colour = colourProvider.Highlight1 }; } if (!Score.Ranked) { - return new UnrankedPerformancePointsPlaceholder(ScoresStrings.StatusNoPp) + return new SpriteTextWithTooltip { + Text = "-", Font = OsuFont.GetFont(weight: FontWeight.Bold), - Colour = colourProvider.Highlight1, + TooltipText = ScoresStrings.StatusNoPp, + Colour = colourProvider.Highlight1 }; } - return new UnprocessedPerformancePointsPlaceholder { Size = new Vector2(16), Colour = colourProvider.Highlight1 }; + return new SpriteIconWithTooltip + { + Icon = FontAwesome.Solid.Sync, + Size = new Vector2(font.Size), + TooltipText = ScoresStrings.StatusProcessing, + Colour = colourProvider.Highlight1 + }; } private partial class ScoreBeatmapMetadataContainer : BeatmapMetadataContainer diff --git a/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs b/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs deleted file mode 100644 index a2cb69062e..0000000000 --- a/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable -using osu.Framework.Graphics; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Localisation; -using osu.Game.Resources.Localisation.Web; - -namespace osu.Game.Scoring.Drawables -{ - /// - /// A placeholder used in PP columns for scores with unprocessed PP value. - /// - public partial class UnprocessedPerformancePointsPlaceholder : SpriteIcon, IHasTooltip - { - public LocalisableString TooltipText => ScoresStrings.StatusProcessing; - - public UnprocessedPerformancePointsPlaceholder() - { - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - Icon = FontAwesome.Solid.Sync; - } - } -} diff --git a/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs b/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs deleted file mode 100644 index 0097497ef1..0000000000 --- a/osu.Game/Scoring/Drawables/UnrankedPerformancePointsPlaceholder.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Localisation; - -namespace osu.Game.Scoring.Drawables -{ - /// - /// A placeholder used in PP columns for scores that do not award PP due to a reason specified by . - /// - public partial class UnrankedPerformancePointsPlaceholder : SpriteText, IHasTooltip - { - public LocalisableString TooltipText { get; } - - public UnrankedPerformancePointsPlaceholder(LocalisableString tooltipText) - { - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - Text = "-"; - TooltipText = tooltipText; - } - } -} From 5bebe9fe0d5c5a5110efd1cd145e5dcb93cd92af Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 12 Feb 2024 21:33:16 +0300 Subject: [PATCH 090/223] Add test case for profile scores made on loved beatmaps --- .../Online/TestSceneUserProfileScores.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs index f72980757b..56e4348b65 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs @@ -102,6 +102,24 @@ namespace osu.Game.Tests.Visual.Online Ranked = true, }; + var lovedScore = new SoloScoreInfo + { + Rank = ScoreRank.B, + Beatmap = new APIBeatmap + { + BeatmapSet = new APIBeatmapSet + { + Title = "C18H27NO3(extend)", + Artist = "Team Grimoire", + }, + DifficultyName = "[4K] Cataclysmic Hypernova", + Status = BeatmapOnlineStatus.Loved, + }, + EndedAt = DateTimeOffset.Now, + Accuracy = 0.55879, + Ranked = true, + }; + var unprocessedPPScore = new SoloScoreInfo { Rank = ScoreRank.B, @@ -151,6 +169,7 @@ namespace osu.Game.Tests.Visual.Online new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(firstScore)), new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(secondScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(noPPScore)), + new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(lovedScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(unprocessedPPScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(unrankedPPScore)), new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(firstScore, 0.97)), From 2d65dfbf09f1e2c139862a649d363e0c12d37030 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 12 Feb 2024 22:10:36 +0300 Subject: [PATCH 091/223] Fix Rider EAP whoopsie --- osu.Game/Graphics/Sprites/SpriteIconWithTooltip.cs | 3 +++ osu.Game/Graphics/Sprites/SpriteTextWithTooltip.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/osu.Game/Graphics/Sprites/SpriteIconWithTooltip.cs b/osu.Game/Graphics/Sprites/SpriteIconWithTooltip.cs index 572a17571b..17f4bf53f9 100644 --- a/osu.Game/Graphics/Sprites/SpriteIconWithTooltip.cs +++ b/osu.Game/Graphics/Sprites/SpriteIconWithTooltip.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.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; diff --git a/osu.Game/Graphics/Sprites/SpriteTextWithTooltip.cs b/osu.Game/Graphics/Sprites/SpriteTextWithTooltip.cs index db98e8ba57..446b621b81 100644 --- a/osu.Game/Graphics/Sprites/SpriteTextWithTooltip.cs +++ b/osu.Game/Graphics/Sprites/SpriteTextWithTooltip.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.Graphics.Cursor; using osu.Framework.Localisation; From 5101979ac099b7e590e020020bf3b0a7bf134164 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Tue, 13 Feb 2024 00:34:06 +0000 Subject: [PATCH 092/223] only use `LegacyReplayPressHandler` on legacy replays --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index a5643e5b49..d2e4e0c669 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Mods Debug.Assert(ruleset.ReplayScore != null); legacyReplay = ruleset.ReplayScore.ScoreInfo.IsLegacyScore; - pressHandler = new LegacyReplayPressHandler(this); + pressHandler = legacyReplay ? new LegacyReplayPressHandler(this) : new PressHandler(this); return; } From 22e9c4a3b59e414a881ceae5abc885389a0af5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 13 Feb 2024 10:19:55 +0100 Subject: [PATCH 093/223] Use private interface rather than weird inheritance --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 38 ++++++++++++++--------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index d2e4e0c669..31511c01b8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Mods private double lastStateChangeTime; private DrawableOsuRuleset ruleset = null!; - private PressHandler pressHandler = null!; + private IPressHandler pressHandler = null!; private bool hasReplay; private bool legacyReplay; @@ -155,44 +155,52 @@ namespace osu.Game.Rulesets.Osu.Mods } } - private class PressHandler + private interface IPressHandler { - protected readonly OsuModRelax Mod; + void HandlePress(bool wasLeft); + void HandleRelease(bool wasLeft); + } + + private class PressHandler : IPressHandler + { + private readonly OsuModRelax mod; public PressHandler(OsuModRelax mod) { - Mod = mod; + this.mod = mod; } - public virtual void HandlePress(bool wasLeft) + public void HandlePress(bool wasLeft) { - Mod.state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); - Mod.state.Apply(Mod.osuInputManager.CurrentState, Mod.osuInputManager); + mod.state.PressedActions.Add(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + mod.state.Apply(mod.osuInputManager.CurrentState, mod.osuInputManager); } - public virtual void HandleRelease(bool wasLeft) + public void HandleRelease(bool wasLeft) { - Mod.state.Apply(Mod.osuInputManager.CurrentState, Mod.osuInputManager); + mod.state.Apply(mod.osuInputManager.CurrentState, mod.osuInputManager); } } // legacy replays do not contain key-presses with Relax mod, so they need to be triggered by themselves. - private class LegacyReplayPressHandler : PressHandler + private class LegacyReplayPressHandler : IPressHandler { + private readonly OsuModRelax mod; + public LegacyReplayPressHandler(OsuModRelax mod) - : base(mod) { + this.mod = mod; } - public override void HandlePress(bool wasLeft) + public void HandlePress(bool wasLeft) { - Mod.osuInputManager.KeyBindingContainer.TriggerPressed(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); + mod.osuInputManager.KeyBindingContainer.TriggerPressed(wasLeft ? OsuAction.LeftButton : OsuAction.RightButton); } - public override void HandleRelease(bool wasLeft) + public void HandleRelease(bool wasLeft) { // this intentionally releases right when `wasLeft` is true because `wasLeft` is set at point of press and not at point of release - Mod.osuInputManager.KeyBindingContainer.TriggerReleased(wasLeft ? OsuAction.RightButton : OsuAction.LeftButton); + mod.osuInputManager.KeyBindingContainer.TriggerReleased(wasLeft ? OsuAction.RightButton : OsuAction.LeftButton); } } } From da4ebd0681e05318d7328fc5be587151233e8f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 9 Feb 2024 10:41:36 +0100 Subject: [PATCH 094/223] Refactor `SoloStatisticsWatcher` to no longer require explicit subscription callbacks --- .../Online/TestSceneSoloStatisticsWatcher.cs | 41 ++++--------- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 59 +++++-------------- .../TransientUserStatisticsUpdateDisplay.cs | 10 ++++ osu.Game/Screens/Play/SubmittingPlayer.cs | 5 ++ osu.Game/Screens/Ranking/SoloResultsScreen.cs | 24 ++++---- 5 files changed, 56 insertions(+), 83 deletions(-) create mode 100644 osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs index 3607b37c7e..19121b7f58 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs @@ -35,8 +35,6 @@ namespace osu.Game.Tests.Visual.Online private Action? handleGetUsersRequest; private Action? handleGetUserRequest; - private IDisposable? subscription; - private readonly Dictionary<(int userId, string rulesetName), UserStatistics> serverSideStatistics = new Dictionary<(int userId, string rulesetName), UserStatistics>(); [SetUpSteps] @@ -252,26 +250,6 @@ namespace osu.Game.Tests.Visual.Online AddAssert("values after are correct", () => update!.After.TotalScore, () => Is.EqualTo(6_000_000)); } - [Test] - public void TestStatisticsUpdateNotFiredAfterSubscriptionDisposal() - { - int userId = getUserId(); - setUpUser(userId); - - long scoreId = getScoreId(); - var ruleset = new OsuRuleset().RulesetInfo; - - SoloStatisticsUpdate? update = null; - registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - AddStep("unsubscribe", () => subscription!.Dispose()); - - feignScoreProcessing(userId, ruleset, 5_000_000); - - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); - AddWaitStep("wait a bit", 5); - AddAssert("update not received", () => update == null); - } - [Test] public void TestGlobalStatisticsUpdatedAfterRegistrationAddedAndScoreProcessed() { @@ -312,13 +290,20 @@ namespace osu.Game.Tests.Visual.Online } private void registerForUpdates(long scoreId, RulesetInfo rulesetInfo, Action onUpdateReady) => - AddStep("register for updates", () => subscription = watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) + AddStep("register for updates", () => + { + watcher.RegisterForStatisticsUpdateAfter( + new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) + { + Ruleset = rulesetInfo, + OnlineID = scoreId + }); + watcher.LatestUpdate.BindValueChanged(update => { - Ruleset = rulesetInfo, - OnlineID = scoreId - }, - onUpdateReady)); + if (update.NewValue?.Score.OnlineID == scoreId) + onUpdateReady.Invoke(update.NewValue); + }); + }); private void feignScoreProcessing(int userId, RulesetInfo rulesetInfo, long newTotalScore) => AddStep("feign score processing", () => serverSideStatistics[(userId, rulesetInfo.ShortName)] = new UserStatistics { TotalScore = newTotalScore }); diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 55b27fb364..2072e8633f 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -1,10 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Game.Extensions; @@ -22,14 +22,16 @@ namespace osu.Game.Online.Solo /// public partial class SoloStatisticsWatcher : Component { + public IBindable LatestUpdate => latestUpdate; + private readonly Bindable latestUpdate = new Bindable(); + [Resolved] private SpectatorClient spectatorClient { get; set; } = null!; [Resolved] private IAPIProvider api { get; set; } = null!; - private readonly Dictionary callbacks = new Dictionary(); - private long? lastProcessedScoreId; + private readonly Dictionary watchedScores = new Dictionary(); private Dictionary? latestStatistics; @@ -45,9 +47,7 @@ namespace osu.Game.Online.Solo /// Registers for a user statistics update after the given has been processed server-side. /// /// The score to listen for the statistics update for. - /// The callback to be invoked once the statistics update has been prepared. - /// An representing the subscription. Disposing it is equivalent to unsubscribing from future notifications. - public IDisposable RegisterForStatisticsUpdateAfter(ScoreInfo score, Action onUpdateReady) + public void RegisterForStatisticsUpdateAfter(ScoreInfo score) { Schedule(() => { @@ -57,24 +57,12 @@ namespace osu.Game.Online.Solo if (!score.Ruleset.IsLegacyRuleset() || score.OnlineID <= 0) return; - var callback = new StatisticsUpdateCallback(score, onUpdateReady); - - if (lastProcessedScoreId == score.OnlineID) - { - requestStatisticsUpdate(api.LocalUser.Value.Id, callback); - return; - } - - callbacks.Add(score.OnlineID, callback); + watchedScores.Add(score.OnlineID, score); }); - - return new InvokeOnDisposal(() => Schedule(() => callbacks.Remove(score.OnlineID))); } private void onUserChanged(APIUser? localUser) => Schedule(() => { - callbacks.Clear(); - lastProcessedScoreId = null; latestStatistics = null; if (localUser == null || localUser.OnlineID <= 1) @@ -107,25 +95,22 @@ namespace osu.Game.Online.Solo if (userId != api.LocalUser.Value?.OnlineID) return; - lastProcessedScoreId = scoreId; - - if (!callbacks.TryGetValue(scoreId, out var callback)) + if (!watchedScores.Remove(scoreId, out var scoreInfo)) return; - requestStatisticsUpdate(userId, callback); - callbacks.Remove(scoreId); + requestStatisticsUpdate(userId, scoreInfo); } - private void requestStatisticsUpdate(int userId, StatisticsUpdateCallback callback) + private void requestStatisticsUpdate(int userId, ScoreInfo scoreInfo) { - var request = new GetUserRequest(userId, callback.Score.Ruleset); - request.Success += user => Schedule(() => dispatchStatisticsUpdate(callback, user.Statistics)); + var request = new GetUserRequest(userId, scoreInfo.Ruleset); + request.Success += user => Schedule(() => dispatchStatisticsUpdate(scoreInfo, user.Statistics)); api.Queue(request); } - private void dispatchStatisticsUpdate(StatisticsUpdateCallback callback, UserStatistics updatedStatistics) + private void dispatchStatisticsUpdate(ScoreInfo scoreInfo, UserStatistics updatedStatistics) { - string rulesetName = callback.Score.Ruleset.ShortName; + string rulesetName = scoreInfo.Ruleset.ShortName; api.UpdateStatistics(updatedStatistics); @@ -135,9 +120,7 @@ namespace osu.Game.Online.Solo latestStatistics.TryGetValue(rulesetName, out UserStatistics? latestRulesetStatistics); latestRulesetStatistics ??= new UserStatistics(); - var update = new SoloStatisticsUpdate(callback.Score, latestRulesetStatistics, updatedStatistics); - callback.OnUpdateReady.Invoke(update); - + latestUpdate.Value = new SoloStatisticsUpdate(scoreInfo, latestRulesetStatistics, updatedStatistics); latestStatistics[rulesetName] = updatedStatistics; } @@ -148,17 +131,5 @@ namespace osu.Game.Online.Solo base.Dispose(isDisposing); } - - private class StatisticsUpdateCallback - { - public ScoreInfo Score { get; } - public Action OnUpdateReady { get; } - - public StatisticsUpdateCallback(ScoreInfo score, Action onUpdateReady) - { - Score = score; - OnUpdateReady = onUpdateReady; - } - } } } diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs new file mode 100644 index 0000000000..3917933958 --- /dev/null +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -0,0 +1,10 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Overlays.Toolbar +{ + public class TransientUserStatisticsUpdateDisplay + { + + } +} diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index c8e84f1961..bbd36c05d8 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -17,6 +17,7 @@ using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; +using osu.Game.Online.Solo; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; @@ -42,6 +43,9 @@ namespace osu.Game.Screens.Play [Resolved] private SessionStatics statics { get; set; } + [Resolved] + private SoloStatisticsWatcher soloStatisticsWatcher { get; set; } + private readonly object scoreSubmissionLock = new object(); private TaskCompletionSource scoreSubmissionSource; @@ -175,6 +179,7 @@ namespace osu.Game.Screens.Play await submitScore(score).ConfigureAwait(false); spectatorClient.EndPlaying(GameplayState); + soloStatisticsWatcher.RegisterForStatisticsUpdateAfter(score.ScoreInfo); } [Resolved] diff --git a/osu.Game/Screens/Ranking/SoloResultsScreen.cs b/osu.Game/Screens/Ranking/SoloResultsScreen.cs index 22d631e137..cba2fa18c0 100644 --- a/osu.Game/Screens/Ranking/SoloResultsScreen.cs +++ b/osu.Game/Screens/Ranking/SoloResultsScreen.cs @@ -31,10 +31,7 @@ namespace osu.Game.Screens.Ranking [Resolved] private RulesetStore rulesets { get; set; } = null!; - [Resolved] - private SoloStatisticsWatcher soloStatisticsWatcher { get; set; } = null!; - - private IDisposable? statisticsSubscription; + private IBindable latestUpdate = null!; private readonly Bindable statisticsUpdate = new Bindable(); public SoloResultsScreen(ScoreInfo score, bool allowRetry) @@ -42,14 +39,20 @@ namespace osu.Game.Screens.Ranking { } - protected override void LoadComplete() + [BackgroundDependencyLoader] + private void load(SoloStatisticsWatcher soloStatisticsWatcher) { - base.LoadComplete(); - - Debug.Assert(Score != null); - if (ShowUserStatistics) - statisticsSubscription = soloStatisticsWatcher.RegisterForStatisticsUpdateAfter(Score, update => statisticsUpdate.Value = update); + { + Debug.Assert(Score != null); + + latestUpdate = soloStatisticsWatcher.LatestUpdate.GetBoundCopy(); + latestUpdate.BindValueChanged(update => + { + if (update.NewValue?.Score.MatchesOnlineID(Score) == true) + statisticsUpdate.Value = update.NewValue; + }); + } } protected override StatisticsPanel CreateStatisticsPanel() @@ -84,7 +87,6 @@ namespace osu.Game.Screens.Ranking base.Dispose(isDisposing); getScoreRequest?.Cancel(); - statisticsSubscription?.Dispose(); } } } From 21b9fb95e28c6c4f7e27467ac301727a00469758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 9 Feb 2024 15:19:38 +0100 Subject: [PATCH 095/223] Move `SoloStatisticsWatcher` to `OsuGame` Doesn't feel like it needs to be in base, and it being in base was causing problems elsewhere before. --- osu.Game/OsuGame.cs | 2 ++ osu.Game/OsuGameBase.cs | 4 ---- osu.Game/Screens/Play/SubmittingPlayer.cs | 5 +++-- osu.Game/Screens/Ranking/SoloResultsScreen.cs | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index c244708385..640096a5a8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -47,6 +47,7 @@ using osu.Game.Localisation; using osu.Game.Online; using osu.Game.Online.Chat; using osu.Game.Online.Rooms; +using osu.Game.Online.Solo; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapListing; using osu.Game.Overlays.Music; @@ -1015,6 +1016,7 @@ namespace osu.Game ScreenStack.Push(CreateLoader().With(l => l.RelativeSizeAxes = Axes.Both)); }); + loadComponentSingleFile(new SoloStatisticsWatcher(), Add, true); loadComponentSingleFile(Toolbar = new Toolbar { OnHome = delegate diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index a2a6322665..81e3d8bed8 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -50,7 +50,6 @@ using osu.Game.Online.API; using osu.Game.Online.Chat; using osu.Game.Online.Metadata; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Solo; using osu.Game.Online.Spectator; using osu.Game.Overlays; using osu.Game.Overlays.Settings; @@ -207,7 +206,6 @@ namespace osu.Game protected MultiplayerClient MultiplayerClient { get; private set; } private MetadataClient metadataClient; - private SoloStatisticsWatcher soloStatisticsWatcher; private RealmAccess realm; @@ -328,7 +326,6 @@ namespace osu.Game dependencies.CacheAs(SpectatorClient = new OnlineSpectatorClient(endpoints)); dependencies.CacheAs(MultiplayerClient = new OnlineMultiplayerClient(endpoints)); dependencies.CacheAs(metadataClient = new OnlineMetadataClient(endpoints)); - dependencies.CacheAs(soloStatisticsWatcher = new SoloStatisticsWatcher()); base.Content.Add(new BeatmapOnlineChangeIngest(beatmapUpdater, realm, metadataClient)); @@ -371,7 +368,6 @@ namespace osu.Game base.Content.Add(SpectatorClient); base.Content.Add(MultiplayerClient); base.Content.Add(metadataClient); - base.Content.Add(soloStatisticsWatcher); base.Content.Add(rulesetConfigCache); diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index bbd36c05d8..c45d46e993 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -43,7 +43,8 @@ namespace osu.Game.Screens.Play [Resolved] private SessionStatics statics { get; set; } - [Resolved] + [Resolved(canBeNull: true)] + [CanBeNull] private SoloStatisticsWatcher soloStatisticsWatcher { get; set; } private readonly object scoreSubmissionLock = new object(); @@ -179,7 +180,7 @@ namespace osu.Game.Screens.Play await submitScore(score).ConfigureAwait(false); spectatorClient.EndPlaying(GameplayState); - soloStatisticsWatcher.RegisterForStatisticsUpdateAfter(score.ScoreInfo); + soloStatisticsWatcher?.RegisterForStatisticsUpdateAfter(score.ScoreInfo); } [Resolved] diff --git a/osu.Game/Screens/Ranking/SoloResultsScreen.cs b/osu.Game/Screens/Ranking/SoloResultsScreen.cs index cba2fa18c0..866440bbd6 100644 --- a/osu.Game/Screens/Ranking/SoloResultsScreen.cs +++ b/osu.Game/Screens/Ranking/SoloResultsScreen.cs @@ -40,9 +40,9 @@ namespace osu.Game.Screens.Ranking } [BackgroundDependencyLoader] - private void load(SoloStatisticsWatcher soloStatisticsWatcher) + private void load(SoloStatisticsWatcher? soloStatisticsWatcher) { - if (ShowUserStatistics) + if (ShowUserStatistics && soloStatisticsWatcher != null) { Debug.Assert(Score != null); From 14052ae1cc15c45cb81f60fd20341dfcfea7d429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 9 Feb 2024 17:14:15 +0100 Subject: [PATCH 096/223] Implement transient stats display on user toolbar button --- .../Menus/TestSceneToolbarUserButton.cs | 91 ++++++++ .../Overlays/Toolbar/ToolbarUserButton.cs | 7 + .../TransientUserStatisticsUpdateDisplay.cs | 215 +++++++++++++++++- 3 files changed, 311 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs index f0506ed35c..69fedf4a3a 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs @@ -2,12 +2,17 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; using osu.Game.Online.API; +using osu.Game.Online.Solo; using osu.Game.Overlays.Toolbar; +using osu.Game.Scoring; +using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -87,5 +92,91 @@ namespace osu.Game.Tests.Visual.Menus AddStep($"Change state to {state}", () => dummyAPI.SetState(state)); } } + + [Test] + public void TestTransientUserStatisticsDisplay() + { + AddStep("Log in", () => dummyAPI.Login("wang", "jang")); + AddStep("Gain", () => + { + var transientUpdateDisplay = this.ChildrenOfType().Single(); + transientUpdateDisplay.LatestUpdate.Value = new SoloStatisticsUpdate( + new ScoreInfo(), + new UserStatistics + { + GlobalRank = 123_456, + PP = 1234 + }, + new UserStatistics + { + GlobalRank = 111_111, + PP = 1357 + }); + }); + AddStep("Loss", () => + { + var transientUpdateDisplay = this.ChildrenOfType().Single(); + transientUpdateDisplay.LatestUpdate.Value = new SoloStatisticsUpdate( + new ScoreInfo(), + new UserStatistics + { + GlobalRank = 111_111, + PP = 1357 + }, + new UserStatistics + { + GlobalRank = 123_456, + PP = 1234 + }); + }); + AddStep("No change", () => + { + var transientUpdateDisplay = this.ChildrenOfType().Single(); + transientUpdateDisplay.LatestUpdate.Value = new SoloStatisticsUpdate( + new ScoreInfo(), + new UserStatistics + { + GlobalRank = 111_111, + PP = 1357 + }, + new UserStatistics + { + GlobalRank = 111_111, + PP = 1357 + }); + }); + AddStep("Was null", () => + { + var transientUpdateDisplay = this.ChildrenOfType().Single(); + transientUpdateDisplay.LatestUpdate.Value = new SoloStatisticsUpdate( + new ScoreInfo(), + new UserStatistics + { + GlobalRank = null, + PP = null + }, + new UserStatistics + { + GlobalRank = 111_111, + PP = 1357 + }); + }); + AddStep("Became null", () => + { + var transientUpdateDisplay = this.ChildrenOfType().Single(); + transientUpdateDisplay.LatestUpdate.Value = new SoloStatisticsUpdate( + new ScoreInfo(), + new UserStatistics + { + GlobalRank = 111_111, + PP = 1357 + }, + new UserStatistics + { + GlobalRank = null, + PP = null + }); + }); + } } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 2620e850c8..96c0b15c44 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -78,6 +78,13 @@ namespace osu.Game.Overlays.Toolbar } }); + Flow.Add(new TransientUserStatisticsUpdateDisplay + { + Alpha = 0 + }); + Flow.AutoSizeEasing = Easing.OutQuint; + Flow.AutoSizeDuration = 250; + apiState = api.State.GetBoundCopy(); apiState.BindValueChanged(onlineStateChanged, true); diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index 3917933958..9070ea9030 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -1,10 +1,221 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.Solo; +using osu.Game.Resources.Localisation.Web; +using osuTK; + namespace osu.Game.Overlays.Toolbar { - public class TransientUserStatisticsUpdateDisplay + public partial class TransientUserStatisticsUpdateDisplay : CompositeDrawable { - + public Bindable LatestUpdate { get; } = new Bindable(); + + private Statistic globalRank = null!; + private Statistic pp = null!; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Y; + AutoSizeAxes = Axes.X; + Alpha = 0; + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Padding = new MarginPadding { Horizontal = 10 }, + Spacing = new Vector2(10), + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + globalRank = new Statistic(UsersStrings.ShowRankGlobalSimple, @"#", Comparer.Create((before, after) => before - after)), + pp = new Statistic(RankingsStrings.StatPerformance, string.Empty, Comparer.Create((before, after) => Math.Sign(after - before))), + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + LatestUpdate.BindValueChanged(val => + { + if (val.NewValue == null) + return; + + var update = val.NewValue; + + // null handling here is best effort because it is annoying. + + globalRank.Alpha = update.After.GlobalRank == null ? 0 : 1; + pp.Alpha = update.After.PP == null ? 0 : 1; + + if (globalRank.Alpha == 0 && pp.Alpha == 0) + return; + + FinishTransforms(true); + + this.FadeIn(500, Easing.OutQuint); + + if (update.After.GlobalRank != null) + { + globalRank.Display( + update.Before.GlobalRank ?? update.After.GlobalRank.Value, + Math.Abs((update.After.GlobalRank.Value - update.Before.GlobalRank) ?? 0), + update.After.GlobalRank.Value); + } + + if (update.After.PP != null) + pp.Display(update.Before.PP ?? update.After.PP.Value, Math.Abs((update.After.PP - update.Before.PP) ?? 0M), update.After.PP.Value); + + this.Delay(4000).FadeOut(500, Easing.OutQuint); + }); + } + + private partial class Statistic : CompositeDrawable + where T : struct, IEquatable, IFormattable + { + private readonly LocalisableString title; + private readonly string mainValuePrefix; + private readonly IComparer valueComparer; + + private Counter mainValue = null!; + private Counter deltaValue = null!; + private OsuSpriteText titleText = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + public Statistic(LocalisableString title, string mainValuePrefix, IComparer valueComparer) + { + this.title = title; + this.mainValuePrefix = mainValuePrefix; + this.valueComparer = valueComparer; + } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Y; + AutoSizeAxes = Axes.X; + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + mainValue = new Counter + { + ValuePrefix = mainValuePrefix, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Font = OsuFont.GetFont(), + }, + new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Children = new Drawable[] + { + deltaValue = new Counter + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Font = OsuFont.GetFont(size: 12, fixedWidth: false, weight: FontWeight.SemiBold), + AlwaysPresent = true, + }, + titleText = new OsuSpriteText + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Font = OsuFont.Default.With(size: 12, weight: FontWeight.SemiBold), + Text = title, + AlwaysPresent = true, + } + } + } + } + }; + } + + public void Display(T before, T delta, T after) + { + int comparison = valueComparer.Compare(before, after); + + if (comparison > 0) + { + deltaValue.Colour = colours.Lime1; + deltaValue.ValuePrefix = "+"; + } + else if (comparison < 0) + { + deltaValue.Colour = colours.Red1; + deltaValue.ValuePrefix = "-"; + } + else + { + deltaValue.Colour = Colour4.White; + deltaValue.ValuePrefix = string.Empty; + } + + mainValue.SetCountWithoutRolling(before); + deltaValue.SetCountWithoutRolling(delta); + + titleText.Alpha = 1; + deltaValue.Alpha = 0; + + using (BeginDelayedSequence(1000)) + { + titleText.FadeOut(250, Easing.OutQuint); + deltaValue.FadeIn(250, Easing.OutQuint) + .Then().Delay(1000) + .Then().OnComplete(_ => + { + mainValue.Current.Value = after; + deltaValue.Current.SetDefault(); + }); + } + } + } + + private partial class Counter : RollingCounter + where T : struct, IEquatable, IFormattable + { + public const double ROLLING_DURATION = 500; + + public FontUsage Font { get; init; } = OsuFont.Default; + + public string ValuePrefix + { + get => valuePrefix; + set + { + valuePrefix = value; + UpdateDisplay(); + } + } + + private string valuePrefix = string.Empty; + + protected override LocalisableString FormatCount(T count) => LocalisableString.Format(@"{0}{1:N0}", ValuePrefix, count); + protected override OsuSpriteText CreateSpriteText() => base.CreateSpriteText().With(t => t.Font = Font); + protected override double RollingDuration => ROLLING_DURATION; + } } } From eae43f5fd90b5aec6a698253c9f82cb6e3f878e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 9 Feb 2024 17:15:52 +0100 Subject: [PATCH 097/223] Consume `SoloStatisticsWatcher` updates in toolbar button --- .../Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs | 5 ++++- osu.Game/Screens/Ranking/ResultsScreen.cs | 3 --- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index 9070ea9030..e3c1746e14 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.Toolbar private Statistic pp = null!; [BackgroundDependencyLoader] - private void load() + private void load(SoloStatisticsWatcher? soloStatisticsWatcher) { RelativeSizeAxes = Axes.Y; AutoSizeAxes = Axes.X; @@ -45,6 +45,9 @@ namespace osu.Game.Overlays.Toolbar pp = new Statistic(RankingsStrings.StatPerformance, string.Empty, Comparer.Create((before, after) => Math.Sign(after - before))), } }; + + if (soloStatisticsWatcher != null) + ((IBindable)LatestUpdate).BindTo(soloStatisticsWatcher.LatestUpdate); } protected override void LoadComplete() diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 82dade40eb..69cfbed8f2 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -41,9 +41,6 @@ namespace osu.Game.Screens.Ranking public override bool? AllowGlobalTrackControl => true; - // Temporary for now to stop dual transitions. Should respect the current toolbar mode, but there's no way to do so currently. - public override bool HideOverlaysOnEnter => true; - public readonly Bindable SelectedScore = new Bindable(); [CanBeNull] From 62f5251b6ef8eef5f0b1c638621aa0258379fb17 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 13 Feb 2024 11:51:21 +0300 Subject: [PATCH 098/223] Rewrite osu!catch playfield layout containers and apply masking around vertical boundaries --- .../UI/CatchPlayfieldAdjustmentContainer.cs | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs index 11531011ee..1bddd06d87 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs @@ -17,24 +17,29 @@ namespace osu.Game.Rulesets.Catch.UI public CatchPlayfieldAdjustmentContainer() { - Anchor = Anchor.TopCentre; - Origin = Anchor.TopCentre; - - // playfields in stable are positioned vertically at three fourths the difference between the playfield height and the window height in stable. - // we can match that in lazer by using relative coordinates for Y and considering window height to be 1, and playfield height to be 0.8. - RelativePositionAxes = Axes.Y; - Y = (1 - playfield_size_adjust) / 4 * 3; - - Size = new Vector2(playfield_size_adjust); + const float base_game_width = 1024f; + const float base_game_height = 768f; InternalChild = new Container { + // This container limits vertical visibility of the playfield to ensure fairness between wide and tall resolutions (i.e. tall resolutions should not see more fruits). + // Note that the container still extends across the screen horizontally, so that hit explosions at the sides of the playfield do not get cut off. + Name = "Visible area", Anchor = Anchor.Centre, Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fit, - FillAspectRatio = 4f / 3, - Child = content = new ScalingContainer { RelativeSizeAxes = Axes.Both, } + RelativeSizeAxes = Axes.X, + Height = base_game_height, + Masking = true, + Child = new Container + { + Name = "Playable area", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + // playfields in stable are positioned vertically at three fourths the difference between the playfield height and the window height in stable. + Y = base_game_height * ((1 - playfield_size_adjust) / 4 * 3), + Size = new Vector2(base_game_width, base_game_height) * playfield_size_adjust, + Child = content = new ScalingContainer { RelativeSizeAxes = Axes.Both } + }, }; } From 9b17020707a5dd53e45211fd0e5de9a682abf16e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Feb 2024 01:03:21 +0300 Subject: [PATCH 099/223] Adjust "Floating Fruits" in line with layout changes --- osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs | 1 - .../UI/CatchPlayfieldAdjustmentContainer.cs | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs index 9d88c90576..f933b9a28f 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs @@ -21,7 +21,6 @@ namespace osu.Game.Rulesets.Catch.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { drawableRuleset.PlayfieldAdjustmentContainer.Scale = new Vector2(1, -1); - drawableRuleset.PlayfieldAdjustmentContainer.Y = 1 - drawableRuleset.PlayfieldAdjustmentContainer.Y; } } } diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs index 1bddd06d87..64d17b08b6 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs @@ -20,6 +20,9 @@ namespace osu.Game.Rulesets.Catch.UI const float base_game_width = 1024f; const float base_game_height = 768f; + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + InternalChild = new Container { // This container limits vertical visibility of the playfield to ensure fairness between wide and tall resolutions (i.e. tall resolutions should not see more fruits). From a96a66bc9e071f0b8bc2771f194965a23cc62d95 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Feb 2024 02:04:19 +0300 Subject: [PATCH 100/223] Add failing test case --- .../Navigation/TestSceneScreenNavigation.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index f59fbc75ac..8ff4fd5ecf 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -986,6 +986,29 @@ namespace osu.Game.Tests.Visual.Navigation } } + [Test] + public void TestPresentBeatmapAfterDeletion() + { + BeatmapSetInfo beatmap = null; + + Screens.Select.SongSelect songSelect = null; + PushAndConfirm(() => songSelect = new TestPlaySongSelect()); + AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded); + + AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely()); + AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault); + + AddStep("delete selected beatmap", () => + { + beatmap = Game.Beatmap.Value.BeatmapSetInfo; + Game.BeatmapManager.Delete(Game.Beatmap.Value.BeatmapSetInfo); + }); + + AddUntilStep("nothing selected", () => Game.Beatmap.IsDefault); + AddStep("present deleted beatmap", () => Game.PresentBeatmap(beatmap)); + AddAssert("still nothing selected", () => Game.Beatmap.IsDefault); + } + private Func playToResults() { var player = playToCompletion(); From 35649d137ca9fea993c473b7b08d26f53ba13441 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Feb 2024 01:59:45 +0300 Subject: [PATCH 101/223] Ignore soft-deleted beatmaps when trying to present from notification --- osu.Game/OsuGame.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index c244708385..11798c22ff 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -630,6 +630,12 @@ namespace osu.Game var detachedSet = databasedSet.PerformRead(s => s.Detach()); + if (detachedSet.DeletePending) + { + Logger.Log("The requested beatmap has since been deleted.", LoggingTarget.Information); + return; + } + PerformFromScreen(screen => { // Find beatmaps that match our predicate. From 5267e0abf788da62e6eaaa1fed1ac35be0fcb428 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Feb 2024 03:38:49 +0300 Subject: [PATCH 102/223] Move comment author line to separate component --- .../Overlays/Comments/CommentAuthorLine.cs | 135 ++++++++++++++++++ osu.Game/Overlays/Comments/DrawableComment.cs | 102 +------------ 2 files changed, 139 insertions(+), 98 deletions(-) create mode 100644 osu.Game/Overlays/Comments/CommentAuthorLine.cs diff --git a/osu.Game/Overlays/Comments/CommentAuthorLine.cs b/osu.Game/Overlays/Comments/CommentAuthorLine.cs new file mode 100644 index 0000000000..b6b5dc00e1 --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentAuthorLine.cs @@ -0,0 +1,135 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; +using osuTK; + +namespace osu.Game.Overlays.Comments +{ + public partial class CommentAuthorLine : FillFlowContainer + { + private readonly Comment comment; + + private OsuSpriteText deletedLabel = null!; + + public CommentAuthorLine(Comment comment) + { + this.comment = comment; + } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(4, 0); + + Add(new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold)) + { + AutoSizeAxes = Axes.Both + }.With(username => + { + if (comment.UserId.HasValue) + username.AddUserLink(comment.User); + else + username.AddText(comment.LegacyName!); + })); + + if (comment.Pinned) + Add(new PinnedCommentNotice()); + + Add(new ParentUsername(comment)); + + Add(deletedLabel = new OsuSpriteText + { + Alpha = 0f, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), + Text = CommentsStrings.Deleted + }); + } + + public void MarkDeleted() + { + deletedLabel.Show(); + } + + private partial class PinnedCommentNotice : FillFlowContainer + { + public PinnedCommentNotice() + { + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(2, 0); + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Thumbtack, + Size = new Vector2(14), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new OsuSpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), + Text = CommentsStrings.Pinned, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + } + }; + } + } + + private partial class ParentUsername : FillFlowContainer, IHasTooltip + { + public LocalisableString TooltipText => getParentMessage(); + + private readonly Comment? parentComment; + + public ParentUsername(Comment comment) + { + parentComment = comment.ParentComment; + + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(3, 0); + Alpha = comment.ParentId == null ? 0 : 1; + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Reply, + Size = new Vector2(14), + }, + new OsuSpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = parentComment?.User?.Username ?? parentComment?.LegacyName! + } + }; + } + + private LocalisableString getParentMessage() + { + if (parentComment == null) + return string.Empty; + + return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? CommentsStrings.Deleted : string.Empty; + } + } + } +} diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index ceae17aa5d..70b1809c3e 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -4,12 +4,10 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Framework.Graphics.Sprites; using osuTK; using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; using osu.Game.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Bindables; using System.Linq; using osu.Game.Graphics.Sprites; @@ -21,7 +19,6 @@ using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; using System.Diagnostics; using osu.Framework.Extensions.LocalisationExtensions; -using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Graphics.UserInterface; @@ -72,7 +69,7 @@ namespace osu.Game.Overlays.Comments private LinkFlowContainer actionsContainer = null!; private LoadingSpinner actionsLoading = null!; private DeletedCommentsCounter deletedCommentsCounter = null!; - private OsuSpriteText deletedLabel = null!; + private CommentAuthorLine author = null!; private GridContainer content = null!; private VotePill votePill = null!; private Container replyEditorContainer = null!; @@ -98,7 +95,6 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, DrawableComment? parentComment) { - LinkFlowContainer username; FillFlowContainer info; CommentMarkdownContainer message; @@ -174,27 +170,7 @@ namespace osu.Game.Overlays.Comments }, Children = new Drawable[] { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new[] - { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold)) - { - AutoSizeAxes = Axes.Both - }, - Comment.Pinned ? new PinnedCommentNotice() : Empty(), - new ParentUsername(Comment), - deletedLabel = new OsuSpriteText - { - Alpha = 0f, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), - Text = CommentsStrings.Deleted - } - } - }, + author = new CommentAuthorLine(Comment), message = new CommentMarkdownContainer { RelativeSizeAxes = Axes.X, @@ -218,7 +194,7 @@ namespace osu.Game.Overlays.Comments { new DrawableDate(Comment.CreatedAt, 12, false) { - Colour = colourProvider.Foreground1 + Colour = colourProvider.Foreground1, } } }, @@ -311,11 +287,6 @@ namespace osu.Game.Overlays.Comments } }; - if (Comment.UserId.HasValue) - username.AddUserLink(Comment.User); - else - username.AddText(Comment.LegacyName!); - if (Comment.EditedAt.HasValue && Comment.EditedUser != null) { var font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular); @@ -400,7 +371,7 @@ namespace osu.Game.Overlays.Comments /// private void makeDeleted() { - deletedLabel.Show(); + author.MarkDeleted(); content.FadeColour(OsuColour.Gray(0.5f)); votePill.Hide(); actionsContainer.Expire(); @@ -547,70 +518,5 @@ namespace osu.Game.Overlays.Comments Top = 10 }; } - - private partial class PinnedCommentNotice : FillFlowContainer - { - public PinnedCommentNotice() - { - AutoSizeAxes = Axes.Both; - Direction = FillDirection.Horizontal; - Spacing = new Vector2(2, 0); - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.Solid.Thumbtack, - Size = new Vector2(14), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - new OsuSpriteText - { - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), - Text = CommentsStrings.Pinned, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - } - }; - } - } - - private partial class ParentUsername : FillFlowContainer, IHasTooltip - { - public LocalisableString TooltipText => getParentMessage(); - - private readonly Comment? parentComment; - - public ParentUsername(Comment comment) - { - parentComment = comment.ParentComment; - - AutoSizeAxes = Axes.Both; - Direction = FillDirection.Horizontal; - Spacing = new Vector2(3, 0); - Alpha = comment.ParentId == null ? 0 : 1; - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.Solid.Reply, - Size = new Vector2(14), - }, - new OsuSpriteText - { - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = parentComment?.User?.Username ?? parentComment?.LegacyName! - } - }; - } - - private LocalisableString getParentMessage() - { - if (parentComment == null) - return string.Empty; - - return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? CommentsStrings.Deleted : string.Empty; - } - } } } From c4e358044a5f0478119c39309dd7525483847413 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Feb 2024 03:44:32 +0300 Subject: [PATCH 103/223] Add API models for comment page metadata --- .../API/Requests/Responses/CommentBundle.cs | 3 ++ .../API/Requests/Responses/CommentableMeta.cs | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 osu.Game/Online/API/Requests/Responses/CommentableMeta.cs diff --git a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs index ae8b850723..cbff8bf76c 100644 --- a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs +++ b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs @@ -11,6 +11,9 @@ namespace osu.Game.Online.API.Requests.Responses { public class CommentBundle { + [JsonProperty(@"commentable_meta")] + public List CommentableMeta { get; set; } = new List(); + [JsonProperty(@"comments")] public List Comments { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/CommentableMeta.cs b/osu.Game/Online/API/Requests/Responses/CommentableMeta.cs new file mode 100644 index 0000000000..1084f1c900 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/CommentableMeta.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class CommentableMeta + { + [JsonProperty("id")] + public long Id { get; set; } + + [JsonProperty("owner_id")] + public long? OwnerId { get; set; } + + [JsonProperty("owner_title")] + public string? OwnerTitle { get; set; } + + [JsonProperty("title")] + public string Title { get; set; } = string.Empty; + + [JsonProperty("type")] + public string Type { get; set; } = string.Empty; + + [JsonProperty("url")] + public string Url { get; set; } = string.Empty; + } +} From 72c6134dbff17ba8a7a2ee82a741a61412bdfa1d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Feb 2024 03:46:19 +0300 Subject: [PATCH 104/223] Include commentable object metadata in comments --- osu.Game/Overlays/Comments/CommentsContainer.cs | 8 ++++---- osu.Game/Overlays/Comments/DrawableComment.cs | 4 +++- osu.Game/Overlays/Comments/ReplyCommentEditor.cs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index b4e9a80ff1..2e5f13aa99 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -301,7 +301,7 @@ namespace osu.Game.Overlays.Comments void addNewComment(Comment comment) { - var drawableComment = GetDrawableComment(comment); + var drawableComment = GetDrawableComment(comment, bundle.CommentableMeta); if (comment.ParentId == null) { @@ -333,7 +333,7 @@ namespace osu.Game.Overlays.Comments if (CommentDictionary.ContainsKey(comment.Id)) continue; - topLevelComments.Add(GetDrawableComment(comment)); + topLevelComments.Add(GetDrawableComment(comment, bundle.CommentableMeta)); } if (topLevelComments.Any()) @@ -351,12 +351,12 @@ namespace osu.Game.Overlays.Comments } } - public DrawableComment GetDrawableComment(Comment comment) + public DrawableComment GetDrawableComment(Comment comment, IReadOnlyList meta) { if (CommentDictionary.TryGetValue(comment.Id, out var existing)) return existing; - return CommentDictionary[comment.Id] = new DrawableComment(comment) + return CommentDictionary[comment.Id] = new DrawableComment(comment, meta) { ShowDeleted = { BindTarget = ShowDeleted }, Sort = { BindTarget = Sort }, diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 70b1809c3e..afb8bdcc8b 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -39,6 +39,7 @@ namespace osu.Game.Overlays.Comments public Action RepliesRequested = null!; public readonly Comment Comment; + public readonly IReadOnlyList Meta; public readonly BindableBool ShowDeleted = new BindableBool(); public readonly Bindable Sort = new Bindable(); @@ -87,9 +88,10 @@ namespace osu.Game.Overlays.Comments [Resolved] private OnScreenDisplay? onScreenDisplay { get; set; } - public DrawableComment(Comment comment) + public DrawableComment(Comment comment, IReadOnlyList meta) { Comment = comment; + Meta = meta; } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Comments/ReplyCommentEditor.cs b/osu.Game/Overlays/Comments/ReplyCommentEditor.cs index dd4c35ef20..8e9e82507d 100644 --- a/osu.Game/Overlays/Comments/ReplyCommentEditor.cs +++ b/osu.Game/Overlays/Comments/ReplyCommentEditor.cs @@ -60,7 +60,7 @@ namespace osu.Game.Overlays.Comments foreach (var comment in cb.Comments) comment.ParentComment = parentComment; - var drawables = cb.Comments.Select(commentsContainer.GetDrawableComment).ToArray(); + var drawables = cb.Comments.Select(c => commentsContainer.GetDrawableComment(c, cb.CommentableMeta)).ToArray(); OnPost?.Invoke(drawables); OnCancel!.Invoke(); From 4d3b605e04d73ff69031d2d4c97ddcd937cb043f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Feb 2024 03:48:45 +0300 Subject: [PATCH 105/223] Add support for displaying "mapper" badges in comments --- .../Overlays/Comments/CommentAuthorLine.cs | 49 ++++++++++++++++++- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentAuthorLine.cs b/osu.Game/Overlays/Comments/CommentAuthorLine.cs index b6b5dc00e1..c269ab4c01 100644 --- a/osu.Game/Overlays/Comments/CommentAuthorLine.cs +++ b/osu.Game/Overlays/Comments/CommentAuthorLine.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -23,12 +22,14 @@ namespace osu.Game.Overlays.Comments public partial class CommentAuthorLine : FillFlowContainer { private readonly Comment comment; + private readonly IReadOnlyList meta; private OsuSpriteText deletedLabel = null!; - public CommentAuthorLine(Comment comment) + public CommentAuthorLine(Comment comment, IReadOnlyList meta) { this.comment = comment; + this.meta = meta; } [BackgroundDependencyLoader] @@ -49,6 +50,17 @@ namespace osu.Game.Overlays.Comments username.AddText(comment.LegacyName!); })); + var ownerMeta = meta.FirstOrDefault(m => m.Id == comment.CommentableId && m.Type == comment.CommentableType); + + if (ownerMeta?.OwnerId != null && ownerMeta.OwnerId == comment.UserId) + { + Add(new OwnerTitleBadge(ownerMeta.OwnerTitle ?? string.Empty) + { + // add top space to align with username + Margin = new MarginPadding { Top = 2f }, + }); + } + if (comment.Pinned) Add(new PinnedCommentNotice()); @@ -67,6 +79,39 @@ namespace osu.Game.Overlays.Comments deletedLabel.Show(); } + private partial class OwnerTitleBadge : CircularContainer + { + private readonly string title; + + public OwnerTitleBadge(string title) + { + this.title = title; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + AutoSizeAxes = Axes.Both; + Masking = true; + + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Light1, + }, + new OsuSpriteText + { + Text = title, + Font = OsuFont.Default.With(size: 10, weight: FontWeight.Bold), + Margin = new MarginPadding { Vertical = 2, Horizontal = 5 }, + Colour = colourProvider.Background6, + }, + }; + } + } + private partial class PinnedCommentNotice : FillFlowContainer { public PinnedCommentNotice() diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index afb8bdcc8b..afd4b96c68 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -172,7 +172,7 @@ namespace osu.Game.Overlays.Comments }, Children = new Drawable[] { - author = new CommentAuthorLine(Comment), + author = new CommentAuthorLine(Comment, Meta), message = new CommentMarkdownContainer { RelativeSizeAxes = Axes.X, From c24af5bfeb65ea125ebdd1c37e8c3e0a296ef78e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Feb 2024 03:49:29 +0300 Subject: [PATCH 106/223] Add test coverage --- .../Online/TestSceneCommentsContainer.cs | 41 ++++++++- .../Visual/Online/TestSceneDrawableComment.cs | 88 ++++++++++--------- .../UserInterface/ThemeComparisonTestScene.cs | 30 ++++--- 3 files changed, 103 insertions(+), 56 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 3d8781d902..fd3552f675 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -170,6 +170,24 @@ namespace osu.Game.Tests.Visual.Online }); } + [Test] + public void TestPostAsOwner() + { + setUpCommentsResponse(getExampleComments()); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + + setUpPostResponse(true); + AddStep("enter text", () => editorTextBox.Current.Value = "comm"); + AddStep("submit", () => commentsContainer.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); + + AddUntilStep("comment sent", () => + { + string writtenText = editorTextBox.Current.Value; + var comment = commentsContainer.ChildrenOfType().LastOrDefault(); + return comment != null && comment.ChildrenOfType().Any(y => y.Text == writtenText) && comment.ChildrenOfType().Any(y => y.Text == "MAPPER"); + }); + } + private void setUpCommentsResponse(CommentBundle commentBundle) => AddStep("set up response", () => { @@ -183,7 +201,7 @@ namespace osu.Game.Tests.Visual.Online }; }); - private void setUpPostResponse() + private void setUpPostResponse(bool asOwner = false) => AddStep("set up response", () => { dummyAPI.HandleRequest = request => @@ -191,7 +209,7 @@ namespace osu.Game.Tests.Visual.Online if (!(request is CommentPostRequest req)) return false; - req.TriggerSuccess(new CommentBundle + var bundle = new CommentBundle { Comments = new List { @@ -202,9 +220,26 @@ namespace osu.Game.Tests.Visual.Online LegacyName = "FirstUser", CreatedAt = DateTimeOffset.Now, VotesCount = 98, + CommentableId = 2001, + CommentableType = "test", } } - }); + }; + + if (asOwner) + { + bundle.Comments[0].UserId = 1001; + bundle.Comments[0].User = new APIUser { Id = 1001, Username = "FirstUser" }; + bundle.CommentableMeta.Add(new CommentableMeta + { + Id = 2001, + OwnerId = 1001, + OwnerTitle = "MAPPER", + Type = "test", + }); + } + + req.TriggerSuccess(bundle); return true; }; }); diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index 5e83dd4fb3..6f09e4c1f6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -4,62 +4,66 @@ #nullable disable using System; -using NUnit.Framework; -using osu.Framework.Allocation; +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Overlays; using osu.Game.Overlays.Comments; +using osu.Game.Tests.Visual.UserInterface; namespace osu.Game.Tests.Visual.Online { - public partial class TestSceneDrawableComment : OsuTestScene + public partial class TestSceneDrawableComment : ThemeComparisonTestScene { - [Cached] - private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - - private Container container; - - [SetUp] - public void SetUp() => Schedule(() => + public TestSceneDrawableComment() + : base(false) { - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background4, - }, - container = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, - }; - }); - - [TestCaseSource(nameof(comments))] - public void TestComment(string description, string text) - { - AddStep(description, () => - { - comment.Pinned = description == "Pinned"; - comment.Message = text; - container.Add(new DrawableComment(comment)); - }); } - private static readonly Comment comment = new Comment + protected override Drawable CreateContent() => new OsuScrollContainer(Direction.Vertical) { - Id = 1, - LegacyName = "Test User", - CreatedAt = DateTimeOffset.Now, - VotesCount = 0, + RelativeSizeAxes = Axes.Both, + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + ChildrenEnumerable = comments.Select(info => + { + var comment = new Comment + { + Id = 1, + UserId = 1000, + User = new APIUser { Id = 1000, Username = "Someone" }, + CreatedAt = DateTimeOffset.Now, + VotesCount = 0, + Pinned = info[0] == "Pinned", + Message = info[1], + CommentableId = 2001, + CommentableType = "test" + }; + + return new[] + { + new DrawableComment(comment, Array.Empty()), + new DrawableComment(comment, new[] + { + new CommentableMeta + { + Id = 2001, + OwnerId = comment.UserId, + OwnerTitle = "MAPPER", + Type = "test", + }, + new CommentableMeta { Title = "Other Meta" }, + }), + }; + }).SelectMany(c => c) + } }; - private static object[] comments = + private static readonly string[][] comments = { new[] { "Plain", "This is plain comment" }, new[] { "Pinned", "This is pinned comment" }, diff --git a/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs b/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs index 2c894eacab..f0c4b5543f 100644 --- a/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs +++ b/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs @@ -14,31 +14,39 @@ namespace osu.Game.Tests.Visual.UserInterface { public abstract partial class ThemeComparisonTestScene : OsuGridTestScene { - protected ThemeComparisonTestScene() - : base(1, 2) + private readonly bool showNoColourProvider; + + protected ThemeComparisonTestScene(bool showNoColourProvider = true) + : base(1, showNoColourProvider ? 2 : 1) { + this.showNoColourProvider = showNoColourProvider; } [BackgroundDependencyLoader] private void load(OsuColour colours) { - Cell(0, 0).AddRange(new[] + if (showNoColourProvider) { - new Box + Cell(0, 0).AddRange(new[] { - RelativeSizeAxes = Axes.Both, - Colour = colours.GreySeaFoam - }, - CreateContent() - }); + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.GreySeaFoam + }, + CreateContent() + }); + } } protected void CreateThemedContent(OverlayColourScheme colourScheme) { var colourProvider = new OverlayColourProvider(colourScheme); - Cell(0, 1).Clear(); - Cell(0, 1).Add(new DependencyProvidingContainer + int col = showNoColourProvider ? 1 : 0; + + Cell(0, col).Clear(); + Cell(0, col).Add(new DependencyProvidingContainer { RelativeSizeAxes = Axes.Both, CachedDependencies = new (Type, object)[] From 02de9122d4466d2a30a915bbbc19e5f143fec824 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Feb 2024 07:17:05 +0300 Subject: [PATCH 107/223] Remove behaviour of flipping catcher plate on direction change --- .../TestSceneCatchSkinConfiguration.cs | 111 ------------------ .../Skinning/CatchSkinConfiguration.cs | 13 -- .../Legacy/CatchLegacySkinTransformer.cs | 13 -- osu.Game.Rulesets.Catch/UI/Catcher.cs | 10 +- 4 files changed, 1 insertion(+), 146 deletions(-) delete mode 100644 osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs delete mode 100644 osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs deleted file mode 100644 index e2fc31d869..0000000000 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Linq; -using NUnit.Framework; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Testing; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Catch.Judgements; -using osu.Game.Rulesets.Catch.Objects; -using osu.Game.Rulesets.Catch.Objects.Drawables; -using osu.Game.Rulesets.Catch.Skinning; -using osu.Game.Rulesets.Catch.UI; -using osu.Game.Skinning; -using osu.Game.Tests.Visual; -using Direction = osu.Game.Rulesets.Catch.UI.Direction; - -namespace osu.Game.Rulesets.Catch.Tests -{ - public partial class TestSceneCatchSkinConfiguration : OsuTestScene - { - private Catcher catcher; - - private readonly Container container; - - public TestSceneCatchSkinConfiguration() - { - Add(container = new Container { RelativeSizeAxes = Axes.Both }); - } - - [TestCase(false)] - [TestCase(true)] - public void TestCatcherPlateFlipping(bool flip) - { - AddStep("setup catcher", () => - { - var skin = new TestSkin { FlipCatcherPlate = flip }; - container.Child = new SkinProvidingContainer(skin) - { - Child = catcher = new Catcher(new DroppedObjectContainer()) - { - Anchor = Anchor.Centre - } - }; - }); - - Fruit fruit = new Fruit(); - - AddStep("catch fruit", () => catchFruit(fruit, 20)); - - float position = 0; - - AddStep("record fruit position", () => position = getCaughtObjectPosition(fruit)); - - AddStep("face left", () => catcher.VisualDirection = Direction.Left); - - if (flip) - AddAssert("fruit position changed", () => !Precision.AlmostEquals(getCaughtObjectPosition(fruit), position)); - else - AddAssert("fruit position unchanged", () => Precision.AlmostEquals(getCaughtObjectPosition(fruit), position)); - - AddStep("face right", () => catcher.VisualDirection = Direction.Right); - - AddAssert("fruit position restored", () => Precision.AlmostEquals(getCaughtObjectPosition(fruit), position)); - } - - private float getCaughtObjectPosition(Fruit fruit) - { - var caughtObject = catcher.ChildrenOfType().Single(c => c.HitObject == fruit); - return caughtObject.Parent!.ToSpaceOfOtherDrawable(caughtObject.Position, catcher).X; - } - - private void catchFruit(Fruit fruit, float x) - { - fruit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - var drawableFruit = new DrawableFruit(fruit) { X = x }; - var judgement = fruit.CreateJudgement(); - catcher.OnNewResult(drawableFruit, new CatchJudgementResult(fruit, judgement) - { - Type = judgement.MaxResult - }); - } - - private class TestSkin : TrianglesSkin - { - public bool FlipCatcherPlate { get; set; } - - public TestSkin() - : base(null!) - { - } - - public override IBindable GetConfig(TLookup lookup) - { - if (lookup is CatchSkinConfiguration config) - { - if (config == CatchSkinConfiguration.FlipCatcherPlate) - return SkinUtils.As(new Bindable(FlipCatcherPlate)); - } - - return base.GetConfig(lookup); - } - } - } -} diff --git a/osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.cs deleted file mode 100644 index ea8d742b1a..0000000000 --- a/osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Rulesets.Catch.Skinning -{ - public enum CatchSkinConfiguration - { - /// - /// Whether the contents of the catcher plate should be visually flipped when the catcher direction is changed. - /// - FlipCatcherPlate - } -} diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index fb8af9bdb6..d1ef47cf17 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -122,19 +122,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy result.Value = LegacyColourCompatibility.DisallowZeroAlpha(result.Value); return (IBindable)result; - - case CatchSkinConfiguration config: - switch (config) - { - case CatchSkinConfiguration.FlipCatcherPlate: - // Don't flip catcher plate contents if the catcher is provided by this legacy skin. - if (GetDrawableComponent(new CatchSkinComponentLookup(CatchSkinComponents.Catcher)) != null) - return (IBindable)new Bindable(); - - break; - } - - break; } return base.GetConfig(lookup); diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 147850a9b7..dca01fc61a 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -112,11 +112,6 @@ namespace osu.Game.Rulesets.Catch.UI public Vector2 BodyScale => Scale * body.Scale; - /// - /// Whether the contents of the catcher plate should be visually flipped when the catcher direction is changed. - /// - private bool flipCatcherPlate; - /// /// Width of the area that can be used to attempt catches during gameplay. /// @@ -339,8 +334,6 @@ namespace osu.Game.Rulesets.Catch.UI skin.GetConfig(CatchSkinColour.HyperDash)?.Value ?? DEFAULT_HYPER_DASH_COLOUR; - flipCatcherPlate = skin.GetConfig(CatchSkinConfiguration.FlipCatcherPlate)?.Value ?? true; - runHyperDashStateTransition(HyperDashing); } @@ -352,8 +345,7 @@ namespace osu.Game.Rulesets.Catch.UI body.Scale = scaleFromDirection; // Inverse of catcher scale is applied here, as catcher gets scaled by circle size and so do the incoming fruit. - caughtObjectContainer.Scale = (1 / Scale.X) * (flipCatcherPlate ? scaleFromDirection : Vector2.One); - hitExplosionContainer.Scale = flipCatcherPlate ? scaleFromDirection : Vector2.One; + caughtObjectContainer.Scale = new Vector2(1 / Scale.X); // Correct overshooting. if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) || From 2981ebe3d5725e4e26ad2d7b9ec22b9afe87fdf5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 14 Feb 2024 17:13:44 +0900 Subject: [PATCH 108/223] Fix inspection --- .../Rulesets/TestSceneRulesetSkinProvidingContainer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs index 11f3fe660d..981258e8d1 100644 --- a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs +++ b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs @@ -43,13 +43,13 @@ namespace osu.Game.Tests.Rulesets AddStep("setup provider", () => { - var rulesetSkinProvider = new RulesetSkinProvidingContainer(Ruleset.Value.CreateInstance(), Beatmap.Value.Beatmap, Beatmap.Value.Skin); - - rulesetSkinProvider.Add(requester = new SkinRequester()); - + requester = new SkinRequester(); requester.OnLoadAsync += () => textureOnLoad = requester.GetTexture("test-image"); - Child = rulesetSkinProvider; + Child = new RulesetSkinProvidingContainer(Ruleset.Value.CreateInstance(), Beatmap.Value.Beatmap, Beatmap.Value.Skin) + { + requester + }; }); AddAssert("requester got correct initial texture", () => textureOnLoad != null); From 6baa0999065adc10f3b61ee527fecc614f6fa1f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 10:12:01 +0100 Subject: [PATCH 109/223] Fix broken delay --- .../Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index e3c1746e14..bec5170377 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -188,7 +188,7 @@ namespace osu.Game.Overlays.Toolbar titleText.FadeOut(250, Easing.OutQuint); deltaValue.FadeIn(250, Easing.OutQuint) .Then().Delay(1000) - .Then().OnComplete(_ => + .Then().Schedule(() => { mainValue.Current.Value = after; deltaValue.Current.SetDefault(); From 153024e61b52dc60f7dba39ffc8b131db743fbf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 10:15:27 +0100 Subject: [PATCH 110/223] Increase transition durations slightly Maybe slightly better readability. Dunno. --- .../Toolbar/TransientUserStatisticsUpdateDisplay.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index bec5170377..9960dd4411 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -84,7 +84,7 @@ namespace osu.Game.Overlays.Toolbar if (update.After.PP != null) pp.Display(update.Before.PP ?? update.After.PP.Value, Math.Abs((update.After.PP - update.Before.PP) ?? 0M), update.After.PP.Value); - this.Delay(4000).FadeOut(500, Easing.OutQuint); + this.Delay(5000).FadeOut(500, Easing.OutQuint); }); } @@ -183,11 +183,11 @@ namespace osu.Game.Overlays.Toolbar titleText.Alpha = 1; deltaValue.Alpha = 0; - using (BeginDelayedSequence(1000)) + using (BeginDelayedSequence(1500)) { titleText.FadeOut(250, Easing.OutQuint); deltaValue.FadeIn(250, Easing.OutQuint) - .Then().Delay(1000) + .Then().Delay(1500) .Then().Schedule(() => { mainValue.Current.Value = after; From d189fa0f6907afbe9f8a83a10c6a712e793a9efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 11:53:41 +0100 Subject: [PATCH 111/223] Rename flag --- .../Visual/UserInterface/ThemeComparisonTestScene.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs b/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs index f0c4b5543f..3177695f44 100644 --- a/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs +++ b/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs @@ -14,18 +14,18 @@ namespace osu.Game.Tests.Visual.UserInterface { public abstract partial class ThemeComparisonTestScene : OsuGridTestScene { - private readonly bool showNoColourProvider; + private readonly bool showWithoutColourProvider; - protected ThemeComparisonTestScene(bool showNoColourProvider = true) - : base(1, showNoColourProvider ? 2 : 1) + protected ThemeComparisonTestScene(bool showWithoutColourProvider = true) + : base(1, showWithoutColourProvider ? 2 : 1) { - this.showNoColourProvider = showNoColourProvider; + this.showWithoutColourProvider = showWithoutColourProvider; } [BackgroundDependencyLoader] private void load(OsuColour colours) { - if (showNoColourProvider) + if (showWithoutColourProvider) { Cell(0, 0).AddRange(new[] { @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.UserInterface { var colourProvider = new OverlayColourProvider(colourScheme); - int col = showNoColourProvider ? 1 : 0; + int col = showWithoutColourProvider ? 1 : 0; Cell(0, col).Clear(); Cell(0, col).Add(new DependencyProvidingContainer From 8312f92b4ea24a981b6916f5207aaaf747471546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 12:24:28 +0100 Subject: [PATCH 112/223] Use better value for alignment --- osu.Game/Overlays/Comments/CommentAuthorLine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentAuthorLine.cs b/osu.Game/Overlays/Comments/CommentAuthorLine.cs index c269ab4c01..1f6fef4df3 100644 --- a/osu.Game/Overlays/Comments/CommentAuthorLine.cs +++ b/osu.Game/Overlays/Comments/CommentAuthorLine.cs @@ -57,7 +57,7 @@ namespace osu.Game.Overlays.Comments Add(new OwnerTitleBadge(ownerMeta.OwnerTitle ?? string.Empty) { // add top space to align with username - Margin = new MarginPadding { Top = 2f }, + Margin = new MarginPadding { Top = 1f }, }); } From 68247fa022c0ba3cbab5fe3c92457e11fb48c4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 13:21:37 +0100 Subject: [PATCH 113/223] Fix typo in json property name Would cause the mapper badge to never actually be shown in the real world. --- osu.Game/Online/API/Requests/Responses/Comment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 907632186c..e6a5559d1f 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -33,7 +33,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"votes_count")] public int VotesCount { get; set; } - [JsonProperty(@"commenatble_type")] + [JsonProperty(@"commentable_type")] public string CommentableType { get; set; } = null!; [JsonProperty(@"commentable_id")] From f0f37df67fea4f20cc117012457ffd2c9b3bfec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 15:27:17 +0100 Subject: [PATCH 114/223] Revert unnecessary change --- osu.Game/Screens/Select/FilterQueryParser.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 24580c9e96..5fb5859a3b 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -121,8 +121,7 @@ namespace osu.Game.Screens.Select value.EndsWith("ms", StringComparison.Ordinal) ? 1 : value.EndsWith('s') ? 1000 : value.EndsWith('m') ? 60000 : - value.EndsWith('h') ? 3600000 : - value.EndsWith('d') ? 86400000 : 1000; + value.EndsWith('h') ? 3600000 : 1000; private static bool tryParseFloatWithPoint(string value, out float result) => float.TryParse(value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out result); From d7dfc8b88aa5081a6765898a94097050c8441c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 15:55:57 +0100 Subject: [PATCH 115/223] Add failing test coverage for empty date filter not parsing --- osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 81a73fc99f..814b26a231 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -488,7 +488,8 @@ namespace osu.Game.Tests.NonVisual.Filtering new object[] { "0:3:" }, new object[] { "\"three days\"" }, new object[] { "0.1y0.1M2d" }, - new object[] { "0.99y0.99M2d" } + new object[] { "0.99y0.99M2d" }, + new object[] { string.Empty } }; [Test] From c24328dda347f8cd2196267790e225bb3f038d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 15:56:32 +0100 Subject: [PATCH 116/223] Abandon date filter if no meaningful time bound found during parsing --- osu.Game/Screens/Select/FilterQueryParser.cs | 23 +++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 5fb5859a3b..3612a84ff9 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -394,7 +394,8 @@ namespace osu.Game.Screens.Select if (match == null) return false; - DateTimeOffset dateTimeOffset = DateTimeOffset.Now; + DateTimeOffset? dateTimeOffset = null; + DateTimeOffset now = DateTimeOffset.Now; try { @@ -410,27 +411,27 @@ namespace osu.Game.Screens.Select switch (key) { case "seconds": - dateTimeOffset = dateTimeOffset.AddSeconds(-length); + dateTimeOffset = (dateTimeOffset ?? now).AddSeconds(-length); break; case "minutes": - dateTimeOffset = dateTimeOffset.AddMinutes(-length); + dateTimeOffset = (dateTimeOffset ?? now).AddMinutes(-length); break; case "hours": - dateTimeOffset = dateTimeOffset.AddHours(-length); + dateTimeOffset = (dateTimeOffset ?? now).AddHours(-length); break; case "days": - dateTimeOffset = dateTimeOffset.AddDays(-length); + dateTimeOffset = (dateTimeOffset ?? now).AddDays(-length); break; case "months": - dateTimeOffset = dateTimeOffset.AddMonths(-(int)length); + dateTimeOffset = (dateTimeOffset ?? now).AddMonths(-(int)length); break; case "years": - dateTimeOffset = dateTimeOffset.AddYears(-(int)length); + dateTimeOffset = (dateTimeOffset ?? now).AddYears(-(int)length); break; } } @@ -438,11 +439,13 @@ namespace osu.Game.Screens.Select } catch (ArgumentOutOfRangeException) { - dateTimeOffset = DateTimeOffset.MinValue; - dateTimeOffset = dateTimeOffset.AddMilliseconds(1); + dateTimeOffset = DateTimeOffset.MinValue.AddMilliseconds(1); } - return tryUpdateCriteriaRange(ref dateRange, reverseInequalityOperator(op), dateTimeOffset); + if (!dateTimeOffset.HasValue) + return false; + + return tryUpdateCriteriaRange(ref dateRange, reverseInequalityOperator(op), dateTimeOffset.Value); } // Function to reverse an Operator From a8ae0a032f67900b8466263ac3ceb5f1b79b95d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 15:58:38 +0100 Subject: [PATCH 117/223] Simplify parsing --- osu.Game/Screens/Select/FilterQueryParser.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 3612a84ff9..17af0ee8ba 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -403,9 +403,12 @@ namespace osu.Game.Screens.Select foreach (string key in keys) { - if (match[key].Success) + if (!match.TryGetValue(key, out var group) || !group.Success) + continue; + + if (group.Success) { - if (!tryParseDoubleWithPoint(match[key].Value, out double length)) + if (!tryParseDoubleWithPoint(group.Value, out double length)) return false; switch (key) From f1d69abdc8d56502b23beccf62827518275cdc90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 15:59:07 +0100 Subject: [PATCH 118/223] Rename test --- osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 814b26a231..a5aac0a4ce 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -532,7 +532,7 @@ namespace osu.Game.Tests.NonVisual.Filtering } [Test] - public void TestOutofrangeDateQuery() + public void TestOutOfRangeDateQuery() { const string query = "played<10000y"; var filterCriteria = new FilterCriteria(); From 414066fd34f18db433fc4c3c2fc10f3624989924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 16:07:42 +0100 Subject: [PATCH 119/223] Inline problematic function (and rename things to make more sense) --- osu.Game/Screens/Select/FilterQueryParser.cs | 67 +++++++++++--------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 17af0ee8ba..278ca1ac5f 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -63,7 +63,7 @@ namespace osu.Game.Screens.Select case "played": case "lastplayed": - return tryUpdateDateRange(ref criteria.LastPlayed, op, value); + return tryUpdateDateAgoRange(ref criteria.LastPlayed, op, value); case "divisor": return TryUpdateCriteriaRange(ref criteria.BeatDivisor, op, value, tryParseInt); @@ -381,10 +381,42 @@ namespace osu.Game.Screens.Select return tryUpdateCriteriaRange(ref criteria.Length, op, totalLength, minScale / 2.0); } - private static bool tryUpdateDateRange(ref FilterCriteria.OptionalRange dateRange, Operator op, string val) + /// + /// This function is intended for parsing "days / months / years ago" type filters. + /// + private static bool tryUpdateDateAgoRange(ref FilterCriteria.OptionalRange dateRange, Operator op, string val) { - if (op == Operator.Equal) - return false; + switch (op) + { + case Operator.Equal: + // an equality filter is difficult to define for support here. + // if "3 months 2 days ago" means a single concrete time instant, such a filter is basically useless. + // if it means a range of 24 hours, then that is annoying to write and also comes with its own implications + // (does it mean "time instant 3 months 2 days ago, within 12 hours of tolerance either direction"? + // does it mean "the full calendar day, from midnight to midnight, 3 months 2 days ago"?) + // as such, for simplicity, just refuse to support this. + return false; + + // for the remaining operators, since the value provided to this function is an "ago" type value + // (as in, referring to some amount of time back), + // we'll want to flip the operator, such that `>5d` means "more than five days ago", as in "*before* five days ago", + // as intended by the user. + case Operator.Less: + op = Operator.Greater; + break; + + case Operator.LessOrEqual: + op = Operator.GreaterOrEqual; + break; + + case Operator.Greater: + op = Operator.Less; + break; + + case Operator.GreaterOrEqual: + op = Operator.LessOrEqual; + break; + } GroupCollection? match = null; @@ -448,32 +480,7 @@ namespace osu.Game.Screens.Select if (!dateTimeOffset.HasValue) return false; - return tryUpdateCriteriaRange(ref dateRange, reverseInequalityOperator(op), dateTimeOffset.Value); - } - - // Function to reverse an Operator - private static Operator reverseInequalityOperator(Operator ope) - { - switch (ope) - { - default: - throw new ArgumentOutOfRangeException(nameof(ope), $"Unsupported operator {ope}"); - - case Operator.Equal: - return Operator.Equal; - - case Operator.Greater: - return Operator.Less; - - case Operator.GreaterOrEqual: - return Operator.LessOrEqual; - - case Operator.Less: - return Operator.Greater; - - case Operator.LessOrEqual: - return Operator.GreaterOrEqual; - } + return tryUpdateCriteriaRange(ref dateRange, op, dateTimeOffset.Value); } } } From f7bea00564b7ac537b92a4eb9c4fe395bffb27d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 16:19:32 +0100 Subject: [PATCH 120/223] Improve test coverage --- .../Filtering/FilterQueryParserTest.cs | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index a5aac0a4ce..12d6060351 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -508,8 +508,11 @@ namespace osu.Game.Tests.NonVisual.Filtering const string query = "played>50"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual(false, filterCriteria.LastPlayed.Max == null); - Assert.AreEqual(true, filterCriteria.LastPlayed.Min == null); + Assert.That(filterCriteria.LastPlayed.Max, Is.Not.Null); + Assert.That(filterCriteria.LastPlayed.Min, Is.Null); + // the parser internally references `DateTimeOffset.Now`, so to not make things too annoying for tests, just assume some tolerance + // (irrelevant in proportion to the actual filter proscribed). + Assert.That(filterCriteria.LastPlayed.Max, Is.EqualTo(DateTimeOffset.Now.AddDays(-50)).Within(TimeSpan.FromSeconds(5))); } [Test] @@ -518,8 +521,25 @@ namespace osu.Game.Tests.NonVisual.Filtering const string query = "played<50"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual(true, filterCriteria.LastPlayed.Max == null); - Assert.AreEqual(false, filterCriteria.LastPlayed.Min == null); + Assert.That(filterCriteria.LastPlayed.Max, Is.Null); + Assert.That(filterCriteria.LastPlayed.Min, Is.Not.Null); + // the parser internally references `DateTimeOffset.Now`, so to not make things too annoying for tests, just assume some tolerance + // (irrelevant in proportion to the actual filter proscribed). + Assert.That(filterCriteria.LastPlayed.Min, Is.EqualTo(DateTimeOffset.Now.AddDays(-50)).Within(TimeSpan.FromSeconds(5))); + } + + [Test] + public void TestBothSidesDateQuery() + { + const string query = "played>3M played<1y6M"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.That(filterCriteria.LastPlayed.Min, Is.Not.Null); + Assert.That(filterCriteria.LastPlayed.Max, Is.Not.Null); + // the parser internally references `DateTimeOffset.Now`, so to not make things too annoying for tests, just assume some tolerance + // (irrelevant in proportion to the actual filter proscribed). + Assert.That(filterCriteria.LastPlayed.Min, Is.EqualTo(DateTimeOffset.Now.AddYears(-1).AddMonths(-6)).Within(TimeSpan.FromSeconds(5))); + Assert.That(filterCriteria.LastPlayed.Max, Is.EqualTo(DateTimeOffset.Now.AddMonths(-3)).Within(TimeSpan.FromSeconds(5))); } [Test] From ae9a2661ace43a96a4fbf26072ed3efd0dc0ba54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 16:20:47 +0100 Subject: [PATCH 121/223] Sprinkle some raw string prefixes --- osu.Game/Screens/Select/FilterQueryParser.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 278ca1ac5f..2c4077dacf 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -431,7 +431,7 @@ namespace osu.Game.Screens.Select try { - List keys = new List { "seconds", "minutes", "hours", "days", "months", "years" }; + List keys = new List { @"seconds", @"minutes", @"hours", @"days", @"months", @"years" }; foreach (string key in keys) { @@ -445,27 +445,27 @@ namespace osu.Game.Screens.Select switch (key) { - case "seconds": + case @"seconds": dateTimeOffset = (dateTimeOffset ?? now).AddSeconds(-length); break; - case "minutes": + case @"minutes": dateTimeOffset = (dateTimeOffset ?? now).AddMinutes(-length); break; - case "hours": + case @"hours": dateTimeOffset = (dateTimeOffset ?? now).AddHours(-length); break; - case "days": + case @"days": dateTimeOffset = (dateTimeOffset ?? now).AddDays(-length); break; - case "months": + case @"months": dateTimeOffset = (dateTimeOffset ?? now).AddMonths(-(int)length); break; - case "years": + case @"years": dateTimeOffset = (dateTimeOffset ?? now).AddYears(-(int)length); break; } From 53884f61c35a573273922ce3976af6b75c598a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 16:41:41 +0100 Subject: [PATCH 122/223] Apply suggested changes --- .../TransientUserStatisticsUpdateDisplay.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index 9960dd4411..52923ea178 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -127,7 +127,7 @@ namespace osu.Game.Overlays.Toolbar ValuePrefix = mainValuePrefix, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Font = OsuFont.GetFont(), + Font = OsuFont.GetFont().With(fixedWidth: true), }, new Container { @@ -140,7 +140,7 @@ namespace osu.Game.Overlays.Toolbar { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Font = OsuFont.GetFont(size: 12, fixedWidth: false, weight: FontWeight.SemiBold), + Font = OsuFont.GetFont(size: 12, fixedWidth: true, weight: FontWeight.SemiBold), AlwaysPresent = true, }, titleText = new OsuSpriteText @@ -183,11 +183,11 @@ namespace osu.Game.Overlays.Toolbar titleText.Alpha = 1; deltaValue.Alpha = 0; - using (BeginDelayedSequence(1500)) + using (BeginDelayedSequence(1200)) { - titleText.FadeOut(250, Easing.OutQuint); - deltaValue.FadeIn(250, Easing.OutQuint) - .Then().Delay(1500) + titleText.FadeOut(250, Easing.OutQuad); + deltaValue.FadeIn(250, Easing.OutQuad) + .Then().Delay(500) .Then().Schedule(() => { mainValue.Current.Value = after; @@ -200,9 +200,9 @@ namespace osu.Game.Overlays.Toolbar private partial class Counter : RollingCounter where T : struct, IEquatable, IFormattable { - public const double ROLLING_DURATION = 500; + public const double ROLLING_DURATION = 1500; - public FontUsage Font { get; init; } = OsuFont.Default; + public FontUsage Font { get; init; } = OsuFont.Default.With(fixedWidth: true); public string ValuePrefix { @@ -217,7 +217,13 @@ namespace osu.Game.Overlays.Toolbar private string valuePrefix = string.Empty; protected override LocalisableString FormatCount(T count) => LocalisableString.Format(@"{0}{1:N0}", ValuePrefix, count); - protected override OsuSpriteText CreateSpriteText() => base.CreateSpriteText().With(t => t.Font = Font); + + protected override OsuSpriteText CreateSpriteText() => base.CreateSpriteText().With(t => + { + t.Font = Font; + t.Spacing = new Vector2(-1.5f, 0); + }); + protected override double RollingDuration => ROLLING_DURATION; } } From aae431e8f6f414abe1155f005d33cf111493220d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 14 Feb 2024 16:48:31 +0100 Subject: [PATCH 123/223] Cancel rolling properly --- .../TransientUserStatisticsUpdateDisplay.cs | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index 52923ea178..50fc54088f 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -98,6 +99,7 @@ namespace osu.Game.Overlays.Toolbar private Counter mainValue = null!; private Counter deltaValue = null!; private OsuSpriteText titleText = null!; + private ScheduledDelegate? valueUpdateSchedule; [Resolved] private OsuColour colours { get; set; } = null!; @@ -159,6 +161,9 @@ namespace osu.Game.Overlays.Toolbar public void Display(T before, T delta, T after) { + valueUpdateSchedule?.Cancel(); + valueUpdateSchedule = null; + int comparison = valueComparer.Compare(before, after); if (comparison > 0) @@ -186,13 +191,16 @@ namespace osu.Game.Overlays.Toolbar using (BeginDelayedSequence(1200)) { titleText.FadeOut(250, Easing.OutQuad); - deltaValue.FadeIn(250, Easing.OutQuad) - .Then().Delay(500) - .Then().Schedule(() => - { - mainValue.Current.Value = after; - deltaValue.Current.SetDefault(); - }); + deltaValue.FadeIn(250, Easing.OutQuad); + + using (BeginDelayedSequence(1250)) + { + valueUpdateSchedule = Schedule(() => + { + mainValue.Current.Value = after; + deltaValue.Current.SetDefault(); + }); + } } } } From c175e036007bf68e0ad131f7d01e31a6b5a7fea8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Feb 2024 02:53:38 +0800 Subject: [PATCH 124/223] Inline rolling duration variable --- .../Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index 50fc54088f..b77a4cfb94 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -208,8 +208,6 @@ namespace osu.Game.Overlays.Toolbar private partial class Counter : RollingCounter where T : struct, IEquatable, IFormattable { - public const double ROLLING_DURATION = 1500; - public FontUsage Font { get; init; } = OsuFont.Default.With(fixedWidth: true); public string ValuePrefix @@ -232,7 +230,7 @@ namespace osu.Game.Overlays.Toolbar t.Spacing = new Vector2(-1.5f, 0); }); - protected override double RollingDuration => ROLLING_DURATION; + protected override double RollingDuration => 1500; } } } From 9ec79755fb2e2e467439f7086e7f720b607aef77 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Feb 2024 02:54:28 +0800 Subject: [PATCH 125/223] Standardise font specs --- .../Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs index b77a4cfb94..f56a1a3dd2 100644 --- a/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs +++ b/osu.Game/Overlays/Toolbar/TransientUserStatisticsUpdateDisplay.cs @@ -129,7 +129,6 @@ namespace osu.Game.Overlays.Toolbar ValuePrefix = mainValuePrefix, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Font = OsuFont.GetFont().With(fixedWidth: true), }, new Container { @@ -142,7 +141,7 @@ namespace osu.Game.Overlays.Toolbar { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Font = OsuFont.GetFont(size: 12, fixedWidth: true, weight: FontWeight.SemiBold), + Font = OsuFont.Default.With(size: 12, fixedWidth: true, weight: FontWeight.SemiBold), AlwaysPresent = true, }, titleText = new OsuSpriteText From 6e1b4152c07a250426e7e89e632db21043dd31cd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 15 Feb 2024 00:00:39 +0300 Subject: [PATCH 126/223] Redice allocations during aggregate beatmap sort --- .../Select/Carousel/CarouselBeatmapSet.cs | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 6d2e938fb7..d2b71b1d5e 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -127,12 +127,40 @@ namespace osu.Game.Screens.Select.Carousel /// /// All beatmaps which are not filtered and valid for display. /// - protected IEnumerable ValidBeatmaps => Beatmaps.Where(b => !b.Filtered.Value || b.State.Value == CarouselItemState.Selected).Select(b => b.BeatmapInfo); + protected IEnumerable ValidBeatmaps + { + get + { + foreach (var item in Items) // iterating over Items directly to not allocate 2 enumerators + { + if (item is CarouselBeatmap b && (!b.Filtered.Value || b.State.Value == CarouselItemState.Selected)) + yield return b.BeatmapInfo; + } + } + } + + /// + /// Whether there are available beatmaps which are not filtered and valid for display. + /// Cheaper alternative to .Any() + /// + public bool HasValidBeatmaps + { + get + { + foreach (var item in Items) // iterating over Items directly to not allocate 2 enumerators + { + if (item is CarouselBeatmap b && (!b.Filtered.Value || b.State.Value == CarouselItemState.Selected)) + return true; + } + + return false; + } + } private int compareUsingAggregateMax(CarouselBeatmapSet other, Func func) { - bool ourBeatmaps = ValidBeatmaps.Any(); - bool otherBeatmaps = other.ValidBeatmaps.Any(); + bool ourBeatmaps = HasValidBeatmaps; + bool otherBeatmaps = other.HasValidBeatmaps; if (!ourBeatmaps && !otherBeatmaps) return 0; if (!ourBeatmaps) return -1; From 80abf6aab346b2f5eed5745c81a521547bf81c26 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Feb 2024 09:45:24 +0800 Subject: [PATCH 127/223] Avoid some further enumerator allocations --- osu.Game/Screens/Select/Carousel/CarouselGroup.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs index b2ca117cec..62d694976f 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Extensions.ListExtensions; +using osu.Framework.Lists; namespace osu.Game.Screens.Select.Carousel { @@ -12,7 +14,7 @@ namespace osu.Game.Screens.Select.Carousel { public override DrawableCarouselItem? CreateDrawableRepresentation() => null; - public IReadOnlyList Items => items; + public SlimReadOnlyListWrapper Items => items.AsSlimReadOnly(); public int TotalItemsNotFiltered { get; private set; } From 674ee91bb5dd28d9f4f79a3f0c6d220274a8c3dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Feb 2024 11:40:50 +0800 Subject: [PATCH 128/223] Define aggregate max delegates as static to further reduce allocations --- osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index d2b71b1d5e..cee68cf9a5 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -91,19 +91,19 @@ namespace osu.Game.Screens.Select.Carousel break; case SortMode.LastPlayed: - comparison = -compareUsingAggregateMax(otherSet, b => (b.LastPlayed ?? DateTimeOffset.MinValue).ToUnixTimeSeconds()); + comparison = -compareUsingAggregateMax(otherSet, static b => (b.LastPlayed ?? DateTimeOffset.MinValue).ToUnixTimeSeconds()); break; case SortMode.BPM: - comparison = compareUsingAggregateMax(otherSet, b => b.BPM); + comparison = compareUsingAggregateMax(otherSet, static b => b.BPM); break; case SortMode.Length: - comparison = compareUsingAggregateMax(otherSet, b => b.Length); + comparison = compareUsingAggregateMax(otherSet, static b => b.Length); break; case SortMode.Difficulty: - comparison = compareUsingAggregateMax(otherSet, b => b.StarRating); + comparison = compareUsingAggregateMax(otherSet, static b => b.StarRating); break; case SortMode.DateSubmitted: From a03835bf1c472a477dc992b7c2d05357e1b07da4 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 14 Feb 2024 20:13:27 -0800 Subject: [PATCH 129/223] Improve comments --- .../Overlays/Profile/Header/Components/GlobalRankDisplay.cs | 2 +- osu.Game/Users/UserRankPanel.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs index dcd4129b45..d32f56ab1b 100644 --- a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs +++ b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Profile.Header.Components Content = s.NewValue?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; }, true); - // needed as statistics doesn't populate User + // needed as `UserStatistics` doesn't populate `User` User.BindValueChanged(u => { var rankHighest = u.NewValue?.RankHighest; diff --git a/osu.Game/Users/UserRankPanel.cs b/osu.Game/Users/UserRankPanel.cs index 4a00583094..0b8a5166e6 100644 --- a/osu.Game/Users/UserRankPanel.cs +++ b/osu.Game/Users/UserRankPanel.cs @@ -167,8 +167,8 @@ namespace osu.Game.Users new GlobalRankDisplay { UserStatistics = { BindTarget = statistics }, - // TODO: make highest rank update, as api.LocalUser doesn't update - // maybe move to statistics in api, so `SoloStatisticsWatcher` can update the value + // TODO: make highest rank update, as `api.LocalUser` doesn't update + // maybe move to `UserStatistics` in api, so `SoloStatisticsWatcher` can update the value User = { BindTarget = user }, }, countryRankDisplay = new ProfileValueDisplay(true) From 0c25a9a460a23740ebfd6f8c8969f0661b1e2cf6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 15 Feb 2024 07:31:01 +0300 Subject: [PATCH 130/223] Add extra bottom space for catcher to not look cut off on tall resolutions --- .../UI/CatchPlayfieldAdjustmentContainer.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs index 64d17b08b6..74dfa6c1fd 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs @@ -20,6 +20,9 @@ namespace osu.Game.Rulesets.Catch.UI const float base_game_width = 1024f; const float base_game_height = 768f; + // extra bottom space for the catcher to not get cut off at tall resolutions lower than 4:3 (e.g. 5:4). number chosen based on testing with maximum catcher scale (i.e. CS 0). + const float extra_bottom_space = 200f; + Anchor = Anchor.Centre; Origin = Anchor.Centre; @@ -31,7 +34,8 @@ namespace osu.Game.Rulesets.Catch.UI Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.X, - Height = base_game_height, + Height = base_game_height + extra_bottom_space, + Y = extra_bottom_space / 2, Masking = true, Child = new Container { From 9e9297bfb3c06b816a8416cac44ad05f819e998a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Feb 2024 13:22:03 +0800 Subject: [PATCH 131/223] Add inline documentation as to why classic mod is not ranked See https://github.com/ppy/osu/pull/27149#issuecomment-1939509941. --- osu.Game/Rulesets/Mods/ModClassic.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Rulesets/Mods/ModClassic.cs b/osu.Game/Rulesets/Mods/ModClassic.cs index 16cb928bd4..b0f6ba9374 100644 --- a/osu.Game/Rulesets/Mods/ModClassic.cs +++ b/osu.Game/Rulesets/Mods/ModClassic.cs @@ -19,5 +19,16 @@ namespace osu.Game.Rulesets.Mods public override LocalisableString Description => "Feeling nostalgic?"; public override ModType Type => ModType.Conversion; + + /// + /// Classic mods are not to be ranked yet due to compatibility and multiplier concerns. + /// Right now classic mods are considered, for leaderboard purposes, to be equal as scores set on osu-stable. + /// But this is not the case. + /// + /// Some examples for things to resolve before even considering this: + /// - Hit windows differ (https://github.com/ppy/osu/issues/11311). + /// - Sliders always gives combo for slider end, even on miss (https://github.com/ppy/osu/issues/11769). + /// + public sealed override bool Ranked => false; } } From 401bd91dc4aefee2582055b798a471d240e17650 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 14 Feb 2024 22:57:38 -0800 Subject: [PATCH 132/223] Add visual test showing overflow on dropdown menu items --- .../Visual/UserInterface/TestSceneOsuDropdown.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuDropdown.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuDropdown.cs index 1678890b73..63f7a2f2cc 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuDropdown.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuDropdown.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Input.States; using osu.Framework.Testing; -using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; @@ -18,13 +17,22 @@ namespace osu.Game.Tests.Visual.UserInterface public partial class TestSceneOsuDropdown : ThemeComparisonTestScene { protected override Drawable CreateContent() => - new OsuEnumDropdown + new OsuEnumDropdown { Anchor = Anchor.Centre, Origin = Anchor.TopCentre, Width = 150 }; + private enum TestEnum + { + [System.ComponentModel.Description("Option")] + Option, + + [System.ComponentModel.Description("Really lonnnnnnng option")] + ReallyLongOption, + } + [Test] // todo: this can be written much better if ThemeComparisonTestScene has a manual input manager public void TestBackAction() @@ -43,7 +51,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("press back", () => dropdown().OnPressed(new KeyBindingPressEvent(new InputState(), GlobalAction.Back))); AddAssert("closed", () => dropdown().ChildrenOfType().Single().State == MenuState.Closed); - OsuEnumDropdown dropdown() => this.ChildrenOfType>().First(); + OsuEnumDropdown dropdown() => this.ChildrenOfType>().First(); } } } From 3d08bc5605242c097531eae2945a89abe7f80955 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 14 Feb 2024 23:00:30 -0800 Subject: [PATCH 133/223] Truncate long dropdown menu item text and show tooltip --- osu.Game/Graphics/UserInterface/OsuDropdown.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 2dc701dc9d..38e90bf4ea 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -186,6 +186,8 @@ namespace osu.Game.Graphics.UserInterface : base(item) { Foreground.Padding = new MarginPadding(2); + Foreground.AutoSizeAxes = Axes.Y; + Foreground.RelativeSizeAxes = Axes.X; Masking = true; CornerRadius = corner_radius; @@ -247,11 +249,12 @@ namespace osu.Game.Graphics.UserInterface Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, }, - Label = new OsuSpriteText + Label = new TruncatingSpriteText { - X = 15, + Padding = new MarginPadding { Left = 15 }, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, }, }; } From a037dbf8debe7bcecfa904d68c20875d3844236d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Feb 2024 18:33:48 +0900 Subject: [PATCH 134/223] Update test to set Child in more canonical manner --- .../Rulesets/TestSceneRulesetSkinProvidingContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs index 981258e8d1..b089144233 100644 --- a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs +++ b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Rulesets Child = new RulesetSkinProvidingContainer(Ruleset.Value.CreateInstance(), Beatmap.Value.Beatmap, Beatmap.Value.Skin) { - requester + Child = requester }; }); From 95e745c6fbabce01dda192e567546185bfe62e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 15 Feb 2024 10:16:06 +0100 Subject: [PATCH 135/223] Use better messaging for selected submission failure reasons These have been cropping up rather often lately, mostly courtesy of linux users, but not only: https://github.com/ppy/osu/issues/26840 https://github.com/ppy/osu/issues/27008 https://github.com/ppy/osu/discussions/26962 so this is a proposal for slightly improved messaging for such cases to hopefully get users on the right track. The original error is still logged to network log, so there's no information loss. --- osu.Game/Screens/Play/SubmittingPlayer.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index c45d46e993..c759710aba 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -140,7 +140,13 @@ namespace osu.Game.Screens.Play { switch (exception.Message) { - case "expired token": + case @"missing token header": + case @"invalid client hash": + case @"invalid verification hash": + Logger.Log("You are not able to submit a score. Please ensure that you are using the latest version of the official game releases.", level: LogLevel.Important); + break; + + case @"expired token": Logger.Log("Score submission failed because your system clock is set incorrectly. Please check your system time, date and timezone.", level: LogLevel.Important); break; From 898d5ce88bd4d249f98b8fe7cc6dd5e7cdd635d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 15 Feb 2024 10:40:40 +0100 Subject: [PATCH 136/223] Show selected submission failure messages even in solo Previously, if a `SubmittingPlayer` instance deemed it okay to proceed with gameplay despite submission failure, it would silently log all errors and proceed, but the score would still not be submitted. This feels a bit anti-user in the cases wherein something is genuinely wrong with either the client or web, so things like token verification failures or API failures are now shown as notifications to give the user an indication that something went wrong at all. Selected cases (non-user-playable mod, logged out, beatmap is not online) are still logged silently because those are either known and expected, or someone is messing with things. --- osu.Game/Screens/Play/SoloPlayer.cs | 2 +- osu.Game/Screens/Play/SubmittingPlayer.cs | 33 ++++++++++++----------- osu.Game/Tests/Visual/TestPlayer.cs | 2 +- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Play/SoloPlayer.cs b/osu.Game/Screens/Play/SoloPlayer.cs index f7ae3eb62b..f4cf2da364 100644 --- a/osu.Game/Screens/Play/SoloPlayer.cs +++ b/osu.Game/Screens/Play/SoloPlayer.cs @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Play Scores = { BindTarget = LeaderboardScores } }; - protected override bool HandleTokenRetrievalFailure(Exception exception) => false; + protected override bool ShouldExitOnTokenRetrievalFailure(Exception exception) => false; protected override Task ImportScore(Score score) { diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index c759710aba..0873f60791 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Play token = r.ID; tcs.SetResult(true); }; - req.Failure += handleTokenFailure; + req.Failure += ex => handleTokenFailure(ex, displayNotification: true); api.Queue(req); @@ -128,14 +128,20 @@ namespace osu.Game.Screens.Play return true; - void handleTokenFailure(Exception exception) + void handleTokenFailure(Exception exception, bool displayNotification = false) { tcs.SetResult(false); - if (HandleTokenRetrievalFailure(exception)) + bool shouldExit = ShouldExitOnTokenRetrievalFailure(exception); + + if (displayNotification || shouldExit) { + string whatWillHappen = shouldExit + ? "You are not able to submit a score." + : "The following score will not be submitted."; + if (string.IsNullOrEmpty(exception.Message)) - Logger.Error(exception, "Failed to retrieve a score submission token."); + Logger.Error(exception, $"{whatWillHappen} Failed to retrieve a score submission token."); else { switch (exception.Message) @@ -143,31 +149,28 @@ namespace osu.Game.Screens.Play case @"missing token header": case @"invalid client hash": case @"invalid verification hash": - Logger.Log("You are not able to submit a score. Please ensure that you are using the latest version of the official game releases.", level: LogLevel.Important); + Logger.Log($"{whatWillHappen} Please ensure that you are using the latest version of the official game releases.", level: LogLevel.Important); break; case @"expired token": - Logger.Log("Score submission failed because your system clock is set incorrectly. Please check your system time, date and timezone.", level: LogLevel.Important); + Logger.Log($"{whatWillHappen} Your system clock is set incorrectly. Please check your system time, date and timezone.", level: LogLevel.Important); break; default: - Logger.Log($"You are not able to submit a score: {exception.Message}", level: LogLevel.Important); + Logger.Log($"{whatWillHappen} {exception.Message}", level: LogLevel.Important); break; } } + } + if (shouldExit) + { Schedule(() => { ValidForResume = false; this.Exit(); }); } - else - { - // Gameplay is allowed to continue, but we still should keep track of the error. - // In the future, this should be visible to the user in some way. - Logger.Log($"Score submission token retrieval failed ({exception.Message})"); - } } } @@ -176,7 +179,7 @@ namespace osu.Game.Screens.Play /// /// The error causing the failure. /// Whether gameplay should be immediately exited as a result. Returning false allows the gameplay session to continue. Defaults to true. - protected virtual bool HandleTokenRetrievalFailure(Exception exception) => true; + protected virtual bool ShouldExitOnTokenRetrievalFailure(Exception exception) => true; protected override async Task PrepareScoreForResultsAsync(Score score) { @@ -237,7 +240,7 @@ namespace osu.Game.Screens.Play /// /// Construct a request to be used for retrieval of the score token. - /// Can return null, at which point will be fired. + /// Can return null, at which point will be fired. /// [CanBeNull] protected abstract APIRequest CreateTokenRequest(); diff --git a/osu.Game/Tests/Visual/TestPlayer.cs b/osu.Game/Tests/Visual/TestPlayer.cs index d9cae6b03b..579a1934e0 100644 --- a/osu.Game/Tests/Visual/TestPlayer.cs +++ b/osu.Game/Tests/Visual/TestPlayer.cs @@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual PauseOnFocusLost = pauseOnFocusLost; } - protected override bool HandleTokenRetrievalFailure(Exception exception) => false; + protected override bool ShouldExitOnTokenRetrievalFailure(Exception exception) => false; protected override APIRequest CreateTokenRequest() { From e91d38872d99dc3904b3664331b94f097881a455 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Feb 2024 18:28:59 +0800 Subject: [PATCH 137/223] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index d7f29beeb3..f61ff79b9f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index a4cd26a372..506bebfd47 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -23,6 +23,6 @@ iossimulator-x64 - + From 755bc7c0507f3ad7b3c8e5b7ed5592ad78497b43 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Feb 2024 20:07:55 +0900 Subject: [PATCH 138/223] Fix resolution scaling --- .../Mods/ManiaModHidden.cs | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 211f21513d..12f17c6c59 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -3,11 +3,14 @@ using System; using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Game.Rulesets.Mania.UI; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Rulesets.Mania.Skinning; using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Mods { @@ -18,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Mods /// private const float reference_playfield_height = 768; - private const float min_coverage = 160 / reference_playfield_height; + private const float min_coverage = 160f / reference_playfield_height; private const float max_coverage = 400f / reference_playfield_height; private const float coverage_increase_per_combo = 0.5f / reference_playfield_height; @@ -49,17 +52,38 @@ namespace osu.Game.Rulesets.Mania.Mods private partial class LegacyPlayfieldCover : PlayfieldCoveringWrapper { + [Resolved] + private ISkinSource skin { get; set; } = null!; + + private IBindable? hitPosition; + public LegacyPlayfieldCover(Drawable content) : base(content) { } + protected override void LoadComplete() + { + base.LoadComplete(); + + skin.SourceChanged += onSkinChanged; + onSkinChanged(); + } + + private void onSkinChanged() + { + hitPosition = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.HitPosition); + } + protected override float GetHeight(float coverage) { - if (DrawHeight == 0) + // In osu!stable, the cover is applied in absolute (x768) coordinates from the hit position. + float availablePlayfieldHeight = Math.Abs(reference_playfield_height - (hitPosition?.Value ?? Stage.HIT_TARGET_POSITION)); + + if (availablePlayfieldHeight == 0) return base.GetHeight(coverage); - return base.GetHeight(coverage) * reference_playfield_height / DrawHeight; + return base.GetHeight(coverage) * reference_playfield_height / availablePlayfieldHeight; } } } From 9c22fa3a9fbae0fb568e5a7b36d4c688268add3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 15 Feb 2024 12:13:01 +0100 Subject: [PATCH 139/223] Fix android test project compile failures --- .../osu.Game.Tests.Android.csproj | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj index 889f0a3583..b02425eadd 100644 --- a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj +++ b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj @@ -31,4 +31,22 @@ + + + + + XamarinJetbrainsAnnotations + + + From d1a51b474c2a4d8ebdd780cc42f0d5ff63a8ab9a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Feb 2024 21:24:00 +0900 Subject: [PATCH 140/223] Adjust tests --- .../Mods/TestSceneManiaModFadeIn.cs | 70 +++++++++++++++++-- .../Mods/TestSceneManiaModHidden.cs | 70 +++++++++++++++++-- .../Mods/ManiaModHidden.cs | 15 ++-- 3 files changed, 142 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs index 2c8c151e7f..fc49dc528d 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs @@ -1,8 +1,14 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Mods @@ -11,9 +17,65 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); - [TestCase(0.5f)] - [TestCase(0.1f)] - [TestCase(0.7f)] - public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModFadeIn { Coverage = { Value = coverage } }, PassCondition = () => true }); + [Test] + public void TestMinCoverageFullWidth() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + PassCondition = () => checkCoverage(ManiaModHidden.MIN_COVERAGE) + }); + } + + [Test] + public void TestMinCoverageHalfWidth() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + PassCondition = () => checkCoverage(ManiaModHidden.MIN_COVERAGE) + }); + + AddStep("set playfield width to 0.5", () => Player.Width = 0.5f); + } + + [Test] + public void TestMaxCoverageFullWidth() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + PassCondition = () => checkCoverage(ManiaModHidden.MAX_COVERAGE) + }); + + AddStep("set combo to 480", () => Player.ScoreProcessor.Combo.Value = 480); + } + + [Test] + public void TestMaxCoverageHalfWidth() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + PassCondition = () => checkCoverage(ManiaModHidden.MAX_COVERAGE) + }); + + AddStep("set combo to 480", () => Player.ScoreProcessor.Combo.Value = 480); + AddStep("set playfield width to 0.5", () => Player.Width = 0.5f); + } + + private bool checkCoverage(float expected) + { + Drawable? cover = this.ChildrenOfType().FirstOrDefault(); + Drawable? filledArea = cover?.ChildrenOfType().LastOrDefault(); + + if (filledArea == null) + return false; + + float scale = cover!.DrawHeight / (768 - Stage.HIT_TARGET_POSITION); + + // A bit of lenience because the test may end up hitting hitobjects before any assertions. + return Precision.AlmostEquals(filledArea.DrawHeight / scale, expected, 0.1); + } } } diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs index 204f26f151..581cc3b33a 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs @@ -1,8 +1,14 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Mods @@ -11,9 +17,65 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); - [TestCase(0.5f)] - [TestCase(0.2f)] - [TestCase(0.8f)] - public void TestCoverage(float coverage) => CreateModTest(new ModTestData { Mod = new ManiaModHidden { Coverage = { Value = coverage } }, PassCondition = () => true }); + [Test] + public void TestMinCoverageFullWidth() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + PassCondition = () => checkCoverage(ManiaModHidden.MIN_COVERAGE) + }); + } + + [Test] + public void TestMinCoverageHalfWidth() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + PassCondition = () => checkCoverage(ManiaModHidden.MIN_COVERAGE) + }); + + AddStep("set playfield width to 0.5", () => Player.Width = 0.5f); + } + + [Test] + public void TestMaxCoverageFullWidth() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + PassCondition = () => checkCoverage(ManiaModHidden.MAX_COVERAGE) + }); + + AddStep("set combo to 480", () => Player.ScoreProcessor.Combo.Value = 480); + } + + [Test] + public void TestMaxCoverageHalfWidth() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + PassCondition = () => checkCoverage(ManiaModHidden.MAX_COVERAGE) + }); + + AddStep("set combo to 480", () => Player.ScoreProcessor.Combo.Value = 480); + AddStep("set playfield width to 0.5", () => Player.Width = 0.5f); + } + + private bool checkCoverage(float expected) + { + Drawable? cover = this.ChildrenOfType().FirstOrDefault(); + Drawable? filledArea = cover?.ChildrenOfType().LastOrDefault(); + + if (filledArea == null) + return false; + + float scale = cover!.DrawHeight / (768 - Stage.HIT_TARGET_POSITION); + + // A bit of lenience because the test may end up hitting hitobjects before any assertions. + return Precision.AlmostEquals(filledArea.DrawHeight / scale, expected, 0.1); + } } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index 12f17c6c59..b2c6988319 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -21,9 +21,9 @@ namespace osu.Game.Rulesets.Mania.Mods /// private const float reference_playfield_height = 768; - private const float min_coverage = 160f / reference_playfield_height; - private const float max_coverage = 400f / reference_playfield_height; - private const float coverage_increase_per_combo = 0.5f / reference_playfield_height; + public const float MIN_COVERAGE = 160f; + public const float MAX_COVERAGE = 400f; + private const float coverage_increase_per_combo = 0.5f; public override LocalisableString Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.Mods typeof(ManiaModCover) }).ToArray(); - public override BindableNumber Coverage { get; } = new BindableFloat(min_coverage); + public override BindableNumber Coverage { get; } = new BindableFloat(MIN_COVERAGE); protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AgainstScroll; private readonly BindableInt combo = new BindableInt(); @@ -45,7 +45,12 @@ namespace osu.Game.Rulesets.Mania.Mods combo.UnbindAll(); combo.BindTo(scoreProcessor.Combo); - combo.BindValueChanged(c => Coverage.Value = Math.Min(max_coverage, min_coverage + c.NewValue * coverage_increase_per_combo), true); + combo.BindValueChanged(c => + { + Coverage.Value = Math.Min( + MAX_COVERAGE / reference_playfield_height, + MIN_COVERAGE / reference_playfield_height + c.NewValue * coverage_increase_per_combo / reference_playfield_height); + }, true); } protected override PlayfieldCoveringWrapper CreateCover(Drawable content) => new LegacyPlayfieldCover(content); From 878fb2d10d8edb3f559e786751941d8ac3f2d05d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Feb 2024 22:05:25 +0900 Subject: [PATCH 141/223] Add break support --- .../Mods/TestSceneManiaModFadeIn.cs | 19 ++++++++++++ .../Mods/TestSceneManiaModHidden.cs | 19 ++++++++++++ .../Mods/ManiaModHidden.cs | 25 ++++++++++----- .../UI/PlayfieldCoveringWrapper.cs | 31 +++++++++++++------ 4 files changed, 78 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs index fc49dc528d..9620897983 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFadeIn.cs @@ -7,8 +7,12 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.Objects; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Mods @@ -64,6 +68,21 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods AddStep("set playfield width to 0.5", () => Player.Width = 0.5f); } + [Test] + public void TestNoCoverageDuringBreak() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + Beatmap = new Beatmap + { + HitObjects = Enumerable.Range(1, 100).Select(i => (HitObject)new Note { StartTime = 1000 + 200 * i }).ToList(), + Breaks = { new BreakPeriod(2000, 28000) } + }, + PassCondition = () => Player.IsBreakTime.Value && checkCoverage(0) + }); + } + private bool checkCoverage(float expected) { Drawable? cover = this.ChildrenOfType().FirstOrDefault(); diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs index 581cc3b33a..ae23c4573c 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHidden.cs @@ -7,8 +7,12 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.Objects; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Mods @@ -64,6 +68,21 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods AddStep("set playfield width to 0.5", () => Player.Width = 0.5f); } + [Test] + public void TestNoCoverageDuringBreak() + { + CreateModTest(new ModTestData + { + Mod = new ManiaModHidden(), + Beatmap = new Beatmap + { + HitObjects = Enumerable.Range(1, 100).Select(i => (HitObject)new Note { StartTime = 1000 + 200 * i }).ToList(), + Breaks = { new BreakPeriod(2000, 28000) } + }, + PassCondition = () => Player.IsBreakTime.Value && checkCoverage(0) + }); + } + private bool checkCoverage(float expected) { Drawable? cover = this.ChildrenOfType().FirstOrDefault(); diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index b2c6988319..5ddc627642 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -9,12 +9,15 @@ using osu.Game.Rulesets.Mania.UI; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Rulesets.Mania.Skinning; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play; using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Mods { - public partial class ManiaModHidden : ManiaModWithPlayfieldCover + public partial class ManiaModHidden : ManiaModWithPlayfieldCover, IApplicableToPlayer, IUpdatableByPlayfield { /// /// osu!stable is referenced to 768px. @@ -37,6 +40,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override BindableNumber Coverage { get; } = new BindableFloat(MIN_COVERAGE); protected override CoverExpandDirection ExpandDirection => CoverExpandDirection.AgainstScroll; + private readonly IBindable isBreakTime = new Bindable(); private readonly BindableInt combo = new BindableInt(); public override void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) @@ -45,12 +49,19 @@ namespace osu.Game.Rulesets.Mania.Mods combo.UnbindAll(); combo.BindTo(scoreProcessor.Combo); - combo.BindValueChanged(c => - { - Coverage.Value = Math.Min( - MAX_COVERAGE / reference_playfield_height, - MIN_COVERAGE / reference_playfield_height + c.NewValue * coverage_increase_per_combo / reference_playfield_height); - }, true); + } + + public void ApplyToPlayer(Player player) + { + isBreakTime.UnbindAll(); + isBreakTime.BindTo(player.IsBreakTime); + } + + public void Update(Playfield playfield) + { + Coverage.Value = isBreakTime.Value + ? 0 + : Math.Min(MAX_COVERAGE, MIN_COVERAGE + combo.Value * coverage_increase_per_combo) / reference_playfield_height; } protected override PlayfieldCoveringWrapper CreateCover(Drawable content) => new LegacyPlayfieldCover(content); diff --git a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs index 2b70c527ae..1cf2be7b06 100644 --- a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs +++ b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.UI private readonly IBindable scrollDirection = new Bindable(); - private float currentCoverage; + private float currentCoverageHeight; public PlayfieldCoveringWrapper(Drawable content) { @@ -106,23 +106,36 @@ namespace osu.Game.Rulesets.Mania.UI protected override void LoadComplete() { base.LoadComplete(); - - updateHeight(Coverage.Value); + updateCoverSize(true); } protected override void Update() { base.Update(); - - updateHeight((float)Interpolation.DampContinuously(currentCoverage, Coverage.Value, 25, Math.Abs(Time.Elapsed))); + updateCoverSize(false); } - private void updateHeight(float coverage) + private void updateCoverSize(bool instant) { - filled.Height = GetHeight(coverage); - gradient.Y = -GetHeight(coverage); + float targetCoverage; + float targetAlpha; - currentCoverage = coverage; + if (instant) + { + targetCoverage = Coverage.Value; + targetAlpha = Coverage.Value > 0 ? 1 : 0; + } + else + { + targetCoverage = (float)Interpolation.DampContinuously(currentCoverageHeight, Coverage.Value, 25, Math.Abs(Time.Elapsed)); + targetAlpha = (float)Interpolation.DampContinuously(gradient.Alpha, Coverage.Value > 0 ? 1 : 0, 25, Math.Abs(Time.Elapsed)); + } + + filled.Height = GetHeight(targetCoverage); + gradient.Y = -GetHeight(targetCoverage); + gradient.Alpha = targetAlpha; + + currentCoverageHeight = targetCoverage; } protected virtual float GetHeight(float coverage) => coverage; From e705190664cee548c402eb2e67ecbaf742341b62 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Feb 2024 23:23:49 +0800 Subject: [PATCH 142/223] Update windows icon metrics to match previous icon --- osu.Desktop/lazer.ico | Bin 67391 -> 76552 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/osu.Desktop/lazer.ico b/osu.Desktop/lazer.ico index f84866b8e93b4c7a449371b71a99b1a8c5567df1..a3280f0de0b6a935309c84594e8b83cdb7d2e43f 100644 GIT binary patch literal 76552 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

X~%=`gEKj(Ksd$CM;}+tqLyrwl(h2dj8hG;X_w+ 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 `fTbt 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 Date: Thu, 15 Feb 2024 16:40:58 +0100 Subject: [PATCH 143/223] Make dropdown text nicer --- osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs index 1cf2be7b06..d8d9705530 100644 --- a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs +++ b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -13,11 +14,12 @@ using osu.Framework.Utils; using osu.Game.Rulesets.UI.Scrolling; using osuTK; using osuTK.Graphics; +using Container = osu.Framework.Graphics.Containers.Container; namespace osu.Game.Rulesets.Mania.UI { ///

- /// A that has its contents partially hidden by an adjustable "cover". This is intended to be used in a playfield. + /// A that has its contents partially hidden by an adjustable "cover". This is intended to be used in a playfield. /// public partial class PlayfieldCoveringWrapper : CompositeDrawable { @@ -157,11 +159,13 @@ namespace osu.Game.Rulesets.Mania.UI /// /// The cover expands along the scrolling direction. /// + [Description("Along scroll")] AlongScroll, /// /// The cover expands against the scrolling direction. /// + [Description("Against scroll")] AgainstScroll } } From c4bcae86ec02c59dfd0a795ddb9a7f828201b8ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Feb 2024 00:43:20 +0800 Subject: [PATCH 144/223] Update iOS icon metrics to match previous icon --- ...0-5cbe0121-ed68-414f-9ddc-dd993ac97e62.png | Bin 278451 -> 453879 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/osu.iOS/Assets.xcassets/AppIcon.appiconset/300076680-5cbe0121-ed68-414f-9ddc-dd993ac97e62.png b/osu.iOS/Assets.xcassets/AppIcon.appiconset/300076680-5cbe0121-ed68-414f-9ddc-dd993ac97e62.png index 21f5f0f3a0901ed465ec468164bce1817fb4ea22..9287a71040091fb7a249018bff4133b91b12e1fc 100644 GIT binary patch literal 453879 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 K)~(TTivAB8ZcmZ` literal 278451 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

EM!on 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

b;UQhmR-aO6N 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�k+(fIDq7qxZKK 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�IQvA; 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

-2ku4wGs_zr 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 Date: Thu, 15 Feb 2024 23:05:13 +0100 Subject: [PATCH 145/223] Point launch.json to new build directory --- .vscode/launch.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index d93fddf42d..7c5225cff7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/osu.Desktop/bin/Debug/net6.0/osu!.dll" + "${workspaceRoot}/osu.Desktop/bin/Debug/net8.0/osu!.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build osu! (Debug)", @@ -19,7 +19,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/osu.Desktop/bin/Release/net6.0/osu!.dll" + "${workspaceRoot}/osu.Desktop/bin/Release/net8.0/osu!.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build osu! (Release)", @@ -31,7 +31,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/osu.Game.Tests/bin/Debug/net6.0/osu.Game.Tests.dll" + "${workspaceRoot}/osu.Game.Tests/bin/Debug/net8.0/osu.Game.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build tests (Debug)", @@ -43,7 +43,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/osu.Game.Tests/bin/Release/net6.0/osu.Game.Tests.dll" + "${workspaceRoot}/osu.Game.Tests/bin/Release/net8.0/osu.Game.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build tests (Release)", @@ -55,7 +55,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/osu.Desktop/bin/Debug/net6.0/osu!.dll", + "${workspaceRoot}/osu.Desktop/bin/Debug/net8.0/osu!.dll", "--tournament" ], "cwd": "${workspaceRoot}", @@ -68,7 +68,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/osu.Desktop/bin/Release/net6.0/osu!.dll", + "${workspaceRoot}/osu.Desktop/bin/Release/net8.0/osu!.dll", "--tournament" ], "cwd": "${workspaceRoot}", @@ -81,7 +81,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net6.0/osu.Game.Tournament.Tests.dll", + "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net8.0/osu.Game.Tournament.Tests.dll", "--tournament" ], "cwd": "${workspaceRoot}", @@ -94,7 +94,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net6.0/osu.Game.Tournament.Tests.dll", + "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net8.0/osu.Game.Tournament.Tests.dll", "--tournament" ], "cwd": "${workspaceRoot}", @@ -105,7 +105,7 @@ "name": "Benchmark", "type": "coreclr", "request": "launch", - "program": "${workspaceRoot}/osu.Game.Benchmarks/bin/Release/net6.0/osu.Game.Benchmarks.dll", + "program": "${workspaceRoot}/osu.Game.Benchmarks/bin/Release/net8.0/osu.Game.Benchmarks.dll", "args": [ "--filter", "*" From a9eac5924de12073d39e8c9b2b57f83be6185de2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Feb 2024 01:18:13 +0300 Subject: [PATCH 146/223] Remove seemingly unnecessary float casts --- osu.Game/Screens/Play/PlayerLoader.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 6154e443ef..fff1118622 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -550,8 +550,10 @@ namespace osu.Game.Screens.Play { if (!muteWarningShownOnce.Value) { + double aggregateVolumeTrack = audioManager.Volume.Value * audioManager.VolumeTrack.Value; + // Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - if (volumeOverlay?.IsMuted.Value == true || (float)(audioManager.Volume.Value * audioManager.VolumeTrack.Value) <= volume_requirement) + if (volumeOverlay?.IsMuted.Value == true || aggregateVolumeTrack <= volume_requirement) { notificationOverlay?.Post(new MutedNotification()); muteWarningShownOnce.Value = true; @@ -580,9 +582,11 @@ namespace osu.Game.Screens.Play volumeOverlay.IsMuted.Value = false; + double aggregateVolumeTrack = audioManager.Volume.Value * audioManager.VolumeTrack.Value; + // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. // Note that we only restore to -20 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. - if ((float)(audioManager.Volume.Value * audioManager.VolumeTrack.Value) <= volume_requirement) + if (aggregateVolumeTrack <= volume_requirement) { // Prioritize increasing music over master volume as to avoid also increasing effects volume. const double target = 0.1; From d81b148b099e56f1a9ff8d7a20d282e7b970d7a9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Feb 2024 01:23:18 +0300 Subject: [PATCH 147/223] Remove mention of decibel units in comment Decibels are irrelevant in the volume bindables, as mentioned in PR already. --- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index fff1118622..c755923ace 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -585,7 +585,7 @@ namespace osu.Game.Screens.Play double aggregateVolumeTrack = audioManager.Volume.Value * audioManager.VolumeTrack.Value; // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. - // Note that we only restore to -20 dB to ensure the user isn't suddenly overloaded by unexpectedly high volume. + // Note that we only restore to 10% to ensure the user isn't suddenly overloaded by unexpectedly high volume. if (aggregateVolumeTrack <= volume_requirement) { // Prioritize increasing music over master volume as to avoid also increasing effects volume. From 5431781f80692d8fc36a5a301126148b00ca916c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Feb 2024 01:23:26 +0300 Subject: [PATCH 148/223] Bring back target volume to 50% --- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index c755923ace..d3f75fe15e 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -589,7 +589,7 @@ namespace osu.Game.Screens.Play if (aggregateVolumeTrack <= volume_requirement) { // Prioritize increasing music over master volume as to avoid also increasing effects volume. - const double target = 0.1; + const double target = 0.5; double result = target / Math.Max(0.01, audioManager.Volume.Value); if (result > 1) From 6751f95eb648b42cdb55baa83efcb07a757ea9a7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Feb 2024 01:28:47 +0300 Subject: [PATCH 149/223] Adjust test cases and approximate equality --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 67e94a2960..02a0ae6e6c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -268,9 +268,9 @@ namespace osu.Game.Tests.Visual.Gameplay { addVolumeSteps("master and music volumes", () => { - audioManager.Volume.Value = 0.15; - audioManager.VolumeTrack.Value = 0.01; - }, () => audioManager.Volume.Value == 0.15 && audioManager.VolumeTrack.Value == 0.67); + audioManager.Volume.Value = 0.6; + audioManager.VolumeTrack.Value = 0.15; + }, () => Precision.AlmostEquals(audioManager.Volume.Value, 0.6) && Precision.AlmostEquals(audioManager.VolumeTrack.Value, 0.83)); } [Test] @@ -280,7 +280,7 @@ namespace osu.Game.Tests.Visual.Gameplay { audioManager.Volume.Value = 0.01; audioManager.VolumeTrack.Value = 0.15; - }, () => audioManager.Volume.Value == 0.1 && audioManager.VolumeTrack.Value == 1); + }, () => Precision.AlmostEquals(audioManager.Volume.Value, 0.5) && Precision.AlmostEquals(audioManager.VolumeTrack.Value, 1)); } [Test] From 7530b1f362451eb18e6fcfaceb5154f4bddddac6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Feb 2024 01:31:52 +0300 Subject: [PATCH 150/223] Adjust comment again --- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index d3f75fe15e..060074890c 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -585,7 +585,7 @@ namespace osu.Game.Screens.Play double aggregateVolumeTrack = audioManager.Volume.Value * audioManager.VolumeTrack.Value; // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. - // Note that we only restore to 10% to ensure the user isn't suddenly overloaded by unexpectedly high volume. + // Note that we only restore halfway to ensure the user isn't suddenly overloaded by unexpectedly high volume. if (aggregateVolumeTrack <= volume_requirement) { // Prioritize increasing music over master volume as to avoid also increasing effects volume. From ec85bf0ae66cf0127e5cfc7d0f231742dd87f8e9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Feb 2024 01:45:30 +0300 Subject: [PATCH 151/223] Update other VS code configuration files --- .../osu.Game.Rulesets.EmptyFreeform.Tests/.vscode/launch.json | 4 ++-- .../osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json | 4 ++-- .../.vscode/launch.json | 4 ++-- .../osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json | 4 ++-- osu.Game.Rulesets.Catch.Tests/.vscode/launch.json | 4 ++-- osu.Game.Rulesets.Mania.Tests/.vscode/launch.json | 4 ++-- osu.Game.Rulesets.Osu.Tests/.vscode/launch.json | 4 ++-- osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json | 4 ++-- osu.Game.Tournament.Tests/.vscode/launch.json | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/.vscode/launch.json b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/.vscode/launch.json index b433819346..0d72037393 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/.vscode/launch.json +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.EmptyFreeformRuleset.Tests.dll" + "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Rulesets.EmptyFreeformRuleset.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", @@ -20,7 +20,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.EmptyFreeformRuleset.Tests.dll" + "${workspaceRoot}/bin/Release/net8.0/osu.Game.Rulesets.EmptyFreeformRuleset.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json index d60bc2571d..ec832d9a72 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Pippidon.Tests.dll" + "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Rulesets.Pippidon.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", @@ -20,7 +20,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Pippidon.Tests.dll" + "${workspaceRoot}/bin/Release/net8.0/osu.Game.Rulesets.Pippidon.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/.vscode/launch.json b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/.vscode/launch.json index f1f37f6363..a60979073b 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/.vscode/launch.json +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.EmptyScrolling.Tests.dll" + "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Rulesets.EmptyScrolling.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", @@ -20,7 +20,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.EmptyScrolling.Tests.dll" + "${workspaceRoot}/bin/Release/net8.0/osu.Game.Rulesets.EmptyScrolling.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json index d60bc2571d..ec832d9a72 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Pippidon.Tests.dll" + "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Rulesets.Pippidon.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", @@ -20,7 +20,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Pippidon.Tests.dll" + "${workspaceRoot}/bin/Release/net8.0/osu.Game.Rulesets.Pippidon.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", diff --git a/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json b/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json index 201343a036..7b9291c870 100644 --- a/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json +++ b/osu.Game.Rulesets.Catch.Tests/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Catch.Tests.dll" + "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Rulesets.Catch.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", @@ -20,7 +20,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Catch.Tests.dll" + "${workspaceRoot}/bin/Release/net8.0/osu.Game.Rulesets.Catch.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", diff --git a/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json b/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json index f6a067a831..b8dafda8b5 100644 --- a/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json +++ b/osu.Game.Rulesets.Mania.Tests/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Mania.Tests.dll" + "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Rulesets.Mania.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", @@ -20,7 +20,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Mania.Tests.dll" + "${workspaceRoot}/bin/Release/net8.0/osu.Game.Rulesets.Mania.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", diff --git a/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json b/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json index 61be25b845..a68d6e12c0 100644 --- a/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json +++ b/osu.Game.Rulesets.Osu.Tests/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Osu.Tests.dll" + "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Rulesets.Osu.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", @@ -20,7 +20,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Osu.Tests.dll" + "${workspaceRoot}/bin/Release/net8.0/osu.Game.Rulesets.Osu.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", diff --git a/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json b/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json index 56ec7d8d9c..5b192c795b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json +++ b/osu.Game.Rulesets.Taiko.Tests/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Debug/net6.0/osu.Game.Rulesets.Taiko.Tests.dll" + "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Rulesets.Taiko.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", @@ -20,7 +20,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Release/net6.0/osu.Game.Rulesets.Taiko.Tests.dll" + "${workspaceRoot}/bin/Release/net8.0/osu.Game.Rulesets.Taiko.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", diff --git a/osu.Game.Tournament.Tests/.vscode/launch.json b/osu.Game.Tournament.Tests/.vscode/launch.json index 51aa541811..07a0db448d 100644 --- a/osu.Game.Tournament.Tests/.vscode/launch.json +++ b/osu.Game.Tournament.Tests/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Debug/net6.0/osu.Game.Tournament.Tests.dll" + "${workspaceRoot}/bin/Debug/net8.0/osu.Game.Tournament.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Debug)", @@ -20,7 +20,7 @@ "request": "launch", "program": "dotnet", "args": [ - "${workspaceRoot}/bin/Release/net6.0/osu.Game.Tournament.Tests.dll" + "${workspaceRoot}/bin/Release/net8.0/osu.Game.Tournament.Tests.dll" ], "cwd": "${workspaceRoot}", "preLaunchTask": "Build (Release)", From 22ffac1718f14f8509d46be93923a5837e80157e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Feb 2024 01:45:38 +0300 Subject: [PATCH 152/223] Update Rider configuration files --- .../.idea/runConfigurations/Benchmarks.xml | 6 +++--- .../.idea/runConfigurations/CatchRuleset__Tests_.xml | 6 +++--- .../.idea/runConfigurations/ManiaRuleset__Tests_.xml | 6 +++--- .../.idea/runConfigurations/OsuRuleset__Tests_.xml | 6 +++--- .../.idea/runConfigurations/TaikoRuleset__Tests_.xml | 6 +++--- .../.idea/runConfigurations/Tournament.xml | 6 +++--- .../.idea/runConfigurations/Tournament__Tests_.xml | 6 +++--- .idea/.idea.osu.Desktop/.idea/runConfigurations/osu_.xml | 6 +++--- .../.idea/runConfigurations/osu___Tests_.xml | 6 +++--- .run/osu! (Second Client).run.xml | 6 +++--- 10 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml index d500c595c0..a7a6649a4f 100644 --- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml +++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml @@ -1,8 +1,8 @@ -

e&FE%k)kw1nZ_Ituv@| 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

public interface IStatefulUserHubClient { + /// + /// Invoked when the server requests a client to disconnect. + /// + /// + /// When this request is received, the client must presume any and all further requests to the server + /// will either fail or be ignored. + /// This method is ONLY to be used for the purposes of: + /// + /// actually physically disconnecting from the server, + /// cleaning up / setting up any and all required local client state. + /// + /// Task DisconnectRequested(); } } From 060b01eee8d30d996858515829568feb827cc8b4 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Fri, 16 Feb 2024 20:24:02 +0300 Subject: [PATCH 166/223] Make CreateJudgement public again and add remarks --- .../Objects/EmptyFreeformHitObject.cs | 2 +- .../osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs | 2 +- .../Objects/EmptyScrollingHitObject.cs | 2 +- .../osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs | 2 +- osu.Game.Rulesets.Catch/Objects/Banana.cs | 2 +- osu.Game.Rulesets.Catch/Objects/BananaShower.cs | 2 +- osu.Game.Rulesets.Catch/Objects/Droplet.cs | 2 +- osu.Game.Rulesets.Catch/Objects/Fruit.cs | 2 +- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 2 +- osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs | 2 +- osu.Game.Rulesets.Mania/Objects/BarLine.cs | 2 +- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 2 +- osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs | 2 +- osu.Game.Rulesets.Mania/Objects/Note.cs | 2 +- osu.Game.Rulesets.Mania/Objects/TailNote.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs | 2 +- osu.Game.Rulesets.Osu/Objects/HitCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SliderTick.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Spinner.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs | 2 +- osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/BarLine.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 4 ++-- osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/StrongNestedHitObject.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/SwellTick.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs | 2 +- osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs | 2 +- osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs | 2 +- osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs | 2 +- osu.Game/Database/StandardisedScoreMigrationTools.cs | 2 +- osu.Game/Rulesets/Objects/HitObject.cs | 6 +++++- osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs | 2 +- 39 files changed, 44 insertions(+), 40 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/EmptyFreeformHitObject.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/EmptyFreeformHitObject.cs index e166d09f84..9cd18d2d9f 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/EmptyFreeformHitObject.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/EmptyFreeformHitObject.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.EmptyFreeform.Objects { public class EmptyFreeformHitObject : HitObject, IHasPosition { - protected override Judgement CreateJudgement() => new Judgement(); + public override Judgement CreateJudgement() => new Judgement(); public Vector2 Position { get; set; } diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs index 748e6d3b53..0c22554e82 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Pippidon.Objects { public class PippidonHitObject : HitObject, IHasPosition { - protected override Judgement CreateJudgement() => new Judgement(); + public override Judgement CreateJudgement() => new Judgement(); public Vector2 Position { get; set; } diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/EmptyScrollingHitObject.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/EmptyScrollingHitObject.cs index 4564bd1e09..9b469be496 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/EmptyScrollingHitObject.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/EmptyScrollingHitObject.cs @@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.EmptyScrolling.Objects { public class EmptyScrollingHitObject : HitObject { - protected override Judgement CreateJudgement() => new Judgement(); + public override Judgement CreateJudgement() => new Judgement(); } } diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs index ed16bce9f6..9dd135479f 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/PippidonHitObject.cs @@ -13,6 +13,6 @@ namespace osu.Game.Rulesets.Pippidon.Objects /// public int Lane; - protected override Judgement CreateJudgement() => new Judgement(); + public override Judgement CreateJudgement() => new Judgement(); } } diff --git a/osu.Game.Rulesets.Catch/Objects/Banana.cs b/osu.Game.Rulesets.Catch/Objects/Banana.cs index 30bdb24b14..b80527f379 100644 --- a/osu.Game.Rulesets.Catch/Objects/Banana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Banana.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Catch.Objects /// public int BananaIndex; - protected override Judgement CreateJudgement() => new CatchBananaJudgement(); + public override Judgement CreateJudgement() => new CatchBananaJudgement(); private static readonly IList default_banana_samples = new List { new BananaHitSampleInfo() }.AsReadOnly(); diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs index 86c41fce90..328cc2b52a 100644 --- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects { public override bool LastInCombo => true; - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { diff --git a/osu.Game.Rulesets.Catch/Objects/Droplet.cs b/osu.Game.Rulesets.Catch/Objects/Droplet.cs index 107c6c3979..9c1004a04b 100644 --- a/osu.Game.Rulesets.Catch/Objects/Droplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Droplet.cs @@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.Catch.Objects { public class Droplet : PalpableCatchHitObject { - protected override Judgement CreateJudgement() => new CatchDropletJudgement(); + public override Judgement CreateJudgement() => new CatchDropletJudgement(); } } diff --git a/osu.Game.Rulesets.Catch/Objects/Fruit.cs b/osu.Game.Rulesets.Catch/Objects/Fruit.cs index 17270b803c..4818fe2cad 100644 --- a/osu.Game.Rulesets.Catch/Objects/Fruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Fruit.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Catch.Objects { public class Fruit : PalpableCatchHitObject { - protected override Judgement CreateJudgement() => new CatchJudgement(); + public override Judgement CreateJudgement() => new CatchJudgement(); public static FruitVisualRepresentation GetVisualRepresentation(int indexInBeatmap) => (FruitVisualRepresentation)(indexInBeatmap % 4); } diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 49c24df5b9..671291ef0e 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Objects /// private const float base_scoring_distance = 100; - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); public int RepeatCount { get; set; } diff --git a/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs index ddcb92875f..1bf160b5a6 100644 --- a/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/TinyDroplet.cs @@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.Catch.Objects { public class TinyDroplet : Droplet { - protected override Judgement CreateJudgement() => new CatchTinyDropletJudgement(); + public override Judgement CreateJudgement() => new CatchTinyDropletJudgement(); } } diff --git a/osu.Game.Rulesets.Mania/Objects/BarLine.cs b/osu.Game.Rulesets.Mania/Objects/BarLine.cs index 742b5e4b0d..cf576239ed 100644 --- a/osu.Game.Rulesets.Mania/Objects/BarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/BarLine.cs @@ -19,6 +19,6 @@ namespace osu.Game.Rulesets.Mania.Objects set => major.Value = value; } - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); } } diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 4aac455bc5..3f930a310b 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Mania.Objects }); } - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs b/osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs index 92b649c174..47163d0d81 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNoteBody.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Objects /// public class HoldNoteBody : ManiaHitObject { - protected override Judgement CreateJudgement() => new HoldNoteBodyJudgement(); + public override Judgement CreateJudgement() => new HoldNoteBodyJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } } diff --git a/osu.Game.Rulesets.Mania/Objects/Note.cs b/osu.Game.Rulesets.Mania/Objects/Note.cs index b0f2991918..0035960c63 100644 --- a/osu.Game.Rulesets.Mania/Objects/Note.cs +++ b/osu.Game.Rulesets.Mania/Objects/Note.cs @@ -11,6 +11,6 @@ namespace osu.Game.Rulesets.Mania.Objects /// public class Note : ManiaHitObject { - protected override Judgement CreateJudgement() => new ManiaJudgement(); + public override Judgement CreateJudgement() => new ManiaJudgement(); } } diff --git a/osu.Game.Rulesets.Mania/Objects/TailNote.cs b/osu.Game.Rulesets.Mania/Objects/TailNote.cs index bddb4630cb..def32880f1 100644 --- a/osu.Game.Rulesets.Mania/Objects/TailNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/TailNote.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Objects /// public const double RELEASE_WINDOW_LENIENCE = 1.5; - protected override Judgement CreateJudgement() => new ManiaJudgement(); + public override Judgement CreateJudgement() => new ManiaJudgement(); public override double MaximumJudgementOffset => base.MaximumJudgementOffset * RELEASE_WINDOW_LENIENCE; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index f07a1e930b..2c9292c58b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Osu.Mods { } - protected override Judgement CreateJudgement() => new OsuJudgement(); + public override Judgement CreateJudgement() => new OsuJudgement(); } private partial class StrictTrackingDrawableSliderTail : DrawableSliderTail diff --git a/osu.Game.Rulesets.Osu/Objects/HitCircle.cs b/osu.Game.Rulesets.Osu/Objects/HitCircle.cs index 6336482ccc..d652db0fd4 100644 --- a/osu.Game.Rulesets.Osu/Objects/HitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/HitCircle.cs @@ -8,6 +8,6 @@ namespace osu.Game.Rulesets.Osu.Objects { public class HitCircle : OsuHitObject { - protected override Judgement CreateJudgement() => new OsuJudgement(); + public override Judgement CreateJudgement() => new OsuJudgement(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index fc0248cbbd..506145568e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -275,7 +275,7 @@ namespace osu.Game.Rulesets.Osu.Objects TailSamples = this.GetNodeSamples(repeatCount + 1); } - protected override Judgement CreateJudgement() => ClassicSliderBehaviour + public override Judgement CreateJudgement() => ClassicSliderBehaviour // Final combo is provided by the slider itself - see logic in `DrawableSlider.CheckForResult()` ? new OsuJudgement() // Final combo is provided by the tail circle - see `SliderTailCircle` diff --git a/osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs index 8d60864f0b..2d5a5b7727 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderEndCircle.cs @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Objects protected override HitWindows CreateHitWindows() => HitWindows.Empty; - protected override Judgement CreateJudgement() => new SliderEndJudgement(); + public override Judgement CreateJudgement() => new SliderEndJudgement(); public class SliderEndJudgement : OsuJudgement { diff --git a/osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs index 4760135081..8305481788 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderHeadCircle.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Osu.Objects /// public bool ClassicSliderBehaviour; - protected override Judgement CreateJudgement() => ClassicSliderBehaviour ? new SliderTickJudgement() : base.CreateJudgement(); + public override Judgement CreateJudgement() => ClassicSliderBehaviour ? new SliderTickJudgement() : base.CreateJudgement(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs index 42d8d895e4..ee2490439f 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Objects { } - protected override Judgement CreateJudgement() => ClassicSliderBehaviour ? new LegacyTailJudgement() : new TailJudgement(); + public override Judgement CreateJudgement() => ClassicSliderBehaviour ? new LegacyTailJudgement() : new TailJudgement(); public class LegacyTailJudgement : OsuJudgement { diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs index 1d7ba2fbaf..74ec4d6eb3 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs @@ -32,6 +32,6 @@ namespace osu.Game.Rulesets.Osu.Objects protected override HitWindows CreateHitWindows() => HitWindows.Empty; - protected override Judgement CreateJudgement() => new SliderTickJudgement(); + public override Judgement CreateJudgement() => new SliderTickJudgement(); } } diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs index 9baa645b3c..e3dfe8e69a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Osu.Objects } } - protected override Judgement CreateJudgement() => new OsuJudgement(); + public override Judgement CreateJudgement() => new OsuJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs b/osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs index 57db29ef0c..8d53100529 100644 --- a/osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SpinnerBonusTick.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Osu.Objects { public class SpinnerBonusTick : SpinnerTick { - protected override Judgement CreateJudgement() => new OsuSpinnerBonusTickJudgement(); + public override Judgement CreateJudgement() => new OsuSpinnerBonusTickJudgement(); public class OsuSpinnerBonusTickJudgement : OsuSpinnerTickJudgement { diff --git a/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs b/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs index cb59014909..7989c9b7ff 100644 --- a/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SpinnerTick.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Objects /// public double SpinnerDuration { get; set; } - protected override Judgement CreateJudgement() => new OsuSpinnerTickJudgement(); + public override Judgement CreateJudgement() => new OsuSpinnerTickJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs index d87f8b3232..46b3f13501 100644 --- a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs +++ b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs @@ -19,6 +19,6 @@ namespace osu.Game.Rulesets.Taiko.Objects set => major.Value = value; } - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 50cd722a3f..f3143de345 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } } - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Taiko.Objects public class StrongNestedHit : StrongNestedHitObject { // The strong hit of the drum roll doesn't actually provide any score. - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); public StrongNestedHit(TaikoHitObject parent) : base(parent) diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs index c1d4102042..dc082ffd21 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Objects Parent = parent; } - protected override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement(); + public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs b/osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs index 44cd700faf..302f940ef4 100644 --- a/osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/IgnoreHit.cs @@ -7,6 +7,6 @@ namespace osu.Game.Rulesets.Taiko.Objects { public class IgnoreHit : Hit { - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/StrongNestedHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/StrongNestedHitObject.cs index 227ab4ab52..14cbe338ed 100644 --- a/osu.Game.Rulesets.Taiko/Objects/StrongNestedHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/StrongNestedHitObject.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Objects Parent = parent; } - protected override Judgement CreateJudgement() => new TaikoStrongJudgement(); + public override Judgement CreateJudgement() => new TaikoStrongJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index 76d106f924..a8db8df021 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } } - protected override Judgement CreateJudgement() => new TaikoSwellJudgement(); + public override Judgement CreateJudgement() => new TaikoSwellJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs index be1c1101de..41fb9cac7e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs @@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Taiko.Objects { public class SwellTick : TaikoHitObject { - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs index 697c23addf..1a1fde1990 100644 --- a/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/TaikoHitObject.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public const float DEFAULT_SIZE = 0.475f; - protected override Judgement CreateJudgement() => new TaikoJudgement(); + public override Judgement CreateJudgement() => new TaikoJudgement(); protected override HitWindows CreateHitWindows() => new TaikoHitWindows(); } diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs index f0f93f59b5..584a9e09c0 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs @@ -358,7 +358,7 @@ namespace osu.Game.Tests.Gameplay this.maxResult = maxResult; } - protected override Judgement CreateJudgement() => new TestJudgement(maxResult); + public override Judgement CreateJudgement() => new TestJudgement(maxResult); protected override HitWindows CreateHitWindows() => new HitWindows(); private class TestJudgement : Judgement diff --git a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs index a428979015..8ec18377f4 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs @@ -196,7 +196,7 @@ namespace osu.Game.Tests.Gameplay this.maxResult = maxResult; } - protected override Judgement CreateJudgement() => new TestJudgement(maxResult); + public override Judgement CreateJudgement() => new TestJudgement(maxResult); } } } diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index ea43a65825..1647fbee42 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -441,7 +441,7 @@ namespace osu.Game.Tests.Rulesets.Scoring private readonly HitResult maxResult; private readonly HitResult? minResult; - protected override Judgement CreateJudgement() => new TestJudgement(maxResult, minResult); + public override Judgement CreateJudgement() => new TestJudgement(maxResult, minResult); public TestHitObject(HitResult maxResult, HitResult? minResult = null) { diff --git a/osu.Game/Database/StandardisedScoreMigrationTools.cs b/osu.Game/Database/StandardisedScoreMigrationTools.cs index 576d08f491..403e73ab77 100644 --- a/osu.Game/Database/StandardisedScoreMigrationTools.cs +++ b/osu.Game/Database/StandardisedScoreMigrationTools.cs @@ -655,7 +655,7 @@ namespace osu.Game.Database { private readonly Judgement judgement; - protected override Judgement CreateJudgement() => judgement; + public override Judgement CreateJudgement() => judgement; public FakeHit(Judgement judgement) { diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index aed821332d..317dd35fef 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -173,8 +173,12 @@ namespace osu.Game.Rulesets.Objects /// /// Creates the that represents the scoring information for this . /// + /// + /// Use to avoid unnecessary allocations. + /// This method has been left public for compatibility reasons and eventually will be made protected. + /// [NotNull] - protected virtual Judgement CreateJudgement() => new Judgement(); + public virtual Judgement CreateJudgement() => new Judgement(); /// /// Creates the for this . diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs index 499953dab9..bb36aab0b3 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Objects.Legacy public int ComboOffset { get; set; } - protected override Judgement CreateJudgement() => new IgnoreJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } From b0f334c39e4ac1c3b587fa31b7c7759cfa5ec281 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 17 Feb 2024 00:45:30 +0300 Subject: [PATCH 167/223] Fix DrawableLinkCompiler allocations --- osu.Game/Online/Chat/DrawableLinkCompiler.cs | 32 ++++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/DrawableLinkCompiler.cs b/osu.Game/Online/Chat/DrawableLinkCompiler.cs index 883a2496f7..fa107a0e43 100644 --- a/osu.Game/Online/Chat/DrawableLinkCompiler.cs +++ b/osu.Game/Online/Chat/DrawableLinkCompiler.cs @@ -4,9 +4,11 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Extensions.ListExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Lists; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -23,12 +25,21 @@ namespace osu.Game.Online.Chat /// /// Each word part of a chat link (split for word-wrap support). /// - public readonly List Parts; + public readonly SlimReadOnlyListWrapper Parts; [Resolved] private OverlayColourProvider? overlayColourProvider { get; set; } - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parts.Any(d => d.ReceivePositionalInputAt(screenSpacePos)); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) + { + foreach (var part in Parts) + { + if (part.ReceivePositionalInputAt(screenSpacePos)) + return true; + } + + return false; + } protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new LinkHoverSounds(sampleSet, Parts); @@ -39,7 +50,7 @@ namespace osu.Game.Online.Chat public DrawableLinkCompiler(IEnumerable parts) { - Parts = parts.ToList(); + Parts = parts.ToList().AsSlimReadOnly(); } [BackgroundDependencyLoader] @@ -52,15 +63,24 @@ namespace osu.Game.Online.Chat private partial class LinkHoverSounds : HoverClickSounds { - private readonly List parts; + private readonly SlimReadOnlyListWrapper parts; - public LinkHoverSounds(HoverSampleSet sampleSet, List parts) + public LinkHoverSounds(HoverSampleSet sampleSet, SlimReadOnlyListWrapper parts) : base(sampleSet) { this.parts = parts; } - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => parts.Any(d => d.ReceivePositionalInputAt(screenSpacePos)); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) + { + foreach (var part in parts) + { + if (part.ReceivePositionalInputAt(screenSpacePos)) + return true; + } + + return false; + } } } } From ce903987e7e71b22ac138b5985fc6ed37b3c5507 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 17 Feb 2024 00:53:53 +0300 Subject: [PATCH 168/223] Fix cursor ripples being added on release positions in replays --- osu.Game.Rulesets.Osu/UI/Cursor/CursorRippleVisualiser.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorRippleVisualiser.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorRippleVisualiser.cs index 4cb91aa103..d898f1a1a8 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorRippleVisualiser.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorRippleVisualiser.cs @@ -11,6 +11,7 @@ using osu.Framework.Input.Events; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Default; +using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK; @@ -39,6 +40,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor public bool OnPressed(KeyBindingPressEvent e) { + if ((Clock as IGameplayClock)?.IsRewinding == true) + return false; + if (showRipples.Value) { AddInternal(ripplePool.Get(r => From 8169d1ac80de9b5cf123c0c5540f4a760fce8f3e Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 21 Jan 2024 18:32:07 -0800 Subject: [PATCH 169/223] Add twenty star counter in visual test --- .../Visual/Gameplay/TestSceneStarCounter.cs | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs index b002e90bb0..fa17b77b55 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -14,39 +15,47 @@ namespace osu.Game.Tests.Visual.Gameplay public partial class TestSceneStarCounter : OsuTestScene { private readonly StarCounter starCounter; + private readonly StarCounter twentyStarCounter; private readonly OsuSpriteText starsLabel; public TestSceneStarCounter() { - starCounter = new StarCounter + Add(new FillFlowContainer { - Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, - }; - - Add(starCounter); - - starsLabel = new OsuSpriteText - { Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Scale = new Vector2(2), - Y = 50, - }; - - Add(starsLabel); + Direction = FillDirection.Vertical, + Spacing = new Vector2(20), + Children = new Drawable[] + { + starCounter = new StarCounter(), + twentyStarCounter = new StarCounter(20), + starsLabel = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Scale = new Vector2(2), + }, + } + }); setStars(5); - AddRepeatStep("random value", () => setStars(RNG.NextSingle() * (starCounter.StarCount + 1)), 10); - AddSliderStep("exact value", 0f, 10f, 5f, setStars); - AddStep("stop animation", () => starCounter.StopAnimation()); + AddRepeatStep("random value", () => setStars(RNG.NextSingle() * (twentyStarCounter.StarCount + 1)), 10); + AddSliderStep("exact value", 0f, 20f, 5f, setStars); + AddStep("stop animation", () => + { + starCounter.StopAnimation(); + twentyStarCounter.StopAnimation(); + }); AddStep("reset", () => setStars(0)); } private void setStars(float stars) { starCounter.Current = stars; + twentyStarCounter.Current = stars; starsLabel.Text = starCounter.Current.ToString("0.00"); } } From 6e8d8b977e000481ca0e769f514371a8bb188bdf Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 21 Jan 2024 18:34:55 -0800 Subject: [PATCH 170/223] Move ternary inside `Math.Max()` --- osu.Game/Graphics/UserInterface/StarCounter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs index 720f479216..5fdc6a4904 100644 --- a/osu.Game/Graphics/UserInterface/StarCounter.cs +++ b/osu.Game/Graphics/UserInterface/StarCounter.cs @@ -115,7 +115,7 @@ namespace osu.Game.Graphics.UserInterface star.ClearTransforms(true); - double delay = (current <= newValue ? Math.Max(i - current, 0) : Math.Max(current - 1 - i, 0)) * AnimationDelay; + double delay = Math.Max(current <= newValue ? i - current : current - 1 - i, 0) * AnimationDelay; using (star.BeginDelayedSequence(delay)) star.DisplayAt(getStarScale(i, newValue)); From 7a74eaa2dec61e1342e9b3c8ca3f3eed1a0ce30f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 21 Jan 2024 18:47:24 -0800 Subject: [PATCH 171/223] Fix star counter decrease animation being delayed when current is over displayed star count --- osu.Game/Graphics/UserInterface/StarCounter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs index 5fdc6a4904..4e9e34d840 100644 --- a/osu.Game/Graphics/UserInterface/StarCounter.cs +++ b/osu.Game/Graphics/UserInterface/StarCounter.cs @@ -115,7 +115,7 @@ namespace osu.Game.Graphics.UserInterface star.ClearTransforms(true); - double delay = Math.Max(current <= newValue ? i - current : current - 1 - i, 0) * AnimationDelay; + double delay = Math.Max(current <= newValue ? i - current : Math.Min(current, StarCount) - 1 - i, 0) * AnimationDelay; using (star.BeginDelayedSequence(delay)) star.DisplayAt(getStarScale(i, newValue)); From 22f5a66c029bed6b135cbb3c99b63363e4248ecd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 17 Feb 2024 15:46:38 +0300 Subject: [PATCH 172/223] Reduce allocations during beatmap selection --- .../Preprocessing/OsuDifficultyHitObject.cs | 8 ++++- osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 8 +++-- osu.Game.Rulesets.Osu/Objects/Slider.cs | 36 +++++++++++++++---- osu.Game/Rulesets/Objects/SliderPath.cs | 15 ++++---- osu.Game/Screens/Select/BeatmapCarousel.cs | 19 ++++++++-- 5 files changed, 67 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 488d1e2e9f..0e537632b1 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -232,7 +232,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing IList nestedObjects = slider.NestedHitObjects; - SliderTick? lastRealTick = slider.NestedHitObjects.OfType().LastOrDefault(); + SliderTick? lastRealTick = null; + + foreach (var hitobject in slider.NestedHitObjects) + { + if (hitobject is SliderTick tick) + lastRealTick = tick; + } if (lastRealTick?.StartTime > trackingEndTime) { diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 74631400ca..6c77d9189c 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -149,8 +148,11 @@ namespace osu.Game.Rulesets.Osu.Objects { StackHeightBindable.BindValueChanged(height => { - foreach (var nested in NestedHitObjects.OfType()) - nested.StackHeight = height.NewValue; + foreach (var nested in NestedHitObjects) + { + if (nested is OsuHitObject osuHitObject) + osuHitObject.StackHeight = height.NewValue; + } }); } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 506145568e..8a87e17089 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -252,18 +252,42 @@ namespace osu.Game.Rulesets.Osu.Objects protected void UpdateNestedSamples() { - var firstSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) - ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) + HitSampleInfo firstSample = null; + + for (int i = 0; i < Samples.Count; i++) + { + // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) + if (i == 0) + { + firstSample = Samples[i]; + continue; + } + + if (Samples[i].Name != HitSampleInfo.HIT_NORMAL) + continue; + + firstSample = Samples[i]; + break; + } + var sampleList = new List(); if (firstSample != null) sampleList.Add(firstSample.With("slidertick")); - foreach (var tick in NestedHitObjects.OfType()) - tick.Samples = sampleList; + foreach (var nested in NestedHitObjects) + { + switch (nested) + { + case SliderTick tick: + tick.Samples = sampleList; + break; - foreach (var repeat in NestedHitObjects.OfType()) - repeat.Samples = this.GetNodeSamples(repeat.RepeatIndex + 1); + case SliderRepeat repeat: + repeat.Samples = this.GetNodeSamples(repeat.RepeatIndex + 1); + break; + } + } if (HeadCircle != null) HeadCircle.Samples = this.GetNodeSamples(0); diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index dc71608132..f33a07f082 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -61,16 +61,17 @@ namespace osu.Game.Rulesets.Objects case NotifyCollectionChangedAction.Add: Debug.Assert(args.NewItems != null); - foreach (var c in args.NewItems.Cast()) - c.Changed += invalidate; + foreach (object? newItem in args.NewItems) + ((PathControlPoint)newItem).Changed += invalidate; + break; case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Remove: Debug.Assert(args.OldItems != null); - foreach (var c in args.OldItems.Cast()) - c.Changed -= invalidate; + foreach (object? oldItem in args.OldItems) + ((PathControlPoint)oldItem).Changed -= invalidate; break; } @@ -269,10 +270,10 @@ namespace osu.Game.Rulesets.Objects { List subPath = calculateSubPath(segmentVertices, segmentType); // Skip the first vertex if it is the same as the last vertex from the previous segment - int skipFirst = calculatedPath.Count > 0 && subPath.Count > 0 && calculatedPath.Last() == subPath[0] ? 1 : 0; + bool skipFirst = calculatedPath.Count > 0 && subPath.Count > 0 && calculatedPath.Last() == subPath[0]; - foreach (Vector2 t in subPath.Skip(skipFirst)) - calculatedPath.Add(t); + for (int j = skipFirst ? 1 : 0; j < subPath.Count; j++) + calculatedPath.Add(subPath[j]); } if (i > 0) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 70ecde3858..ae0f397d52 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -510,12 +510,27 @@ namespace osu.Game.Screens.Select if (beatmapInfo?.Hidden != false) return false; - foreach (CarouselBeatmapSet set in beatmapSets) + foreach (var carouselItem in root.Items) { + if (carouselItem is not CarouselBeatmapSet set) + continue; + if (!bypassFilters && set.Filtered.Value) continue; - var item = set.Beatmaps.FirstOrDefault(p => p.BeatmapInfo.Equals(beatmapInfo)); + CarouselBeatmap? item = null; + + foreach (var setCarouselItem in set.Items) + { + if (setCarouselItem is not CarouselBeatmap setCarouselBeatmap) + continue; + + if (!setCarouselBeatmap.BeatmapInfo.Equals(beatmapInfo)) + continue; + + item = setCarouselBeatmap; + break; + } if (item == null) // The beatmap that needs to be selected doesn't exist in this set From 62a7e315bf669fea52ea2bb153995f08f16e9661 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Feb 2024 03:11:29 +0800 Subject: [PATCH 173/223] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index f61ff79b9f..85171cc0fa 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index 506bebfd47..f23debd38f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -23,6 +23,6 @@ iossimulator-x64 - + From 0714a4fc1e23a4a3e7672ff7a075fe86d6878194 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Feb 2024 03:18:50 +0800 Subject: [PATCH 174/223] Revert sample lookup logic that was not allocating anything --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 8a87e17089..900f42d96b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -252,23 +252,8 @@ namespace osu.Game.Rulesets.Osu.Objects protected void UpdateNestedSamples() { - HitSampleInfo firstSample = null; - - for (int i = 0; i < Samples.Count; i++) - { - // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) - if (i == 0) - { - firstSample = Samples[i]; - continue; - } - - if (Samples[i].Name != HitSampleInfo.HIT_NORMAL) - continue; - - firstSample = Samples[i]; - break; - } + var firstSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) + ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) var sampleList = new List(); From 0df6e8f5950aaeac17ff1fefee6fb80b3f73d4f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Feb 2024 03:22:10 +0800 Subject: [PATCH 175/223] Remove list allocations in `UpdateNestedSamples` --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 900f42d96b..79bf91bcae 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -252,20 +252,16 @@ namespace osu.Game.Rulesets.Osu.Objects protected void UpdateNestedSamples() { - var firstSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) - ?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) - - var sampleList = new List(); - - if (firstSample != null) - sampleList.Add(firstSample.With("slidertick")); + // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) + HitSampleInfo tickSample = (Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) ?? Samples.First()).With("slidertick"); foreach (var nested in NestedHitObjects) { switch (nested) { case SliderTick tick: - tick.Samples = sampleList; + tick.SamplesBindable.Clear(); + tick.SamplesBindable.Add(tickSample); break; case SliderRepeat repeat: From dd82de473a1b42ad77d871ad7faeea6b5f1c718c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 17 Feb 2024 22:42:47 +0300 Subject: [PATCH 176/223] Revert BeatmapCarousel changes --- osu.Game/Screens/Select/BeatmapCarousel.cs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index ae0f397d52..70ecde3858 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -510,27 +510,12 @@ namespace osu.Game.Screens.Select if (beatmapInfo?.Hidden != false) return false; - foreach (var carouselItem in root.Items) + foreach (CarouselBeatmapSet set in beatmapSets) { - if (carouselItem is not CarouselBeatmapSet set) - continue; - if (!bypassFilters && set.Filtered.Value) continue; - CarouselBeatmap? item = null; - - foreach (var setCarouselItem in set.Items) - { - if (setCarouselItem is not CarouselBeatmap setCarouselBeatmap) - continue; - - if (!setCarouselBeatmap.BeatmapInfo.Equals(beatmapInfo)) - continue; - - item = setCarouselBeatmap; - break; - } + var item = set.Beatmaps.FirstOrDefault(p => p.BeatmapInfo.Equals(beatmapInfo)); if (item == null) // The beatmap that needs to be selected doesn't exist in this set From 572f693eec361a69d83dedc317fa9608bd816099 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 17 Feb 2024 23:28:35 +0300 Subject: [PATCH 177/223] Fix failing tests related to slider ticks --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 79bf91bcae..203e829180 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -253,7 +253,7 @@ namespace osu.Game.Rulesets.Osu.Objects protected void UpdateNestedSamples() { // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933) - HitSampleInfo tickSample = (Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) ?? Samples.First()).With("slidertick"); + HitSampleInfo tickSample = (Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL) ?? Samples.FirstOrDefault())?.With("slidertick"); foreach (var nested in NestedHitObjects) { @@ -261,7 +261,9 @@ namespace osu.Game.Rulesets.Osu.Objects { case SliderTick tick: tick.SamplesBindable.Clear(); - tick.SamplesBindable.Add(tickSample); + + if (tickSample != null) + tick.SamplesBindable.Add(tickSample); break; case SliderRepeat repeat: From 414e55c90e33d492988914f992f0684284209145 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 18 Feb 2024 01:38:50 +0300 Subject: [PATCH 178/223] Add visual test case --- .../Visual/Online/TestSceneDrawableComment.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index 6f09e4c1f6..5cdf79160c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -81,16 +81,17 @@ namespace osu.Game.Tests.Visual.Online }, // Taken from https://github.com/ppy/osu/issues/13993#issuecomment-885994077 + new[] { "Problematic", @"My tablet doesn't work :( It's a Huion 420 and it's apparently incompatible with OpenTablet Driver. The warning I get is: ""DeviceInUseException: Device is currently in use by another kernel module. To fix this issue, please follow the instructions from https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ#arg umentoutofrangeexception-value-0-15"" and it repeats 4 times on the notification before logging subsequent warnings. Checking the logs, it looks for other Huion tablets before sending the notification (e.g. ""2021-07-23 03:52:33 [verbose]: Detect: Searching for tablet 'Huion WH1409 V2' 20 2021-07-23 03:52:33 [error]: DeviceInUseException: Device is currently in use by another kernel module. To fix this issue, please follow the instructions from https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ#arg umentoutofrangeexception-value-0-15"") I use an Arch based installation of Linux and the tablet runs perfectly with Digimend kernel driver, with area configuration, pen pressure, etc. On osu!lazer the cursor disappears until I set it to ""Borderless"" instead of ""Fullscreen"" and even after it shows up, it goes to the bottom left corner as soon as a map starts. I have honestly 0 idea of whats going on at this point.", }, new[] { - "Problematic", @"My tablet doesn't work :( -It's a Huion 420 and it's apparently incompatible with OpenTablet Driver. The warning I get is: ""DeviceInUseException: Device is currently in use by another kernel module. To fix this issue, please follow the instructions from https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ#arg umentoutofrangeexception-value-0-15"" and it repeats 4 times on the notification before logging subsequent warnings. -Checking the logs, it looks for other Huion tablets before sending the notification (e.g. - ""2021-07-23 03:52:33 [verbose]: Detect: Searching for tablet 'Huion WH1409 V2' - 20 2021-07-23 03:52:33 [error]: DeviceInUseException: Device is currently in use by another kernel module. To fix this issue, please follow the instructions from https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ#arg umentoutofrangeexception-value-0-15"") -I use an Arch based installation of Linux and the tablet runs perfectly with Digimend kernel driver, with area configuration, pen pressure, etc. On osu!lazer the cursor disappears until I set it to ""Borderless"" instead of ""Fullscreen"" and even after it shows up, it goes to the bottom left corner as soon as a map starts. -I have honestly 0 idea of whats going on at this point." - } + "Code Block", @"User not found! ;_; + +There are a few possible reasons for this: + + They may have changed their username. + The account may be temporarily unavailable due to security or abuse issues. + You may have made a typo!" + }, }; } } From 91675e097033c249cf7b6947e1023ee2c719ef5f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 18 Feb 2024 02:00:55 +0300 Subject: [PATCH 179/223] Update markdown code block implementation in line with framework changes --- ...suMarkdownFencedCodeBlock.cs => OsuMarkdownCodeBlock.cs} | 6 +++--- .../Graphics/Containers/Markdown/OsuMarkdownContainer.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename osu.Game/Graphics/Containers/Markdown/{OsuMarkdownFencedCodeBlock.cs => OsuMarkdownCodeBlock.cs} (87%) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownFencedCodeBlock.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownCodeBlock.cs similarity index 87% rename from osu.Game/Graphics/Containers/Markdown/OsuMarkdownFencedCodeBlock.cs rename to osu.Game/Graphics/Containers/Markdown/OsuMarkdownCodeBlock.cs index 7d84d368ad..27802f4c0e 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownFencedCodeBlock.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownCodeBlock.cs @@ -10,11 +10,11 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.Containers.Markdown { - public partial class OsuMarkdownFencedCodeBlock : MarkdownFencedCodeBlock + public partial class OsuMarkdownCodeBlock : MarkdownCodeBlock { // TODO : change to monospace font for this component - public OsuMarkdownFencedCodeBlock(FencedCodeBlock fencedCodeBlock) - : base(fencedCodeBlock) + public OsuMarkdownCodeBlock(CodeBlock codeBlock) + : base(codeBlock) { } diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index b4031752db..d465e53432 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -67,7 +67,7 @@ namespace osu.Game.Graphics.Containers.Markdown protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new OsuMarkdownHeading(headingBlock); - protected override MarkdownFencedCodeBlock CreateFencedCodeBlock(FencedCodeBlock fencedCodeBlock) => new OsuMarkdownFencedCodeBlock(fencedCodeBlock); + protected override MarkdownCodeBlock CreateCodeBlock(CodeBlock codeBlock) => new OsuMarkdownCodeBlock(codeBlock); protected override MarkdownSeparator CreateSeparator(ThematicBreakBlock thematicBlock) => new OsuMarkdownSeparator(); From 9655e8c48af03283ee323ee0d35fd6f354454119 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Feb 2024 17:54:29 +0800 Subject: [PATCH 180/223] Adjust xmldoc slightly --- osu.Game/Rulesets/Objects/HitObject.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 317dd35fef..04bdc35941 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -171,11 +171,10 @@ namespace osu.Game.Rulesets.Objects private Judgement judgement; /// - /// Creates the that represents the scoring information for this . + /// Should be overridden to create a that represents the scoring information for this . /// /// - /// Use to avoid unnecessary allocations. - /// This method has been left public for compatibility reasons and eventually will be made protected. + /// For read access, use to avoid unnecessary allocations. /// [NotNull] public virtual Judgement CreateJudgement() => new Judgement(); From 415a65bf59cdce4b8fab7d836fe3cdc4f7a2a168 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 17 Feb 2024 19:00:30 +0800 Subject: [PATCH 181/223] Add failing tests for beatmap inconsistencies --- .../Navigation/TestSceneScreenNavigation.cs | 63 +++++++++++++++++++ osu.Game/Tests/Visual/OsuGameTestScene.cs | 4 +- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 8ff4fd5ecf..7e42d4781d 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.IO; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -18,6 +19,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Collections; using osu.Game.Configuration; +using osu.Game.Extensions; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; @@ -221,6 +223,67 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible); } + [Test] + public void TestAttemptPlayBeatmapWrongHashFails() + { + Screens.Select.SongSelect songSelect = null; + + AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely()); + PushAndConfirm(() => songSelect = new TestPlaySongSelect()); + AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded); + + AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault); + + AddStep("change beatmap files", () => + { + foreach (var file in Game.Beatmap.Value.BeatmapSetInfo.Files.Where(f => Path.GetExtension(f.Filename) == ".osu")) + { + using (var stream = Game.Storage.GetStream(Path.Combine("files", file.File.GetStoragePath()), FileAccess.ReadWrite)) + stream.WriteByte(0); + } + }); + + AddStep("invalidate cache", () => + { + ((IWorkingBeatmapCache)Game.BeatmapManager).Invalidate(Game.Beatmap.Value.BeatmapSetInfo); + }); + + AddStep("select next difficulty", () => InputManager.Key(Key.Down)); + AddStep("press enter", () => InputManager.Key(Key.Enter)); + + AddUntilStep("wait for player loader", () => Game.ScreenStack.CurrentScreen is PlayerLoader); + AddUntilStep("wait for song select", () => songSelect.IsCurrentScreen()); + } + + [Test] + public void TestAttemptPlayBeatmapMissingFails() + { + Screens.Select.SongSelect songSelect = null; + + AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely()); + PushAndConfirm(() => songSelect = new TestPlaySongSelect()); + AddUntilStep("wait for song select", () => songSelect.BeatmapSetsLoaded); + + AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault); + + AddStep("delete beatmap files", () => + { + foreach (var file in Game.Beatmap.Value.BeatmapSetInfo.Files.Where(f => Path.GetExtension(f.Filename) == ".osu")) + Game.Storage.Delete(Path.Combine("files", file.File.GetStoragePath())); + }); + + AddStep("invalidate cache", () => + { + ((IWorkingBeatmapCache)Game.BeatmapManager).Invalidate(Game.Beatmap.Value.BeatmapSetInfo); + }); + + AddStep("select next difficulty", () => InputManager.Key(Key.Down)); + AddStep("press enter", () => InputManager.Key(Key.Enter)); + + AddUntilStep("wait for player loader", () => Game.ScreenStack.CurrentScreen is PlayerLoader); + AddUntilStep("wait for song select", () => songSelect.IsCurrentScreen()); + } + [Test] public void TestRetryCountIncrements() { diff --git a/osu.Game/Tests/Visual/OsuGameTestScene.cs b/osu.Game/Tests/Visual/OsuGameTestScene.cs index 6069fe4fb0..b86273b4a3 100644 --- a/osu.Game/Tests/Visual/OsuGameTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGameTestScene.cs @@ -153,6 +153,8 @@ namespace osu.Game.Tests.Visual public new Bindable> SelectedMods => base.SelectedMods; + public new Storage Storage => base.Storage; + public new SpectatorClient SpectatorClient => base.SpectatorClient; // if we don't apply these changes, when running under nUnit the version that gets populated is that of nUnit. @@ -166,7 +168,7 @@ namespace osu.Game.Tests.Visual public TestOsuGame(Storage storage, IAPIProvider api, string[] args = null) : base(args) { - Storage = storage; + base.Storage = storage; API = api; } From 882f11bf79d0ce405fb865cd0a7a1d552f540513 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Feb 2024 23:19:57 +0800 Subject: [PATCH 182/223] Fix logo tracking container being off by one frame This was especially visible at the main menu when running in single thread mode. --- osu.Game/Graphics/Containers/LogoTrackingContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index 08eae25951..57f87b588a 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -82,9 +82,9 @@ namespace osu.Game.Graphics.Containers absolutePos.Y / Logo.Parent!.RelativeToAbsoluteFactor.Y); } - protected override void Update() + protected override void UpdateAfterChildren() { - base.Update(); + base.UpdateAfterChildren(); if (Logo == null) return; From 6b6a6aea54fadf4dd5b811629fd075fe1b7f5c34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Feb 2024 23:35:26 +0800 Subject: [PATCH 183/223] Apply NRT to `LogoTrackingContainer` --- .../Visual/UserInterface/TestSceneLogoTrackingContainer.cs | 2 +- osu.Game/Graphics/Containers/LogoTrackingContainer.cs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs index 57ea4ee58e..8d5c961265 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs @@ -282,7 +282,7 @@ namespace osu.Game.Tests.Visual.UserInterface /// /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. /// - public bool IsLogoTracking => Precision.AlmostEquals(Logo.Position, ComputeLogoTrackingPosition()); + public bool IsLogoTracking => Precision.AlmostEquals(Logo!.Position, ComputeLogoTrackingPosition()); } } } diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index 57f87b588a..13c672cbd6 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -19,7 +17,7 @@ namespace osu.Game.Graphics.Containers { public Facade LogoFacade => facade; - protected OsuLogo Logo { get; private set; } + protected OsuLogo? Logo { get; private set; } private readonly InternalFacade facade = new InternalFacade(); @@ -76,7 +74,7 @@ namespace osu.Game.Graphics.Containers /// Will only be correct if the logo's are set to Axes.Both protected Vector2 ComputeLogoTrackingPosition() { - var absolutePos = Logo.Parent!.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre); + var absolutePos = Logo!.Parent!.ToLocalSpace(LogoFacade.ScreenSpaceDrawQuad.Centre); return new Vector2(absolutePos.X / Logo.Parent!.RelativeToAbsoluteFactor.X, absolutePos.Y / Logo.Parent!.RelativeToAbsoluteFactor.Y); From 998d8206668ba1733d7f7d6ff1afacde219f8a3a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Feb 2024 00:21:54 +0800 Subject: [PATCH 184/223] Ensure audio filters can't be attached before load (or post-disposal) Will probably fix https://github.com/ppy/osu/issues/27225? --- osu.Game/Audio/Effects/AudioFilter.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game/Audio/Effects/AudioFilter.cs b/osu.Game/Audio/Effects/AudioFilter.cs index 682ca4ca7b..c8673372d7 100644 --- a/osu.Game/Audio/Effects/AudioFilter.cs +++ b/osu.Game/Audio/Effects/AudioFilter.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using ManagedBass.Fx; using osu.Framework.Audio.Mixing; +using osu.Framework.Caching; using osu.Framework.Graphics; namespace osu.Game.Audio.Effects @@ -22,6 +23,8 @@ namespace osu.Game.Audio.Effects private bool isAttached; + private readonly Cached filterApplication = new Cached(); + private int cutoff; /// @@ -36,7 +39,7 @@ namespace osu.Game.Audio.Effects return; cutoff = value; - updateFilter(cutoff); + filterApplication.Invalidate(); } } @@ -61,6 +64,17 @@ namespace osu.Game.Audio.Effects Cutoff = getInitialCutoff(type); } + protected override void Update() + { + base.Update(); + + if (!filterApplication.IsValid) + { + updateFilter(cutoff); + filterApplication.Validate(); + } + } + private int getInitialCutoff(BQFType type) { switch (type) From 3059ddf3b2638a0c6c3c1520fd1e93b32c1dc24d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Feb 2024 01:08:40 +0300 Subject: [PATCH 185/223] Fix allocations in SliderInputManager --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index e472de1dfe..ceac1989a6 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -1,13 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; using System.ComponentModel; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Lists; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu { public partial class OsuInputManager : RulesetInputManager { - public IEnumerable PressedActions => KeyBindingContainer.PressedActions; + public SlimReadOnlyListWrapper PressedActions => KeyBindingContainer.PressedActions; /// /// Whether gameplay input buttons should be allowed. From 5a448ce02f5c65a40a57b4a3f51641d907a92de9 Mon Sep 17 00:00:00 2001 From: maromalo Date: Sun, 18 Feb 2024 19:59:56 -0300 Subject: [PATCH 186/223] Turn BPMDisplay to RollingCounter --- osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs b/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs index b9e4896b21..1db02b7cf2 100644 --- a/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs +++ b/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -168,7 +169,7 @@ namespace osu.Game.Overlays.Mods foreach (var mod in mods.Value.OfType()) rate = mod.ApplyToRate(0, rate); - bpmDisplay.Current.Value = BeatmapInfo.Value.BPM * rate; + bpmDisplay.Current.Value = (int)Math.Round(Math.Round(BeatmapInfo.Value.BPM) * rate); BeatmapDifficulty originalDifficulty = new BeatmapDifficulty(BeatmapInfo.Value.Difficulty); @@ -194,11 +195,11 @@ namespace osu.Game.Overlays.Mods RightContent.FadeTo(Collapsed.Value && !IsHovered ? 0 : 1, transition_duration, Easing.OutQuint); } - private partial class BPMDisplay : RollingCounter + private partial class BPMDisplay : RollingCounter { protected override double RollingDuration => 250; - protected override LocalisableString FormatCount(double count) => count.ToLocalisableString("0 BPM"); + protected override LocalisableString FormatCount(int count) => count.ToLocalisableString("0 BPM"); protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText { From 444ac5ed4d312fc0914b79888c8a2d00f414a728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Feb 2024 09:34:52 +0100 Subject: [PATCH 187/223] Add failing test coverage --- .../TestSceneSkinEditorNavigation.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 57f1b2fbe9..9c180d43da 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Framework.Threading; @@ -301,6 +302,25 @@ namespace osu.Game.Tests.Visual.Navigation switchToGameplayScene(); } + [Test] + public void TestRulesetInputDisabledWhenSkinEditorOpen() + { + advanceToSongSelect(); + openSkinEditor(); + + AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely()); + AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault); + + switchToGameplayScene(); + AddUntilStep("nested input disabled", () => ((Player)Game.ScreenStack.CurrentScreen).ChildrenOfType().All(manager => !manager.UseParentInput)); + + toggleSkinEditor(); + AddUntilStep("nested input enabled", () => ((Player)Game.ScreenStack.CurrentScreen).ChildrenOfType().Any(manager => manager.UseParentInput)); + + toggleSkinEditor(); + AddUntilStep("nested input disabled", () => ((Player)Game.ScreenStack.CurrentScreen).ChildrenOfType().All(manager => !manager.UseParentInput)); + } + private void advanceToSongSelect() { PushAndConfirm(() => songSelect = new TestPlaySongSelect()); From 7f82f103171223518fe34341f07dd07ab4be6c8f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 17 Feb 2024 19:00:43 +0800 Subject: [PATCH 188/223] Fix beatmap potentially loading in a bad state Over-caching could mean that a beatmap could load and cause a late crash. Let's catch it early to avoid such a crash occurring. --- osu.Game/Beatmaps/WorkingBeatmapCache.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index 74a85cde7c..8af74d11d8 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -9,6 +9,7 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Audio; using osu.Framework.Audio.Track; +using osu.Framework.Extensions; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Dummy; using osu.Framework.Graphics.Textures; @@ -143,8 +144,6 @@ namespace osu.Game.Beatmaps { string fileStorePath = BeatmapSetInfo.GetPathForFile(BeatmapInfo.Path); - // TODO: check validity of file - var stream = GetStream(fileStorePath); if (stream == null) @@ -153,6 +152,12 @@ namespace osu.Game.Beatmaps return null; } + if (stream.ComputeMD5Hash() != BeatmapInfo.MD5Hash) + { + Logger.Log($"Beatmap failed to load (file {BeatmapInfo.Path} does not have the expected hash).", level: LogLevel.Error); + return null; + } + using (var reader = new LineBufferedReader(stream)) return Decoder.GetDecoder(reader).Decode(reader); } From 1ca566c6b0001dace3e3a3911c51f66cbf8536fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Feb 2024 09:45:03 +0100 Subject: [PATCH 189/223] Disable nested input managers on edited screen when skin editor is open --- .../Overlays/SkinEditor/SkinEditorOverlay.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs index 40cd31934f..93e2f92a1c 100644 --- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs +++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs @@ -10,9 +10,11 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; +using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Screens; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Containers; @@ -66,6 +68,7 @@ namespace osu.Game.Overlays.SkinEditor private IBindable beatmap { get; set; } = null!; private OsuScreen? lastTargetScreen; + private InvokeOnDisposal? nestedInputManagerDisable; private Vector2 lastDrawSize; @@ -105,6 +108,7 @@ namespace osu.Game.Overlays.SkinEditor if (skinEditor != null) { + disableNestedInputManagers(); skinEditor.Show(); return; } @@ -132,6 +136,8 @@ namespace osu.Game.Overlays.SkinEditor { skinEditor?.Save(false); skinEditor?.Hide(); + nestedInputManagerDisable?.Dispose(); + nestedInputManagerDisable = null; globallyReenableBeatmapSkinSetting(); } @@ -243,6 +249,9 @@ namespace osu.Game.Overlays.SkinEditor /// public void SetTarget(OsuScreen screen) { + nestedInputManagerDisable?.Dispose(); + nestedInputManagerDisable = null; + lastTargetScreen = screen; if (skinEditor == null) return; @@ -271,6 +280,7 @@ namespace osu.Game.Overlays.SkinEditor { skinEditor.Save(false); skinEditor.UpdateTargetScreen(target); + disableNestedInputManagers(); } else { @@ -280,6 +290,21 @@ namespace osu.Game.Overlays.SkinEditor } } + private void disableNestedInputManagers() + { + if (lastTargetScreen == null) + return; + + var nestedInputManagers = lastTargetScreen.ChildrenOfType().Where(manager => manager.UseParentInput).ToArray(); + foreach (var inputManager in nestedInputManagers) + inputManager.UseParentInput = false; + nestedInputManagerDisable = new InvokeOnDisposal(() => + { + foreach (var inputManager in nestedInputManagers) + inputManager.UseParentInput = true; + }); + } + private readonly Bindable beatmapSkins = new Bindable(); private LeasedBindable? leasedBeatmapSkins; From ec26ab51d18d5e4e46ee30782ebc388461c4073f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Feb 2024 13:56:21 +0100 Subject: [PATCH 190/223] Use different wording --- osu.Game/Screens/Play/SubmittingPlayer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 0873f60791..ecb507f382 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -137,11 +137,11 @@ namespace osu.Game.Screens.Play if (displayNotification || shouldExit) { string whatWillHappen = shouldExit - ? "You are not able to submit a score." - : "The following score will not be submitted."; + ? "Play in this state is not permitted." + : "Your score will not be submitted."; if (string.IsNullOrEmpty(exception.Message)) - Logger.Error(exception, $"{whatWillHappen} Failed to retrieve a score submission token."); + Logger.Error(exception, $"Failed to retrieve a score submission token.\n\n{whatWillHappen}"); else { switch (exception.Message) @@ -149,11 +149,11 @@ namespace osu.Game.Screens.Play case @"missing token header": case @"invalid client hash": case @"invalid verification hash": - Logger.Log($"{whatWillHappen} Please ensure that you are using the latest version of the official game releases.", level: LogLevel.Important); + Logger.Log($"Please ensure that you are using the latest version of the official game releases.\n\n{whatWillHappen}", level: LogLevel.Important); break; case @"expired token": - Logger.Log($"{whatWillHappen} Your system clock is set incorrectly. Please check your system time, date and timezone.", level: LogLevel.Important); + Logger.Log($"Your system clock is set incorrectly. Please check your system time, date and timezone.\n\n{whatWillHappen}", level: LogLevel.Important); break; default: From 012d6b7fe1058696e92eaf3c2eee589da50e4f3c Mon Sep 17 00:00:00 2001 From: Mike Will Date: Sun, 18 Feb 2024 22:16:54 -0500 Subject: [PATCH 191/223] Change `userBeatmapOffsetClock` to a `FramedOffsetClock` Assuming that the global audio offset is set perfectly, such that any audio latency is fully accounted for, if a specific beatmap still sounds out of sync, that would no longer be a latency issue. Instead, it would indicate a misalignment between the beatmap's track and time codes, the correction for which should be a virtual-time offset, not a real-time offset. --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index d0ffbdd459..49dff96ff1 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps private readonly OffsetCorrectionClock? userGlobalOffsetClock; private readonly OffsetCorrectionClock? platformOffsetClock; - private readonly OffsetCorrectionClock? userBeatmapOffsetClock; + private readonly FramedOffsetClock? userBeatmapOffsetClock; private readonly IFrameBasedClock finalClockSource; @@ -70,7 +70,7 @@ namespace osu.Game.Beatmaps userGlobalOffsetClock = new OffsetCorrectionClock(platformOffsetClock); // User per-beatmap offset will be applied to this final clock. - finalClockSource = userBeatmapOffsetClock = new OffsetCorrectionClock(userGlobalOffsetClock); + finalClockSource = userBeatmapOffsetClock = new FramedOffsetClock(userGlobalOffsetClock); } else { @@ -122,7 +122,7 @@ namespace osu.Game.Beatmaps Debug.Assert(userBeatmapOffsetClock != null); Debug.Assert(platformOffsetClock != null); - return userGlobalOffsetClock.RateAdjustedOffset + userBeatmapOffsetClock.RateAdjustedOffset + platformOffsetClock.RateAdjustedOffset; + return userGlobalOffsetClock.RateAdjustedOffset + userBeatmapOffsetClock.Offset + platformOffsetClock.RateAdjustedOffset; } } From 29900353d924e2dd2efc54f98df5b1fdd8bcd38b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Feb 2024 20:26:15 +0300 Subject: [PATCH 192/223] Reduce allocations in SliderSelectionBlueprint --- .../Sliders/SliderSelectionBlueprint.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index e421d497e7..4d2b980c23 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -416,8 +416,22 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation) }; - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => - BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)) == true; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) + { + if (BodyPiece.ReceivePositionalInputAt(screenSpacePos)) + return true; + + if (ControlPointVisualiser == null) + return false; + + foreach (var p in ControlPointVisualiser.Pieces) + { + if (p.ReceivePositionalInputAt(screenSpacePos)) + return true; + } + + return false; + } protected virtual SliderCircleOverlay CreateCircleOverlay(Slider slider, SliderPosition position) => new SliderCircleOverlay(slider, position); } From c7586403112e4616d12817e0dd3d52e7d8dea487 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Feb 2024 20:49:56 +0300 Subject: [PATCH 193/223] Reduce allocations in ComposerDistanceSnapProvider --- .../Edit/ComposerDistanceSnapProvider.cs | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs index b3ca59a5b0..b2f38662cc 100644 --- a/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs +++ b/osu.Game/Rulesets/Edit/ComposerDistanceSnapProvider.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -124,12 +123,34 @@ namespace osu.Game.Rulesets.Edit private (HitObject before, HitObject after)? getObjectsOnEitherSideOfCurrentTime() { - HitObject? lastBefore = playfield.HitObjectContainer.AliveObjects.LastOrDefault(h => h.HitObject.StartTime < editorClock.CurrentTime)?.HitObject; + HitObject? lastBefore = null; + + foreach (var entry in playfield.HitObjectContainer.AliveEntries) + { + double objTime = entry.Value.HitObject.StartTime; + + if (objTime >= editorClock.CurrentTime) + continue; + + if (objTime > lastBefore?.StartTime) + lastBefore = entry.Value.HitObject; + } if (lastBefore == null) return null; - HitObject? firstAfter = playfield.HitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime >= editorClock.CurrentTime)?.HitObject; + HitObject? firstAfter = null; + + foreach (var entry in playfield.HitObjectContainer.AliveEntries) + { + double objTime = entry.Value.HitObject.StartTime; + + if (objTime < editorClock.CurrentTime) + continue; + + if (objTime < firstAfter?.StartTime) + firstAfter = entry.Value.HitObject; + } if (firstAfter == null) return null; From 3791ab30c44acaaa312f4180c4a82263d2b1aa7c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 19 Feb 2024 20:55:43 +0300 Subject: [PATCH 194/223] Reduce allocations in HitCircleOverlapMarker --- .../HitCircles/Components/HitCircleOverlapMarker.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs index 3cba0610a1..fe335a048d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs @@ -78,9 +78,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components Scale = new Vector2(hitObject.Scale); - if (hitObject is IHasComboInformation combo) - ring.BorderColour = combo.GetComboColour(skin); - double editorTime = editorClock.CurrentTime; double hitObjectTime = hitObject.StartTime; bool hasReachedObject = editorTime >= hitObjectTime; @@ -92,6 +89,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components ring.Scale = new Vector2(1 + 0.1f * ringScale); content.Alpha = 0.9f * (1 - alpha); + + // TODO: should only update colour on skin/combo/object change. + if (hitObject is IHasComboInformation combo && content.Alpha > 0) + ring.BorderColour = combo.GetComboColour(skin); } else content.Alpha = 0; From 2ff8667dd2e433fd7abb832cc8bb91def14c44d1 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 19 Feb 2024 12:11:12 -0800 Subject: [PATCH 195/223] Revert "Centralise global rank display logic to new class" Also don't show on `LoginOverlay` usage for now. --- .../Header/Components/GlobalRankDisplay.cs | 44 ------------------- .../Profile/Header/Components/MainDetails.cs | 17 +++++-- osu.Game/Users/UserRankPanel.cs | 13 +++--- 3 files changed, 19 insertions(+), 55 deletions(-) delete mode 100644 osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs diff --git a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs b/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs deleted file mode 100644 index d32f56ab1b..0000000000 --- a/osu.Game/Overlays/Profile/Header/Components/GlobalRankDisplay.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osu.Framework.Extensions.LocalisationExtensions; -using osu.Framework.Localisation; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Users; - -namespace osu.Game.Overlays.Profile.Header.Components -{ - public partial class GlobalRankDisplay : ProfileValueDisplay - { - public readonly Bindable UserStatistics = new Bindable(); - public readonly Bindable User = new Bindable(); - - public GlobalRankDisplay() - : base(true) - { - Title = UsersStrings.ShowRankGlobalSimple; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - UserStatistics.BindValueChanged(s => - { - Content = s.NewValue?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; - }, true); - - // needed as `UserStatistics` doesn't populate `User` - User.BindValueChanged(u => - { - var rankHighest = u.NewValue?.RankHighest; - - ContentTooltipText = rankHighest != null - ? UsersStrings.ShowRankHighest(rankHighest.Rank.ToLocalisableString("\\##,##0"), rankHighest.UpdatedAt.ToLocalisableString(@"d MMM yyyy")) - : string.Empty; - }, true); - } - } -} diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs index ffdf8edc21..2505c1bc8c 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private readonly Dictionary scoreRankInfos = new Dictionary(); private ProfileValueDisplay medalInfo = null!; private ProfileValueDisplay ppInfo = null!; - private GlobalRankDisplay detailGlobalRank = null!; + private ProfileValueDisplay detailGlobalRank = null!; private ProfileValueDisplay detailCountryRank = null!; private RankGraph rankGraph = null!; @@ -52,7 +52,10 @@ namespace osu.Game.Overlays.Profile.Header.Components Spacing = new Vector2(20), Children = new Drawable[] { - detailGlobalRank = new GlobalRankDisplay(), + detailGlobalRank = new ProfileValueDisplay(true) + { + Title = UsersStrings.ShowRankGlobalSimple, + }, detailCountryRank = new ProfileValueDisplay(true) { Title = UsersStrings.ShowRankCountrySimple, @@ -139,8 +142,14 @@ namespace osu.Game.Overlays.Profile.Header.Components foreach (var scoreRankInfo in scoreRankInfos) scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; - detailGlobalRank.UserStatistics.Value = user?.Statistics; - detailGlobalRank.User.Value = user; + detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + + var rankHighest = user?.RankHighest; + + detailGlobalRank.ContentTooltipText = rankHighest != null + ? UsersStrings.ShowRankHighest(rankHighest.Rank.ToLocalisableString("\\##,##0"), rankHighest.UpdatedAt.ToLocalisableString(@"d MMM yyyy")) + : string.Empty; + detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; rankGraph.Statistics.Value = user?.Statistics; diff --git a/osu.Game/Users/UserRankPanel.cs b/osu.Game/Users/UserRankPanel.cs index 0b8a5166e6..b440261a4c 100644 --- a/osu.Game/Users/UserRankPanel.cs +++ b/osu.Game/Users/UserRankPanel.cs @@ -27,10 +27,10 @@ namespace osu.Game.Users [Resolved] private IAPIProvider api { get; set; } = null!; + private ProfileValueDisplay globalRankDisplay = null!; private ProfileValueDisplay countryRankDisplay = null!; private readonly IBindable statistics = new Bindable(); - private readonly IBindable user = new Bindable(); public UserRankPanel(APIUser user) : base(user) @@ -47,10 +47,9 @@ namespace osu.Game.Users statistics.BindTo(api.Statistics); statistics.BindValueChanged(stats => { + globalRankDisplay.Content = stats.NewValue?.GlobalRank?.ToLocalisableString("\\##,##0") ?? "-"; countryRankDisplay.Content = stats.NewValue?.CountryRank?.ToLocalisableString("\\##,##0") ?? "-"; }, true); - - user.BindTo(api.LocalUser!); } protected override Drawable CreateLayout() @@ -164,12 +163,12 @@ namespace osu.Game.Users { new Drawable[] { - new GlobalRankDisplay + globalRankDisplay = new ProfileValueDisplay(true) { - UserStatistics = { BindTarget = statistics }, - // TODO: make highest rank update, as `api.LocalUser` doesn't update + Title = UsersStrings.ShowRankGlobalSimple, + // TODO: implement highest rank tooltip + // `RankHighest` resides in `APIUser`, but `api.LocalUser` doesn't update // maybe move to `UserStatistics` in api, so `SoloStatisticsWatcher` can update the value - User = { BindTarget = user }, }, countryRankDisplay = new ProfileValueDisplay(true) { From 40d6e8ce85cbd516a75510299c230d4048fd5b25 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Feb 2024 15:13:22 +0900 Subject: [PATCH 196/223] Remove legacy OpenGL renderer option, it's now just OpenGL --- .../Sections/Graphics/RendererSettings.cs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs index fc5dd34971..a8b127d522 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; -using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Extensions; @@ -28,15 +27,16 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics var renderer = config.GetBindable(FrameworkSetting.Renderer); automaticRendererInUse = renderer.Value == RendererType.Automatic; - SettingsEnumDropdown rendererDropdown; - Children = new Drawable[] { - rendererDropdown = new RendererSettingsDropdown + new RendererSettingsDropdown { LabelText = GraphicsSettingsStrings.Renderer, Current = renderer, - Items = host.GetPreferredRenderersForCurrentPlatform().Order().Where(t => t != RendererType.Vulkan), + Items = host.GetPreferredRenderersForCurrentPlatform().Order() +#pragma warning disable CS0612 // Type or member is obsolete + .Where(t => t != RendererType.Vulkan && t != RendererType.OpenGLLegacy), +#pragma warning restore CS0612 // Type or member is obsolete Keywords = new[] { @"compatibility", @"directx" }, }, // TODO: this needs to be a custom dropdown at some point @@ -79,13 +79,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics })); } }); - - // TODO: remove this once we support SDL+android. - if (RuntimeInfo.OS == RuntimeInfo.Platform.Android) - { - rendererDropdown.Items = new[] { RendererType.Automatic, RendererType.OpenGLLegacy }; - rendererDropdown.SetNoticeText("New renderer support for android is coming soon!", true); - } } private partial class RendererSettingsDropdown : SettingsEnumDropdown From e9aca9226a43285bded225e75465b41045965938 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Feb 2024 19:10:03 +0300 Subject: [PATCH 197/223] Reduce allocations in ManiaPlayfield.TotalColumns --- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 0d36f51943..b3420c49f3 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using System; using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics.Primitives; using osu.Game.Rulesets.Mania.Beatmaps; @@ -149,7 +148,18 @@ namespace osu.Game.Rulesets.Mania.UI /// /// Retrieves the total amount of columns across all stages in this playfield. /// - public int TotalColumns => stages.Sum(s => s.Columns.Length); + public int TotalColumns + { + get + { + int sum = 0; + + foreach (var stage in stages) + sum += stage.Columns.Length; + + return sum; + } + } private Stage getStageByColumn(int column) { From 6678c4783bc338287b6465f65cf7a8bb3ee2d288 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Feb 2024 19:31:28 +0300 Subject: [PATCH 198/223] Fix PlaybackControl string allocations --- osu.Game/Screens/Edit/Components/PlaybackControl.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 431336aa60..a5ed0d680f 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -97,11 +97,14 @@ namespace osu.Game.Screens.Edit.Components editorClock.Start(); } + private static readonly IconUsage play_icon = FontAwesome.Regular.PlayCircle; + private static readonly IconUsage pause_icon = FontAwesome.Regular.PauseCircle; + protected override void Update() { base.Update(); - playButton.Icon = editorClock.IsRunning ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle; + playButton.Icon = editorClock.IsRunning ? pause_icon : play_icon; } private partial class PlaybackTabControl : OsuTabControl From 871bdb9cf7919088f0344cf9c9f6ca37b204b622 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Feb 2024 19:38:57 +0300 Subject: [PATCH 199/223] Reduce string allocations in TimeInfoContainer --- .../Edit/Components/TimeInfoContainer.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs index 9c51258f17..4747828bca 100644 --- a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs +++ b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs @@ -47,11 +47,26 @@ namespace osu.Game.Screens.Edit.Components }; } + private double? lastTime; + private double? lastBPM; + protected override void Update() { base.Update(); - trackTimer.Text = editorClock.CurrentTime.ToEditorFormattedString(); - bpm.Text = @$"{editorBeatmap.ControlPointInfo.TimingPointAt(editorClock.CurrentTime).BPM:0} BPM"; + + if (lastTime != editorClock.CurrentTime) + { + lastTime = editorClock.CurrentTime; + trackTimer.Text = editorClock.CurrentTime.ToEditorFormattedString(); + } + + double newBPM = editorBeatmap.ControlPointInfo.TimingPointAt(editorClock.CurrentTime).BPM; + + if (lastBPM != newBPM) + { + lastBPM = newBPM; + bpm.Text = @$"{newBPM:0} BPM"; + } } } } From b92cff9a8ed370c59fca69dba9b9cb9923efa737 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Feb 2024 20:29:35 +0300 Subject: [PATCH 200/223] Reduce allocations in ManiaSelectionBlueprint --- .../Blueprints/ManiaSelectionBlueprint.cs | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs index 1ae65dd8c0..c645ddd98d 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Objects; @@ -17,9 +18,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints [Resolved] private Playfield playfield { get; set; } = null!; - [Resolved] - private IScrollingInfo scrollingInfo { get; set; } = null!; - protected ScrollingHitObjectContainer HitObjectContainer => ((ManiaPlayfield)playfield).GetColumn(HitObject.Column).HitObjectContainer; protected ManiaSelectionBlueprint(T hitObject) @@ -28,14 +26,31 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints RelativeSizeAxes = Axes.None; } - protected override void Update() - { - base.Update(); + private readonly IBindable directionBindable = new Bindable(); - var anchor = scrollingInfo.Direction.Value == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; + [BackgroundDependencyLoader] + private void load(IScrollingInfo scrollingInfo) + { + directionBindable.BindTo(scrollingInfo.Direction); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + directionBindable.BindValueChanged(onDirectionChanged, true); + } + + private void onDirectionChanged(ValueChangedEvent direction) + { + var anchor = direction.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; Anchor = Origin = anchor; foreach (var child in InternalChildren) child.Anchor = child.Origin = anchor; + } + + protected override void Update() + { + base.Update(); Position = Parent!.ToLocalSpace(HitObjectContainer.ScreenSpacePositionAtTime(HitObject.StartTime)) - AnchorPosition; Width = HitObjectContainer.DrawWidth; From 2543a48ac83a2983b76da3bfe5d63f55ad3b1544 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 20 Feb 2024 23:18:37 +0300 Subject: [PATCH 201/223] Apply padding to GridContainers directly --- .../Chat/ChannelList/ChannelListItem.cs | 56 ++++---- .../Profile/Header/DetailHeaderContainer.cs | 63 ++++----- osu.Game/Screens/Edit/BottomBar.cs | 46 +++---- .../Compose/Components/BeatDivisorControl.cs | 89 +++++------- .../Screens/Edit/EditorScreenWithTimeline.cs | 35 ++--- .../Screens/Edit/Timing/TapTimingControl.cs | 35 ++--- osu.Game/Screens/Edit/Verify/VerifyScreen.cs | 24 ++-- .../Components/MatchBeatmapDetailArea.cs | 52 ++++--- .../Lounge/Components/PillContainer.cs | 30 ++-- .../Playlists/PlaylistsRoomSubScreen.cs | 42 +++--- .../ContractedPanelMiddleContent.cs | 50 ++++--- osu.Game/Screens/Select/BeatmapDetails.cs | 129 +++++++++--------- 12 files changed, 292 insertions(+), 359 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index 21b6147113..87b1f4ef01 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -66,41 +66,37 @@ namespace osu.Game.Overlays.Chat.ChannelList Colour = colourProvider.Background4, Alpha = 0f, }, - new Container + new GridContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Left = 18, Right = 10 }, - Child = new GridContainer + ColumnDimensions = new[] { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - }, - Content = new[] - { - new Drawable?[] - { - createIcon(), - text = new TruncatingSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = Channel.Name, - Font = OsuFont.Torus.With(size: 17, weight: FontWeight.SemiBold), - Colour = colourProvider.Light3, - Margin = new MarginPadding { Bottom = 2 }, - RelativeSizeAxes = Axes.X, - }, - createMentionPill(), - close = createCloseButton(), - } - }, + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), }, - }, + Content = new[] + { + new Drawable?[] + { + createIcon(), + text = new TruncatingSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = Channel.Name, + Font = OsuFont.Torus.With(size: 17, weight: FontWeight.SemiBold), + Colour = colourProvider.Light3, + Margin = new MarginPadding { Bottom = 2 }, + RelativeSizeAxes = Axes.X, + }, + createMentionPill(), + close = createCloseButton(), + } + } + } }; Action = () => OnRequestSelect?.Invoke(Channel); diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 1f35f39b49..118bf9171e 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -26,47 +26,42 @@ namespace osu.Game.Overlays.Profile.Header RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, }, - new Container + new GridContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING, Vertical = 10 }, - Child = new GridContainer + RowDimensions = new[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - RowDimensions = new[] + new Dimension(GridSizeMode.AutoSize), + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] { - new Dimension(GridSizeMode.AutoSize), - }, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - }, - Content = new[] - { - new Drawable[] + new MainDetails { - new MainDetails - { - RelativeSizeAxes = Axes.X, - User = { BindTarget = User } - }, - new Box - { - RelativeSizeAxes = Axes.Y, - Width = 2, - Colour = colourProvider.Background6, - Margin = new MarginPadding { Horizontal = 15 } - }, - new ExtendedDetails - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - User = { BindTarget = User } - } + RelativeSizeAxes = Axes.X, + User = { BindTarget = User } + }, + new Box + { + RelativeSizeAxes = Axes.Y, + Width = 2, + Colour = colourProvider.Background6, + Margin = new MarginPadding { Horizontal = 15 } + }, + new ExtendedDetails + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + User = { BindTarget = User } } } } diff --git a/osu.Game/Screens/Edit/BottomBar.cs b/osu.Game/Screens/Edit/BottomBar.cs index aa3c4ba0d0..bc7dfaab88 100644 --- a/osu.Game/Screens/Edit/BottomBar.cs +++ b/osu.Game/Screens/Edit/BottomBar.cs @@ -47,35 +47,31 @@ namespace osu.Game.Screens.Edit RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background4, }, - new Container + new GridContainer { RelativeSizeAxes = Axes.Both, - Child = new GridContainer + ColumnDimensions = new[] { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Absolute, 170), - new Dimension(), - new Dimension(GridSizeMode.Absolute, 220), - new Dimension(GridSizeMode.Absolute, HitObjectComposer.TOOLBOX_CONTRACTED_SIZE_RIGHT), - }, - Content = new[] - { - new Drawable[] - { - new TimeInfoContainer { RelativeSizeAxes = Axes.Both }, - new SummaryTimeline { RelativeSizeAxes = Axes.Both }, - new PlaybackControl { RelativeSizeAxes = Axes.Both }, - TestGameplayButton = new TestGameplayButton - { - RelativeSizeAxes = Axes.Both, - Size = new Vector2(1), - Action = editor.TestGameplay, - } - }, - } + new Dimension(GridSizeMode.Absolute, 170), + new Dimension(), + new Dimension(GridSizeMode.Absolute, 220), + new Dimension(GridSizeMode.Absolute, HitObjectComposer.TOOLBOX_CONTRACTED_SIZE_RIGHT), }, + Content = new[] + { + new Drawable[] + { + new TimeInfoContainer { RelativeSizeAxes = Axes.Both }, + new SummaryTimeline { RelativeSizeAxes = Axes.Both }, + new PlaybackControl { RelativeSizeAxes = Axes.Both }, + TestGameplayButton = new TestGameplayButton + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(1), + Action = editor.TestGameplay, + } + }, + } } }; } diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index da1a37d57f..40b97d2137 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -86,35 +86,31 @@ namespace osu.Game.Screens.Edit.Compose.Components RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background3 }, - new Container + new GridContainer { RelativeSizeAxes = Axes.Both, - Child = new GridContainer + Content = new[] { - RelativeSizeAxes = Axes.Both, - Content = new[] + new Drawable[] { - new Drawable[] + new ChevronButton { - new ChevronButton - { - Icon = FontAwesome.Solid.ChevronLeft, - Action = beatDivisor.SelectPrevious - }, - new DivisorDisplay { BeatDivisor = { BindTarget = beatDivisor } }, - new ChevronButton - { - Icon = FontAwesome.Solid.ChevronRight, - Action = beatDivisor.SelectNext - } + Icon = FontAwesome.Solid.ChevronLeft, + Action = beatDivisor.SelectPrevious }, + new DivisorDisplay { BeatDivisor = { BindTarget = beatDivisor } }, + new ChevronButton + { + Icon = FontAwesome.Solid.ChevronRight, + Action = beatDivisor.SelectNext + } }, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Absolute, 20), - new Dimension(), - new Dimension(GridSizeMode.Absolute, 20) - } + }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Absolute, 20), + new Dimension(), + new Dimension(GridSizeMode.Absolute, 20) } } } @@ -122,42 +118,31 @@ namespace osu.Game.Screens.Edit.Compose.Components }, new Drawable[] { - new Container + new GridContainer { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + Content = new[] { - new Container + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Child = new GridContainer + new ChevronButton { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new ChevronButton - { - Icon = FontAwesome.Solid.ChevronLeft, - Action = () => cycleDivisorType(-1) - }, - new DivisorTypeText { BeatDivisor = { BindTarget = beatDivisor } }, - new ChevronButton - { - Icon = FontAwesome.Solid.ChevronRight, - Action = () => cycleDivisorType(1) - } - }, - }, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Absolute, 20), - new Dimension(), - new Dimension(GridSizeMode.Absolute, 20) - } + Icon = FontAwesome.Solid.ChevronLeft, + Action = () => cycleDivisorType(-1) + }, + new DivisorTypeText { BeatDivisor = { BindTarget = beatDivisor } }, + new ChevronButton + { + Icon = FontAwesome.Solid.ChevronRight, + Action = () => cycleDivisorType(1) } - } + }, + }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Absolute, 20), + new Dimension(), + new Dimension(GridSizeMode.Absolute, 20) } } }, diff --git a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs index 575a66d421..2b97d363f1 100644 --- a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs +++ b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs @@ -57,37 +57,32 @@ namespace osu.Game.Screens.Edit RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background4 }, - new Container + new GridContainer { Name = "Timeline content", RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Horizontal = PADDING, Top = PADDING }, - Child = new GridContainer + Content = new[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Content = new[] + new Drawable[] { - new Drawable[] + TimelineContent = new Container { - TimelineContent = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, }, }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - }, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 90), - } }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 90), + } } } }, diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index bb7a3b8be3..8cdbd97ecb 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -65,35 +65,28 @@ namespace osu.Game.Screens.Edit.Timing { new Drawable[] { - new Container + new GridContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(padding), - Children = new Drawable[] + ColumnDimensions = new[] { - new GridContainer + new Dimension(GridSizeMode.AutoSize), + new Dimension() + }, + Content = new[] + { + new Drawable[] { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] + metronome = new MetronomeDisplay { - new Dimension(GridSizeMode.AutoSize), - new Dimension() - }, - Content = new[] - { - new Drawable[] - { - metronome = new MetronomeDisplay - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - new WaveformComparisonDisplay() - } + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, }, + new WaveformComparisonDisplay() } - } - }, + }, + } }, new Drawable[] { diff --git a/osu.Game/Screens/Edit/Verify/VerifyScreen.cs b/osu.Game/Screens/Edit/Verify/VerifyScreen.cs index b6e0450e23..fe508860e0 100644 --- a/osu.Game/Screens/Edit/Verify/VerifyScreen.cs +++ b/osu.Game/Screens/Edit/Verify/VerifyScreen.cs @@ -34,25 +34,21 @@ namespace osu.Game.Screens.Edit.Verify InterpretedDifficulty.Default = StarDifficulty.GetDifficultyRating(EditorBeatmap.BeatmapInfo.StarRating); InterpretedDifficulty.SetDefault(); - Child = new Container + Child = new GridContainer { RelativeSizeAxes = Axes.Both, - Child = new GridContainer + ColumnDimensions = new[] { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] + new Dimension(), + new Dimension(GridSizeMode.Absolute, 250), + }, + Content = new[] + { + new Drawable[] { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 250), + IssueList = new IssueList(), + new IssueSettings(), }, - Content = new[] - { - new Drawable[] - { - IssueList = new IssueList(), - new IssueSettings(), - }, - } } }; } diff --git a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs index dec91d8a37..b0ede8d9b5 100644 --- a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs +++ b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs @@ -26,48 +26,44 @@ namespace osu.Game.Screens.OnlinePlay.Components [Resolved(typeof(Room))] protected BindableList Playlist { get; private set; } - private readonly Drawable playlistArea; + private readonly GridContainer playlistArea; private readonly DrawableRoomPlaylist playlist; public MatchBeatmapDetailArea() { - Add(playlistArea = new Container + Add(playlistArea = new GridContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Vertical = 10 }, - Child = new GridContainer + Content = new[] { - RelativeSizeAxes = Axes.Both, - Content = new[] + new Drawable[] { - new Drawable[] + new Container { - new Container + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Bottom = 10 }, + Child = playlist = new PlaylistsRoomSettingsPlaylist { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Bottom = 10 }, - Child = playlist = new PlaylistsRoomSettingsPlaylist - { - RelativeSizeAxes = Axes.Both - } + RelativeSizeAxes = Axes.Both } - }, - new Drawable[] - { - new RoundedButton - { - Text = "Add new playlist entry", - RelativeSizeAxes = Axes.Both, - Size = Vector2.One, - Action = () => CreateNewItem?.Invoke() - } - }, + } }, - RowDimensions = new[] + new Drawable[] { - new Dimension(), - new Dimension(GridSizeMode.Absolute, 50), - } + new RoundedButton + { + Text = "Add new playlist entry", + RelativeSizeAxes = Axes.Both, + Size = Vector2.One, + Action = () => CreateNewItem?.Invoke() + } + }, + }, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.Absolute, 50), } }); } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs index b473ea82c6..5f77742588 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs @@ -40,35 +40,31 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Colour = Color4.Black, Alpha = 0.5f }, - new Container + new GridContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = padding }, - Child = new GridContainer + ColumnDimensions = new[] { - AutoSizeAxes = Axes.Both, - ColumnDimensions = new[] + new Dimension(GridSizeMode.AutoSize, minSize: 80 - 2 * padding) + }, + Content = new[] + { + new[] { - new Dimension(GridSizeMode.AutoSize, minSize: 80 - 2 * padding) - }, - Content = new[] - { - new[] + new Container { - new Container + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Padding = new MarginPadding { Bottom = 2 }, + Child = content = new Container { AutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Padding = new MarginPadding { Bottom = 2 }, - Child = content = new Container - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } } } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index cf5a8e1985..2460f78c96 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -95,38 +95,34 @@ namespace osu.Game.Screens.OnlinePlay.Playlists new Drawable[] { // Playlist items column - new Container + new GridContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = 5 }, - Child = new GridContainer + Content = new[] { - RelativeSizeAxes = Axes.Both, - Content = new[] + new Drawable[] { new OverlinedPlaylistHeader(), }, + new Drawable[] { - new Drawable[] { new OverlinedPlaylistHeader(), }, - new Drawable[] + new DrawableRoomPlaylist { - new DrawableRoomPlaylist + RelativeSizeAxes = Axes.Both, + Items = { BindTarget = Room.Playlist }, + SelectedItem = { BindTarget = SelectedItem }, + AllowSelection = true, + AllowShowingResults = true, + RequestResults = item => { - RelativeSizeAxes = Axes.Both, - Items = { BindTarget = Room.Playlist }, - SelectedItem = { BindTarget = SelectedItem }, - AllowSelection = true, - AllowShowingResults = true, - RequestResults = item => - { - Debug.Assert(RoomId.Value != null); - ParentScreen?.Push(new PlaylistsResultsScreen(null, RoomId.Value.Value, item, false)); - } + Debug.Assert(RoomId.Value != null); + ParentScreen?.Push(new PlaylistsResultsScreen(null, RoomId.Value.Value, item, false)); } - }, + } }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - } + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), } }, // Spacer diff --git a/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs index 195cd03e9b..cfb6465e62 100644 --- a/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs @@ -150,44 +150,40 @@ namespace osu.Game.Screens.Ranking.Contracted }, new Drawable[] { - new Container + new GridContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Vertical = 5 }, - Child = new GridContainer + Content = new[] { - RelativeSizeAxes = Axes.Both, - Content = new[] + new Drawable[] { - new Drawable[] + new OsuSpriteText { - new OsuSpriteText + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Current = scoreManager.GetBindableTotalScoreString(score), + Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, fixedWidth: true), + Spacing = new Vector2(-1, 0) + }, + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 2 }, + Child = new DrawableRank(score.Rank) { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Current = scoreManager.GetBindableTotalScoreString(score), - Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, fixedWidth: true), - Spacing = new Vector2(-1, 0) - }, - }, - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 2 }, - Child = new DrawableRank(score.Rank) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } } - }, + } }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - } + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), } } }, diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index dec2c1c1de..2bb60716ff 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -75,99 +75,92 @@ namespace osu.Game.Screens.Select RelativeSizeAxes = Axes.Both, Colour = Colour4.Black.Opacity(0.3f), }, - new Container + new GridContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = spacing }, - Children = new Drawable[] + RowDimensions = new[] { - new GridContainer + new Dimension(GridSizeMode.AutoSize), + new Dimension() + }, + Content = new[] + { + new Drawable[] { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] + new FillFlowContainer { - new Dimension(GridSizeMode.AutoSize), - new Dimension() - }, - Content = new[] - { - new Drawable[] + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Children = new Drawable[] { new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Children = new Drawable[] + Width = 0.5f, + Spacing = new Vector2(spacing), + Padding = new MarginPadding { Right = spacing / 2 }, + Children = new[] { - new FillFlowContainer + new DetailBox().WithChild(new OnlineViewContainer(string.Empty) { RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Width = 0.5f, - Spacing = new Vector2(spacing), - Padding = new MarginPadding { Right = spacing / 2 }, - Children = new[] + Height = 134, + Padding = new MarginPadding { Horizontal = spacing, Top = spacing }, + Child = ratingsDisplay = new UserRatings { - new DetailBox().WithChild(new OnlineViewContainer(string.Empty) - { - RelativeSizeAxes = Axes.X, - Height = 134, - Padding = new MarginPadding { Horizontal = spacing, Top = spacing }, - Child = ratingsDisplay = new UserRatings - { - RelativeSizeAxes = Axes.Both, - }, - }), + RelativeSizeAxes = Axes.Both, }, - }, - new OsuScrollContainer + }), + }, + }, + new OsuScrollContainer + { + RelativeSizeAxes = Axes.X, + Height = 250, + Width = 0.5f, + ScrollbarVisible = false, + Padding = new MarginPadding { Left = spacing / 2 }, + Child = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + LayoutDuration = transition_duration, + LayoutEasing = Easing.OutQuad, + Children = new[] { - RelativeSizeAxes = Axes.X, - Height = 250, - Width = 0.5f, - ScrollbarVisible = false, - Padding = new MarginPadding { Left = spacing / 2 }, - Child = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - LayoutDuration = transition_duration, - LayoutEasing = Easing.OutQuad, - Children = new[] - { - description = new MetadataSectionDescription(query => songSelect?.Search(query)), - source = new MetadataSectionSource(query => songSelect?.Search(query)), - tags = new MetadataSectionTags(query => songSelect?.Search(query)), - }, - }, + description = new MetadataSectionDescription(query => songSelect?.Search(query)), + source = new MetadataSectionSource(query => songSelect?.Search(query)), + tags = new MetadataSectionTags(query => songSelect?.Search(query)), }, }, }, }, - new Drawable[] + }, + }, + new Drawable[] + { + failRetryContainer = new OnlineViewContainer("Sign in to view more details") + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - failRetryContainer = new OnlineViewContainer("Sign in to view more details") + new OsuSpriteText + { + Text = BeatmapsetsStrings.ShowInfoPointsOfFailure, + Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14), + }, + failRetryGraph = new FailRetryGraph { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = BeatmapsetsStrings.ShowInfoPointsOfFailure, - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14), - }, - failRetryGraph = new FailRetryGraph - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 14 + spacing / 2 }, - }, - }, + Padding = new MarginPadding { Top = 14 + spacing / 2 }, }, - } - } - }, - }, + }, + }, + } + } }, loading = new LoadingLayer(true) }; From 86e3b597b42e79eafdb6ea0722277b6a9882485b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Feb 2024 13:18:51 +0800 Subject: [PATCH 202/223] Fix `LegacyApproachCircle` incorrectly applying scaling factor --- .../Skinning/Legacy/LegacyApproachCircle.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs index 0bdea0cab1..8ff85090ca 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Skinning; -using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy @@ -26,10 +25,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy var texture = skin.GetTexture(@"approachcircle"); Debug.Assert(texture != null); Texture = texture.WithMaximumSize(OsuHitObject.OBJECT_DIMENSIONS * 2); - - // 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. - Scale = new Vector2(128 / 118f); } protected override void LoadComplete() From a11a83ac480f86f9420ee2f78abb01a2912b858d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Feb 2024 13:44:04 +0800 Subject: [PATCH 203/223] Improve comment regarding scale adjust of approach circles --- .../Skinning/Default/DefaultApproachCircle.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs index 272f4b5658..3a4c454bf1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs @@ -25,8 +25,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { Texture = textures.Get(@"Gameplay/osu/approachcircle").WithMaximumSize(OsuHitObject.OBJECT_DIMENSIONS * 2); - // 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. + // In triangles and argon skins, we expanded hitcircles to take up the full 128 px which are clickable, + // but still use the old approach circle sprite. To make it feel correct (ie. disappear as it collides + // with the hitcircle, *not when it overlaps the border*) we need to expand it slightly. Scale = new Vector2(128 / 118f); } From a137fa548080cf6c5ff5b6d79b427cf23a677d2b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Feb 2024 15:43:53 +0800 Subject: [PATCH 204/223] Fix classic skin follow circles animating from incorrect starting point --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs index fa2bb9b2ad..4a8b737206 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy // Note that the scale adjust here is 2 instead of DrawableSliderBall.FOLLOW_AREA to match legacy behaviour. // This means the actual tracking area for gameplay purposes is larger than the sprite (but skins may be accounting for this). - this.ScaleTo(0.5f).ScaleTo(2f, Math.Min(180f, remainingTime), Easing.Out) + this.ScaleTo(1f).ScaleTo(2f, Math.Min(180f, remainingTime), Easing.Out) .FadeTo(0).FadeTo(1f, Math.Min(60f, remainingTime)); } From 259be976e870db1fcc6f64f1382a23be02919ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 21 Feb 2024 11:42:34 +0100 Subject: [PATCH 205/223] Adjust test to fail --- .../SongSelect/TestSceneBeatmapCarousel.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index aa4c879468..de2ae3708f 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -629,7 +629,8 @@ namespace osu.Game.Tests.Visual.SongSelect { var sets = new List(); - const string zzz_string = "zzzzz"; + const string zzz_lowercase = "zzzzz"; + const string zzz_uppercase = "ZZZZZ"; AddStep("Populuate beatmap sets", () => { @@ -640,10 +641,16 @@ namespace osu.Game.Tests.Visual.SongSelect var set = TestResources.CreateTestBeatmapSetInfo(); if (i == 4) - set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string); + set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_uppercase); + + if (i == 8) + set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_lowercase); + + if (i == 12) + set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_uppercase); if (i == 16) - set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_string); + set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_lowercase); sets.Add(set); } @@ -652,9 +659,11 @@ namespace osu.Game.Tests.Visual.SongSelect loadBeatmaps(sets); AddStep("Sort by author", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Author }, false)); - AddAssert($"Check {zzz_string} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Author.Username == zzz_string); + AddAssert($"Check {zzz_uppercase} is last", () => carousel.BeatmapSets.Last().Metadata.Author.Username == zzz_uppercase); + AddAssert($"Check {zzz_lowercase} is second last", () => carousel.BeatmapSets.SkipLast(1).Last().Metadata.Author.Username == zzz_lowercase); AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); - AddAssert($"Check {zzz_string} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Artist == zzz_string); + AddAssert($"Check {zzz_uppercase} is last", () => carousel.BeatmapSets.Last().Metadata.Artist == zzz_uppercase); + AddAssert($"Check {zzz_lowercase} is second last", () => carousel.BeatmapSets.SkipLast(1).Last().Metadata.Artist == zzz_lowercase); } /// From 59235d6c50a796469bb29440745eec9e13d0e926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 21 Feb 2024 12:07:18 +0100 Subject: [PATCH 206/223] Implement custom comparer for expected carousel sort behaviour Co-authored-by: Salman Ahmed --- .../Utils/OrdinalSortByCaseStringComparer.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 osu.Game/Utils/OrdinalSortByCaseStringComparer.cs diff --git a/osu.Game/Utils/OrdinalSortByCaseStringComparer.cs b/osu.Game/Utils/OrdinalSortByCaseStringComparer.cs new file mode 100644 index 0000000000..99d73f644f --- /dev/null +++ b/osu.Game/Utils/OrdinalSortByCaseStringComparer.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 System.Collections.Generic; + +namespace osu.Game.Utils +{ + /// + /// This string comparer is something of a cross-over between and . + /// is used first, but is used as a tie-breaker. + /// + /// + /// This comparer's behaviour somewhat emulates , + /// but non-ordinal comparers - both culture-aware and culture-invariant - have huge performance overheads due to i18n factors (up to 5x slower). + /// + /// + /// Given the following strings to sort: [A, B, C, D, a, b, c, d, A] and a stable sorting algorithm: + /// + /// + /// would return [A, A, B, C, D, a, b, c, d]. + /// This is undesirable as letters are interleaved. + /// + /// + /// would return [A, a, A, B, b, C, c, D, d]. + /// Different letters are not interleaved, but because case is ignored, the As are left in arbitrary order. + /// + /// + /// + /// would return [a, A, A, b, B, c, C, d, D], which is the expected behaviour. + /// + /// + public class OrdinalSortByCaseStringComparer : IComparer + { + public static readonly OrdinalSortByCaseStringComparer INSTANCE = new OrdinalSortByCaseStringComparer(); + + private OrdinalSortByCaseStringComparer() + { + } + + public int Compare(string? a, string? b) + { + int result = StringComparer.OrdinalIgnoreCase.Compare(a, b); + if (result == 0) + result = -StringComparer.Ordinal.Compare(a, b); // negative to place lowercase letters before uppercase. + return result; + } + } +} From 04a2ac3df332fda91ae41c2ee9bc5e1300a60d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 21 Feb 2024 12:07:28 +0100 Subject: [PATCH 207/223] Add benchmarking for custom string comparer --- .../BenchmarkStringComparison.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 osu.Game.Benchmarks/BenchmarkStringComparison.cs diff --git a/osu.Game.Benchmarks/BenchmarkStringComparison.cs b/osu.Game.Benchmarks/BenchmarkStringComparison.cs new file mode 100644 index 0000000000..78e4130abe --- /dev/null +++ b/osu.Game.Benchmarks/BenchmarkStringComparison.cs @@ -0,0 +1,48 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using BenchmarkDotNet.Attributes; +using osu.Game.Utils; + +namespace osu.Game.Benchmarks +{ + public class BenchmarkStringComparison + { + private string[] strings = null!; + + [GlobalSetup] + public void GlobalSetUp() + { + strings = new string[10000]; + + for (int i = 0; i < strings.Length; ++i) + strings[i] = Guid.NewGuid().ToString(); + + for (int i = 0; i < strings.Length; ++i) + { + if (i % 2 == 0) + strings[i] = strings[i].ToUpperInvariant(); + } + } + + [Benchmark] + public void OrdinalIgnoreCase() => compare(StringComparer.OrdinalIgnoreCase); + + [Benchmark] + public void OrdinalSortByCase() => compare(OrdinalSortByCaseStringComparer.INSTANCE); + + [Benchmark] + public void InvariantCulture() => compare(StringComparer.InvariantCulture); + + private void compare(IComparer comparer) + { + for (int i = 0; i < strings.Length; ++i) + { + for (int j = i + 1; j < strings.Length; ++j) + _ = comparer.Compare(strings[i], strings[j]); + } + } + } +} From 929858226ad208e29746f1b22b80399623f07d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 21 Feb 2024 12:09:37 +0100 Subject: [PATCH 208/223] Use custom comparer in beatmap carousel for expected sort behaviour --- osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 6c41bc3805..bf0d7dcbde 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Beatmaps; using osu.Game.Screens.Select.Filter; +using osu.Game.Utils; namespace osu.Game.Screens.Select.Carousel { @@ -67,19 +68,19 @@ namespace osu.Game.Screens.Select.Carousel { default: case SortMode.Artist: - comparison = string.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist, StringComparison.Ordinal); + comparison = OrdinalSortByCaseStringComparer.INSTANCE.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist); break; case SortMode.Title: - comparison = string.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title, StringComparison.Ordinal); + comparison = OrdinalSortByCaseStringComparer.INSTANCE.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title); break; case SortMode.Author: - comparison = string.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username, StringComparison.Ordinal); + comparison = OrdinalSortByCaseStringComparer.INSTANCE.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username); break; case SortMode.Source: - comparison = string.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source, StringComparison.Ordinal); + comparison = OrdinalSortByCaseStringComparer.INSTANCE.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source); break; case SortMode.DateAdded: From fb593470d553c68b77e7ec129c47cfd9a21097d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Feb 2024 21:02:20 +0800 Subject: [PATCH 209/223] Use `DEFAULT` instead of `INSTANCE` or static field Matches other similar comparers. --- osu.Game.Benchmarks/BenchmarkStringComparison.cs | 2 +- osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 8 ++++---- osu.Game/Utils/OrdinalSortByCaseStringComparer.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Benchmarks/BenchmarkStringComparison.cs b/osu.Game.Benchmarks/BenchmarkStringComparison.cs index 78e4130abe..d40b92db5f 100644 --- a/osu.Game.Benchmarks/BenchmarkStringComparison.cs +++ b/osu.Game.Benchmarks/BenchmarkStringComparison.cs @@ -31,7 +31,7 @@ namespace osu.Game.Benchmarks public void OrdinalIgnoreCase() => compare(StringComparer.OrdinalIgnoreCase); [Benchmark] - public void OrdinalSortByCase() => compare(OrdinalSortByCaseStringComparer.INSTANCE); + public void OrdinalSortByCase() => compare(OrdinalSortByCaseStringComparer.DEFAULT); [Benchmark] public void InvariantCulture() => compare(StringComparer.InvariantCulture); diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index bf0d7dcbde..43c9c621e8 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -68,19 +68,19 @@ namespace osu.Game.Screens.Select.Carousel { default: case SortMode.Artist: - comparison = OrdinalSortByCaseStringComparer.INSTANCE.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist); + comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Artist, otherSet.BeatmapSet.Metadata.Artist); break; case SortMode.Title: - comparison = OrdinalSortByCaseStringComparer.INSTANCE.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title); + comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Title, otherSet.BeatmapSet.Metadata.Title); break; case SortMode.Author: - comparison = OrdinalSortByCaseStringComparer.INSTANCE.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username); + comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Author.Username, otherSet.BeatmapSet.Metadata.Author.Username); break; case SortMode.Source: - comparison = OrdinalSortByCaseStringComparer.INSTANCE.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source); + comparison = OrdinalSortByCaseStringComparer.DEFAULT.Compare(BeatmapSet.Metadata.Source, otherSet.BeatmapSet.Metadata.Source); break; case SortMode.DateAdded: diff --git a/osu.Game/Utils/OrdinalSortByCaseStringComparer.cs b/osu.Game/Utils/OrdinalSortByCaseStringComparer.cs index 99d73f644f..6c1532eef5 100644 --- a/osu.Game/Utils/OrdinalSortByCaseStringComparer.cs +++ b/osu.Game/Utils/OrdinalSortByCaseStringComparer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Utils /// public class OrdinalSortByCaseStringComparer : IComparer { - public static readonly OrdinalSortByCaseStringComparer INSTANCE = new OrdinalSortByCaseStringComparer(); + public static readonly OrdinalSortByCaseStringComparer DEFAULT = new OrdinalSortByCaseStringComparer(); private OrdinalSortByCaseStringComparer() { From 6d32cfb7ee7c466a6a8b673ea6b9cac3c66d6ffd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Feb 2024 21:39:33 +0800 Subject: [PATCH 210/223] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 85171cc0fa..30037c868c 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index f23debd38f..463a726856 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -23,6 +23,6 @@ iossimulator-x64 - + From 805f0b6a296aa2507d97fdeec1f14fe78e8c8854 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 21 Feb 2024 14:55:10 +0100 Subject: [PATCH 211/223] Remove unused using directive --- osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs index 25fe8170b1..5bf7c0326a 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Diagnostics; -using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; From 4cefa8bb8d256228266d204449610f443c6c37d6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 21 Feb 2024 22:47:49 +0300 Subject: [PATCH 212/223] Reduce allocations in TimelineBlueprintContainer --- .../Components/Timeline/TimelineBlueprintContainer.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index b60e04afc1..6ebd1961a2 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -116,6 +116,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline updateStacking(); } + private readonly Stack currentConcurrentObjects = new Stack(); + private void updateStacking() { // because only blueprints of objects which are alive (via pooling) are displayed in the timeline, it's feasible to do this every-update. @@ -125,10 +127,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline // after the stack gets this tall, we can presume there is space underneath to draw subsequent blueprints. const int stack_reset_count = 3; - Stack currentConcurrentObjects = new Stack(); + currentConcurrentObjects.Clear(); - foreach (var b in SelectionBlueprints.Reverse()) + for (int i = SelectionBlueprints.Count - 1; i >= 0; i--) { + var b = SelectionBlueprints[i]; + // remove objects from the stack as long as their end time is in the past. while (currentConcurrentObjects.TryPeek(out HitObject hitObject)) { From d01421b951bc308583caa0c687f0715ab55f34de Mon Sep 17 00:00:00 2001 From: Boudewijn Popkema Date: Wed, 21 Feb 2024 23:15:37 +0100 Subject: [PATCH 213/223] clear remembered username when checkbox is unticked --- osu.Game/Overlays/Login/LoginForm.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Login/LoginForm.cs b/osu.Game/Overlays/Login/LoginForm.cs index 80dfca93d2..a77baa3186 100644 --- a/osu.Game/Overlays/Login/LoginForm.cs +++ b/osu.Game/Overlays/Login/LoginForm.cs @@ -13,11 +13,11 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Overlays.Settings; using osu.Game.Resources.Localisation.Web; using osuTK; -using osu.Game.Localisation; namespace osu.Game.Overlays.Login { @@ -26,6 +26,7 @@ namespace osu.Game.Overlays.Login private TextBox username = null!; private TextBox password = null!; private ShakeContainer shakeSignIn = null!; + private SettingsCheckbox rememberUsername = null!; [Resolved] private IAPIProvider api { get; set; } = null!; @@ -82,7 +83,7 @@ namespace osu.Game.Overlays.Login }, }, }, - new SettingsCheckbox + rememberUsername = new SettingsCheckbox { LabelText = LoginPanelStrings.RememberUsername, Current = config.GetBindable(OsuSetting.SaveUsername), @@ -130,6 +131,7 @@ namespace osu.Game.Overlays.Login forgottenPasswordLink.AddLink(LayoutStrings.PopupLoginLoginForgot, $"{api.WebsiteRootUrl}/home/password-reset"); password.OnCommit += (_, _) => performLogin(); + rememberUsername.SettingChanged += () => onRememberUsernameChanged(config); if (api.LastLoginError?.Message is string error) { @@ -146,6 +148,12 @@ namespace osu.Game.Overlays.Login shakeSignIn.Shake(); } + private void onRememberUsernameChanged(OsuConfigManager config) + { + if (rememberUsername.Current.Value == false) + config.SetValue(OsuSetting.Username, string.Empty); + } + protected override bool OnClick(ClickEvent e) => true; protected override void OnFocus(FocusEvent e) From 2831ff60e1a361874f0285f1db74be7fa621300a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 09:39:49 +0100 Subject: [PATCH 214/223] Add test coverage --- .../Visual/Menus/TestSceneLoginOverlay.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoginOverlay.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoginOverlay.cs index 5fc075ed99..e603f72bb8 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneLoginOverlay.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneLoginOverlay.cs @@ -8,11 +8,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays; using osu.Game.Overlays.Login; +using osu.Game.Overlays.Settings; using osu.Game.Users.Drawables; using osuTK.Input; @@ -25,6 +27,9 @@ namespace osu.Game.Tests.Visual.Menus private LoginOverlay loginOverlay = null!; + [Resolved] + private OsuConfigManager configManager { get; set; } = null!; + [BackgroundDependencyLoader] private void load() { @@ -156,5 +161,36 @@ namespace osu.Game.Tests.Visual.Menus }); AddAssert("login overlay is hidden", () => loginOverlay.State.Value == Visibility.Hidden); } + + [Test] + public void TestUncheckingRememberUsernameClearsIt() + { + AddStep("logout", () => API.Logout()); + AddStep("set username", () => configManager.SetValue(OsuSetting.Username, "test_user")); + AddStep("set remember password", () => configManager.SetValue(OsuSetting.SavePassword, true)); + AddStep("uncheck remember username", () => + { + InputManager.MoveMouseTo(loginOverlay.ChildrenOfType().First()); + InputManager.Click(MouseButton.Left); + }); + AddAssert("remember username off", () => configManager.Get(OsuSetting.SaveUsername), () => Is.False); + AddAssert("remember password off", () => configManager.Get(OsuSetting.SavePassword), () => Is.False); + AddAssert("username cleared", () => configManager.Get(OsuSetting.Username), () => Is.Empty); + } + + [Test] + public void TestUncheckingRememberPasswordClearsToken() + { + AddStep("logout", () => API.Logout()); + AddStep("set token", () => configManager.SetValue(OsuSetting.Token, "test_token")); + AddStep("set remember password", () => configManager.SetValue(OsuSetting.SavePassword, true)); + AddStep("uncheck remember token", () => + { + InputManager.MoveMouseTo(loginOverlay.ChildrenOfType().Last()); + InputManager.Click(MouseButton.Left); + }); + AddAssert("remember password off", () => configManager.Get(OsuSetting.SavePassword), () => Is.False); + AddAssert("token cleared", () => configManager.Get(OsuSetting.Token), () => Is.Empty); + } } } From a1046f0a865641e5b7ffea225d3ad32b45ae4177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 09:40:27 +0100 Subject: [PATCH 215/223] Revert "clear remembered username when checkbox is unticked" This reverts commit d01421b951bc308583caa0c687f0715ab55f34de. --- osu.Game/Overlays/Login/LoginForm.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Login/LoginForm.cs b/osu.Game/Overlays/Login/LoginForm.cs index a77baa3186..80dfca93d2 100644 --- a/osu.Game/Overlays/Login/LoginForm.cs +++ b/osu.Game/Overlays/Login/LoginForm.cs @@ -13,11 +13,11 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Overlays.Settings; using osu.Game.Resources.Localisation.Web; using osuTK; +using osu.Game.Localisation; namespace osu.Game.Overlays.Login { @@ -26,7 +26,6 @@ namespace osu.Game.Overlays.Login private TextBox username = null!; private TextBox password = null!; private ShakeContainer shakeSignIn = null!; - private SettingsCheckbox rememberUsername = null!; [Resolved] private IAPIProvider api { get; set; } = null!; @@ -83,7 +82,7 @@ namespace osu.Game.Overlays.Login }, }, }, - rememberUsername = new SettingsCheckbox + new SettingsCheckbox { LabelText = LoginPanelStrings.RememberUsername, Current = config.GetBindable(OsuSetting.SaveUsername), @@ -131,7 +130,6 @@ namespace osu.Game.Overlays.Login forgottenPasswordLink.AddLink(LayoutStrings.PopupLoginLoginForgot, $"{api.WebsiteRootUrl}/home/password-reset"); password.OnCommit += (_, _) => performLogin(); - rememberUsername.SettingChanged += () => onRememberUsernameChanged(config); if (api.LastLoginError?.Message is string error) { @@ -148,12 +146,6 @@ namespace osu.Game.Overlays.Login shakeSignIn.Shake(); } - private void onRememberUsernameChanged(OsuConfigManager config) - { - if (rememberUsername.Current.Value == false) - config.SetValue(OsuSetting.Username, string.Empty); - } - protected override bool OnClick(ClickEvent e) => true; protected override void OnFocus(FocusEvent e) From 01f6ab0336a630a588b0938576660a02150bdeb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 09:44:59 +0100 Subject: [PATCH 216/223] Use more correct implementation --- osu.Game/Configuration/OsuConfigManager.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 6b2cb4ee74..a71460ded7 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -77,12 +77,19 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.SavePassword, false).ValueChanged += enabled => { - if (enabled.NewValue) SetValue(OsuSetting.SaveUsername, true); + if (enabled.NewValue) + SetValue(OsuSetting.SaveUsername, true); + else + GetBindable(OsuSetting.Token).SetDefault(); }; SetDefault(OsuSetting.SaveUsername, true).ValueChanged += enabled => { - if (!enabled.NewValue) SetValue(OsuSetting.SavePassword, false); + if (!enabled.NewValue) + { + GetBindable(OsuSetting.Username).SetDefault(); + SetValue(OsuSetting.SavePassword, false); + } }; SetDefault(OsuSetting.ExternalLinkWarning, true); From 81a9908c60012bde9ee9135c254ab2b891be5ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 10:27:37 +0100 Subject: [PATCH 217/223] Extract common helper for BPM rounding --- osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs | 4 ++-- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 7 ++++--- osu.Game/Utils/FormatUtils.cs | 10 ++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs b/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs index 1db02b7cf2..2f0b39bfbd 100644 --- a/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs +++ b/osu.Game/Overlays/Mods/BeatmapAttributesDisplay.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -20,6 +19,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; +using osu.Game.Utils; using osuTK; namespace osu.Game.Overlays.Mods @@ -169,7 +169,7 @@ namespace osu.Game.Overlays.Mods foreach (var mod in mods.Value.OfType()) rate = mod.ApplyToRate(0, rate); - bpmDisplay.Current.Value = (int)Math.Round(Math.Round(BeatmapInfo.Value.BPM) * rate); + bpmDisplay.Current.Value = FormatUtils.RoundBPM(BeatmapInfo.Value.BPM, rate); BeatmapDifficulty originalDifficulty = new BeatmapDifficulty(BeatmapInfo.Value.Difficulty); diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index c69cd6ead6..3cab4b67b6 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -31,6 +31,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osu.Game.Graphics.Containers; using osu.Game.Resources.Localisation.Web; +using osu.Game.Utils; namespace osu.Game.Screens.Select { @@ -405,9 +406,9 @@ namespace osu.Game.Screens.Select foreach (var mod in mods.Value.OfType()) rate = mod.ApplyToRate(0, rate); - int bpmMax = (int)Math.Round(Math.Round(beatmap.ControlPointInfo.BPMMaximum) * rate); - int bpmMin = (int)Math.Round(Math.Round(beatmap.ControlPointInfo.BPMMinimum) * rate); - int mostCommonBPM = (int)Math.Round(Math.Round(60000 / beatmap.GetMostCommonBeatLength()) * rate); + int bpmMax = FormatUtils.RoundBPM(beatmap.ControlPointInfo.BPMMaximum, rate); + int bpmMin = FormatUtils.RoundBPM(beatmap.ControlPointInfo.BPMMinimum, rate); + int mostCommonBPM = FormatUtils.RoundBPM(60000 / beatmap.GetMostCommonBeatLength(), rate); string labelText = bpmMin == bpmMax ? $"{bpmMin}" diff --git a/osu.Game/Utils/FormatUtils.cs b/osu.Game/Utils/FormatUtils.cs index 799dc75ca9..cccad3711c 100644 --- a/osu.Game/Utils/FormatUtils.cs +++ b/osu.Game/Utils/FormatUtils.cs @@ -49,5 +49,15 @@ namespace osu.Game.Utils return precision; } + + /// + /// Applies rounding to the given BPM value. + /// + /// + /// Double-rounding is applied intentionally (see https://github.com/ppy/osu/pull/18345#issue-1243311382 for rationale). + /// + /// The base BPM to round. + /// Rate adjustment, if applicable. + public static int RoundBPM(double baseBpm, double rate = 1) => (int)Math.Round(Math.Round(baseBpm) * rate); } } From 84fdcd24ef17194422a3aab9f3d6653955cda3d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 10:56:50 +0100 Subject: [PATCH 218/223] Remove description from mod search terms Closes https://github.com/ppy/osu/issues/27111. --- osu.Game/Overlays/Mods/ModPanel.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModPanel.cs b/osu.Game/Overlays/Mods/ModPanel.cs index 2d8d01d8c8..cf173b0d6a 100644 --- a/osu.Game/Overlays/Mods/ModPanel.cs +++ b/osu.Game/Overlays/Mods/ModPanel.cs @@ -77,12 +77,11 @@ namespace osu.Game.Overlays.Mods /// public bool Visible => modState.Visible; - public override IEnumerable FilterTerms => new[] + public override IEnumerable FilterTerms => new LocalisableString[] { Mod.Name, Mod.Name.Replace(" ", string.Empty), Mod.Acronym, - Mod.Description }; public override bool MatchingFilter From b08fcbd4e953af0051bf9560eba57006763ded43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 10:56:13 +0100 Subject: [PATCH 219/223] Adjust tests to new behaviour --- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 99a5897dff..b26e126249 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -788,7 +788,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("all columns visible", () => this.ChildrenOfType().All(col => col.IsPresent)); AddStep("set search", () => modSelectOverlay.SearchTerm = "HD"); - AddAssert("one column visible", () => this.ChildrenOfType().Count(col => col.IsPresent) == 1); + AddAssert("two columns visible", () => this.ChildrenOfType().Count(col => col.IsPresent) == 2); AddStep("filter out everything", () => modSelectOverlay.SearchTerm = "Some long search term with no matches"); AddAssert("no columns visible", () => this.ChildrenOfType().All(col => !col.IsPresent)); @@ -812,7 +812,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("all columns visible", () => this.ChildrenOfType().All(col => col.IsPresent)); AddStep("set search", () => modSelectOverlay.SearchTerm = "fail"); - AddAssert("one column visible", () => this.ChildrenOfType().Count(col => col.IsPresent) == 2); + AddAssert("one column visible", () => this.ChildrenOfType().Count(col => col.IsPresent) == 1); AddStep("hide", () => modSelectOverlay.Hide()); AddStep("show", () => modSelectOverlay.Show()); From 47db317df84862a68947c20e71dcfe87c552830f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 11:45:57 +0100 Subject: [PATCH 220/223] Enable NRT in `TestSceneDifficultyIcon` --- osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs index 80320c138b..e544177d50 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -16,7 +14,7 @@ namespace osu.Game.Tests.Visual.Beatmaps { public partial class TestSceneDifficultyIcon : OsuTestScene { - private FillFlowContainer fill; + private FillFlowContainer fill = null!; protected override void LoadComplete() { @@ -35,7 +33,7 @@ namespace osu.Game.Tests.Visual.Beatmaps [Test] public void CreateDifficultyIcon() { - DifficultyIcon difficultyIcon = null; + DifficultyIcon difficultyIcon = null!; AddRepeatStep("create difficulty icon", () => { From d06c67ad8f921b02990b954256c95c22c5e70f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 11:57:40 +0100 Subject: [PATCH 221/223] Substitute two jank interdependent bool flags for single tri-state enums --- .../Beatmaps/TestSceneDifficultyIcon.cs | 12 ++------ osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 29 ++++++++++++++----- .../Drawables/DifficultyIconTooltip.cs | 11 ++++--- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 2 +- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 2 +- .../Carousel/DrawableCarouselBeatmap.cs | 2 +- 6 files changed, 34 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs index e544177d50..6a226c2b8c 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs @@ -50,18 +50,12 @@ namespace osu.Game.Tests.Visual.Beatmaps fill.Add(difficultyIcon = new DifficultyIcon(beatmapInfo, rulesetInfo) { Scale = new Vector2(2), - ShowTooltip = true, - ShowExtendedTooltip = true }); }, 10); - AddStep("hide extended tooltip", () => difficultyIcon.ShowExtendedTooltip = false); - - AddStep("hide tooltip", () => difficultyIcon.ShowTooltip = false); - - AddStep("show tooltip", () => difficultyIcon.ShowTooltip = true); - - AddStep("show extended tooltip", () => difficultyIcon.ShowExtendedTooltip = true); + AddStep("no tooltip", () => difficultyIcon.TooltipType = DifficultyIconTooltipType.None); + AddStep("basic tooltip", () => difficultyIcon.TooltipType = DifficultyIconTooltipType.StarRating); + AddStep("extended tooltip", () => difficultyIcon.TooltipType = DifficultyIconTooltipType.Extended); } } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 73073a8286..2e7f894d12 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -32,14 +32,9 @@ namespace osu.Game.Beatmaps.Drawables } /// - /// Whether to display a tooltip on hover. Only works if a beatmap was provided at construction time. + /// Which type of tooltip to show. Only works if a beatmap was provided at construction time. /// - public bool ShowTooltip { get; set; } = true; - - /// - /// Whether to include the difficulty stats in the tooltip or not. Defaults to false. Has no effect if is false. - /// - public bool ShowExtendedTooltip { get; set; } + public DifficultyIconTooltipType TooltipType { get; set; } = DifficultyIconTooltipType.StarRating; private readonly IBeatmapInfo? beatmap; @@ -138,6 +133,24 @@ namespace osu.Game.Beatmaps.Drawables GetCustomTooltip() => new DifficultyIconTooltip(); DifficultyIconTooltipContent IHasCustomTooltip. - TooltipContent => (ShowTooltip && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current, ruleset, mods, ShowExtendedTooltip) : null)!; + TooltipContent => (TooltipType != DifficultyIconTooltipType.None && beatmap != null ? new DifficultyIconTooltipContent(beatmap, Current, ruleset, mods, TooltipType) : null)!; + } + + public enum DifficultyIconTooltipType + { + /// + /// No tooltip. + /// + None, + + /// + /// Star rating only. + /// + StarRating, + + /// + /// Star rating, OD, HP, CS, AR, length, BPM, and max combo. + /// + Extended, } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 71366de654..952f71332f 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -113,7 +113,7 @@ namespace osu.Game.Beatmaps.Drawables starRating.Current.BindTarget = displayedContent.Difficulty; difficultyName.Text = displayedContent.BeatmapInfo.DifficultyName; - if (!displayedContent.ShowExtendedTooltip) + if (displayedContent.TooltipType == DifficultyIconTooltipType.StarRating) { difficultyFillFlowContainer.Hide(); miscFillFlowContainer.Hide(); @@ -166,15 +166,18 @@ namespace osu.Game.Beatmaps.Drawables public readonly IBindable Difficulty; public readonly IRulesetInfo Ruleset; public readonly Mod[]? Mods; - public readonly bool ShowExtendedTooltip; + public readonly DifficultyIconTooltipType TooltipType; - public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty, IRulesetInfo rulesetInfo, Mod[]? mods, bool showExtendedTooltip = false) + public DifficultyIconTooltipContent(IBeatmapInfo beatmapInfo, IBindable difficulty, IRulesetInfo rulesetInfo, Mod[]? mods, DifficultyIconTooltipType tooltipType) { + if (tooltipType == DifficultyIconTooltipType.None) + throw new ArgumentOutOfRangeException(nameof(tooltipType), tooltipType, "Cannot instantiate a tooltip without a type"); + BeatmapInfo = beatmapInfo; Difficulty = difficulty; Ruleset = rulesetInfo; Mods = mods; - ShowExtendedTooltip = showExtendedTooltip; + TooltipType = tooltipType; } } } diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 1f38e2ed6c..5f021803b0 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -297,7 +297,7 @@ namespace osu.Game.Overlays.BeatmapSet }, icon = new DifficultyIcon(beatmapInfo, ruleset) { - ShowTooltip = false, + TooltipType = DifficultyIconTooltipType.None, Current = { Value = new StarDifficulty(beatmapInfo.StarRating, 0) }, Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 44e91c6975..1b8e2d8be6 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -285,7 +285,7 @@ namespace osu.Game.Screens.OnlinePlay difficultyIconContainer.Child = new DifficultyIcon(beatmap, ruleset, requiredMods) { Size = new Vector2(icon_height), - ShowExtendedTooltip = true + TooltipType = DifficultyIconTooltipType.Extended, }; } else diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index baf0a14062..01e58d4ab2 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -122,7 +122,7 @@ namespace osu.Game.Screens.Select.Carousel { difficultyIcon = new DifficultyIcon(beatmapInfo) { - ShowTooltip = false, + TooltipType = DifficultyIconTooltipType.None, Scale = new Vector2(1.8f), }, new FillFlowContainer From 37400643605426647eb80097401002828ff0d7ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 11:59:55 +0100 Subject: [PATCH 222/223] Fix test scene not properly setting tooltip type on all icons --- .../Visual/Beatmaps/TestSceneDifficultyIcon.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs index 6a226c2b8c..fb6bebe50d 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultyIcon.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; @@ -14,13 +15,13 @@ namespace osu.Game.Tests.Visual.Beatmaps { public partial class TestSceneDifficultyIcon : OsuTestScene { - private FillFlowContainer fill = null!; + private FillFlowContainer fill = null!; protected override void LoadComplete() { base.LoadComplete(); - Child = fill = new FillFlowContainer + Child = fill = new FillFlowContainer { AutoSizeAxes = Axes.Y, Width = 300, @@ -33,8 +34,6 @@ namespace osu.Game.Tests.Visual.Beatmaps [Test] public void CreateDifficultyIcon() { - DifficultyIcon difficultyIcon = null!; - AddRepeatStep("create difficulty icon", () => { var rulesetInfo = new OsuRuleset().RulesetInfo; @@ -47,15 +46,15 @@ namespace osu.Game.Tests.Visual.Beatmaps beatmapInfo.StarRating = RNG.NextSingle(0, 10); beatmapInfo.BPM = RNG.Next(60, 300); - fill.Add(difficultyIcon = new DifficultyIcon(beatmapInfo, rulesetInfo) + fill.Add(new DifficultyIcon(beatmapInfo, rulesetInfo) { Scale = new Vector2(2), }); }, 10); - AddStep("no tooltip", () => difficultyIcon.TooltipType = DifficultyIconTooltipType.None); - AddStep("basic tooltip", () => difficultyIcon.TooltipType = DifficultyIconTooltipType.StarRating); - AddStep("extended tooltip", () => difficultyIcon.TooltipType = DifficultyIconTooltipType.Extended); + AddStep("no tooltip", () => fill.ForEach(icon => icon.TooltipType = DifficultyIconTooltipType.None)); + AddStep("basic tooltip", () => fill.ForEach(icon => icon.TooltipType = DifficultyIconTooltipType.StarRating)); + AddStep("extended tooltip", () => fill.ForEach(icon => icon.TooltipType = DifficultyIconTooltipType.Extended)); } } } From 7861125e7ac1dcd48c06f5ab005870b5c111c31c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Feb 2024 12:11:49 +0100 Subject: [PATCH 223/223] Swap AR and OD on tooltips Matches everything else. --- osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 952f71332f..1f3dcfee8c 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -78,8 +78,8 @@ namespace osu.Game.Beatmaps.Drawables { circleSize = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, drainRate = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, + overallDifficulty = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, approachRate = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) }, - overallDifficulty = new OsuSpriteText { Font = OsuFont.GetFont(size: 14) } } }, miscFillFlowContainer = new FillFlowContainer