mirror of
https://github.com/ppy/osu.git
synced 2024-12-17 03:02:56 +08:00
Merge pull request #30245 from 424ever/group-slider-ends
Group `HitResult`s with the same name into one column in beatmap ranking
This commit is contained in:
commit
8ed0554b91
@ -8,11 +8,13 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Overlays;
|
||||
@ -90,6 +92,48 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddAssert("no best score displayed", () => scoresContainer.ChildrenOfType<DrawableTopScore>().Count() == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHitResultsWithSameNameAreGrouped()
|
||||
{
|
||||
AddStep("Load scores without user best", () =>
|
||||
{
|
||||
var allScores = createScores();
|
||||
allScores.UserScore = null;
|
||||
scoresContainer.Scores = allScores;
|
||||
});
|
||||
|
||||
AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType<ScoreTableRowBackground>().Any());
|
||||
AddAssert("only one column for slider end", () =>
|
||||
{
|
||||
ScoreTable scoreTable = scoresContainer.ChildrenOfType<ScoreTable>().First();
|
||||
return scoreTable.Columns.Count(c => c.Header.Equals("slider end")) == 1;
|
||||
});
|
||||
|
||||
AddAssert("all rows show non-zero slider ends", () =>
|
||||
{
|
||||
ScoreTable scoreTable = scoresContainer.ChildrenOfType<ScoreTable>().First();
|
||||
int sliderEndColumnIndex = Array.FindIndex(scoreTable.Columns, c => c != null && c.Header.Equals("slider end"));
|
||||
bool sliderEndFilledInEachRow = true;
|
||||
|
||||
for (int i = 0; i < scoreTable.Content?.GetLength(0); i++)
|
||||
{
|
||||
switch (scoreTable.Content[i, sliderEndColumnIndex])
|
||||
{
|
||||
case OsuSpriteText text:
|
||||
if (text.Text.Equals(0.0d.ToLocalisableString(@"N0")))
|
||||
sliderEndFilledInEachRow = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
sliderEndFilledInEachRow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sliderEndFilledInEachRow;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUserBest()
|
||||
{
|
||||
@ -287,13 +331,17 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
const int initial_great_count = 2000;
|
||||
const int initial_tick_count = 100;
|
||||
const int initial_slider_end_count = 500;
|
||||
|
||||
int greatCount = initial_great_count;
|
||||
int tickCount = initial_tick_count;
|
||||
int sliderEndCount = initial_slider_end_count;
|
||||
|
||||
foreach (var s in scores.Scores)
|
||||
foreach (var (score, index) in scores.Scores.Select((s, i) => (s, i)))
|
||||
{
|
||||
s.Statistics = new Dictionary<HitResult, int>
|
||||
HitResult sliderEndResult = index % 2 == 0 ? HitResult.SliderTailHit : HitResult.SmallTickHit;
|
||||
|
||||
score.Statistics = new Dictionary<HitResult, int>
|
||||
{
|
||||
{ HitResult.Great, greatCount },
|
||||
{ HitResult.LargeTickHit, tickCount },
|
||||
@ -301,10 +349,19 @@ namespace osu.Game.Tests.Visual.Online
|
||||
{ HitResult.Meh, RNG.Next(100) },
|
||||
{ HitResult.Miss, initial_great_count - greatCount },
|
||||
{ HitResult.LargeTickMiss, initial_tick_count - tickCount },
|
||||
{ sliderEndResult, sliderEndCount },
|
||||
};
|
||||
|
||||
// Some hit results, including SliderTailHit and SmallTickHit, are only displayed
|
||||
// when the maximum number is known
|
||||
score.MaximumStatistics = new Dictionary<HitResult, int>
|
||||
{
|
||||
{ sliderEndResult, initial_slider_end_count },
|
||||
};
|
||||
|
||||
greatCount -= 100;
|
||||
tickCount -= RNG.Next(1, 5);
|
||||
sliderEndCount -= 20;
|
||||
}
|
||||
|
||||
return scores;
|
||||
|
@ -9,7 +9,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
@ -58,9 +57,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The statistics that appear in the table, in order of appearance.
|
||||
/// The names of the statistics that appear in the table. If multiple HitResults have the same
|
||||
/// DisplayName (for example, "slider end" is the name for both <see cref="HitResult.SliderTailHit"/> and <see cref="HitResult.SmallTickHit"/>
|
||||
/// in osu!) the name will only be listed once.
|
||||
/// </summary>
|
||||
private readonly List<(HitResult result, LocalisableString displayName)> statisticResultTypes = new List<(HitResult, LocalisableString)>();
|
||||
private readonly List<LocalisableString> statisticResultNames = new List<LocalisableString>();
|
||||
|
||||
private bool showPerformancePoints;
|
||||
|
||||
@ -72,7 +73,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
return;
|
||||
|
||||
showPerformancePoints = showPerformanceColumn;
|
||||
statisticResultTypes.Clear();
|
||||
statisticResultNames.Clear();
|
||||
|
||||
for (int i = 0; i < scores.Count; i++)
|
||||
backgroundFlow.Add(new ScoreTableRowBackground(i, scores[i], row_height));
|
||||
@ -105,20 +106,18 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
|
||||
var ruleset = scores.First().Ruleset.CreateInstance();
|
||||
|
||||
foreach (var result in EnumExtensions.GetValuesInOrder<HitResult>())
|
||||
foreach (var resultGroup in ruleset.GetHitResults().GroupBy(r => r.displayName))
|
||||
{
|
||||
if (!allScoreStatistics.Contains(result))
|
||||
if (!resultGroup.Any(r => allScoreStatistics.Contains(r.result)))
|
||||
continue;
|
||||
|
||||
// for the time being ignore bonus result types.
|
||||
// this is not being sent from the API and will be empty in all cases.
|
||||
if (result.IsBonus())
|
||||
if (resultGroup.All(r => r.result.IsBonus()))
|
||||
continue;
|
||||
|
||||
var displayName = ruleset.GetDisplayNameForHitResult(result);
|
||||
|
||||
columns.Add(new TableColumn(displayName, Anchor.CentreLeft, new Dimension(minSize: 35, maxSize: 60)));
|
||||
statisticResultTypes.Add((result, displayName));
|
||||
columns.Add(new TableColumn(resultGroup.Key, Anchor.CentreLeft, new Dimension(minSize: 35, maxSize: 60)));
|
||||
statisticResultNames.Add(resultGroup.Key);
|
||||
}
|
||||
|
||||
if (showPerformancePoints)
|
||||
@ -167,14 +166,25 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
||||
#pragma warning restore 618
|
||||
};
|
||||
|
||||
var availableStatistics = score.GetStatisticsForDisplay().ToDictionary(tuple => tuple.Result);
|
||||
var availableStatistics = score.GetStatisticsForDisplay().ToLookup(tuple => tuple.DisplayName);
|
||||
|
||||
foreach (var result in statisticResultTypes)
|
||||
foreach (var columnName in statisticResultNames)
|
||||
{
|
||||
if (!availableStatistics.TryGetValue(result.result, out var stat))
|
||||
stat = new HitResultDisplayStatistic(result.result, 0, null, result.displayName);
|
||||
int count = 0;
|
||||
int? maxCount = null;
|
||||
|
||||
content.Add(new StatisticText(stat.Count, stat.MaxCount, @"N0") { Colour = stat.Count == 0 ? Color4.Gray : Color4.White });
|
||||
if (availableStatistics.Contains(columnName))
|
||||
{
|
||||
maxCount = 0;
|
||||
|
||||
foreach (var s in availableStatistics[columnName])
|
||||
{
|
||||
count += s.Count;
|
||||
maxCount += s.MaxCount;
|
||||
}
|
||||
}
|
||||
|
||||
content.Add(new StatisticText(count, maxCount, @"N0") { Colour = count == 0 ? Color4.Gray : Color4.White });
|
||||
}
|
||||
|
||||
if (showPerformancePoints)
|
||||
|
Loading…
Reference in New Issue
Block a user