Fix BeatmapSetOverlay not displaying Fails/Retries/Ratings (#5016)

Fix BeatmapSetOverlay not displaying Fails/Retries/Ratings

Co-authored-by: Dean Herbert <pe@ppy.sh>
This commit is contained in:
Dean Herbert 2019-06-15 18:46:01 +09:00 committed by GitHub
commit 6fc5aa73b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 388 additions and 174 deletions

View File

@ -41,6 +41,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(SuccessRate), typeof(SuccessRate),
}; };
private RulesetInfo maniaRuleset;
private RulesetInfo taikoRuleset;
public TestSceneBeatmapSetOverlay() public TestSceneBeatmapSetOverlay()
{ {
Add(overlay = new BeatmapSetOverlay()); Add(overlay = new BeatmapSetOverlay());
@ -49,13 +52,25 @@ namespace osu.Game.Tests.Visual.Online
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(RulesetStore rulesets) private void load(RulesetStore rulesets)
{ {
var mania = rulesets.GetRuleset(3); maniaRuleset = rulesets.GetRuleset(3);
var taiko = rulesets.GetRuleset(1); taikoRuleset = rulesets.GetRuleset(1);
}
[Test]
public void TestLoading()
{
AddStep(@"show loading", () => overlay.ShowBeatmapSet(null)); AddStep(@"show loading", () => overlay.ShowBeatmapSet(null));
}
[Test]
public void TestOnline()
{
AddStep(@"show online", () => overlay.FetchAndShowBeatmapSet(55)); AddStep(@"show online", () => overlay.FetchAndShowBeatmapSet(55));
}
[Test]
public void TestLocalBeatmaps()
{
AddStep(@"show first", () => AddStep(@"show first", () =>
{ {
overlay.ShowBeatmapSet(new BeatmapSetInfo overlay.ShowBeatmapSet(new BeatmapSetInfo
@ -87,13 +102,14 @@ namespace osu.Game.Tests.Visual.Online
Cover = @"https://assets.ppy.sh/beatmaps/415886/covers/cover.jpg?1465651778", Cover = @"https://assets.ppy.sh/beatmaps/415886/covers/cover.jpg?1465651778",
}, },
}, },
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
Beatmaps = new List<BeatmapInfo> Beatmaps = new List<BeatmapInfo>
{ {
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 1.36, StarDifficulty = 1.36,
Version = @"BASIC", Version = @"BASIC",
Ruleset = mania, Ruleset = maniaRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 4, CircleSize = 4,
@ -111,16 +127,15 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 2.22, StarDifficulty = 2.22,
Version = @"NOVICE", Version = @"NOVICE",
Ruleset = mania, Ruleset = maniaRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 4, CircleSize = 4,
@ -138,16 +153,15 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 3.49, StarDifficulty = 3.49,
Version = @"ADVANCED", Version = @"ADVANCED",
Ruleset = mania, Ruleset = maniaRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 4, CircleSize = 4,
@ -165,16 +179,15 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 4.24, StarDifficulty = 4.24,
Version = @"EXHAUST", Version = @"EXHAUST",
Ruleset = mania, Ruleset = maniaRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 4, CircleSize = 4,
@ -192,16 +205,15 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 5.26, StarDifficulty = 5.26,
Version = @"GRAVITY", Version = @"GRAVITY",
Ruleset = mania, Ruleset = maniaRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 4, CircleSize = 4,
@ -219,9 +231,8 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
}, },
@ -258,13 +269,14 @@ namespace osu.Game.Tests.Visual.Online
Cover = @"https://assets.ppy.sh/beatmaps/625493/covers/cover.jpg?1499167472", Cover = @"https://assets.ppy.sh/beatmaps/625493/covers/cover.jpg?1499167472",
}, },
}, },
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
Beatmaps = new List<BeatmapInfo> Beatmaps = new List<BeatmapInfo>
{ {
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 1.40, StarDifficulty = 1.40,
Version = @"yzrin's Kantan", Version = @"yzrin's Kantan",
Ruleset = taiko, Ruleset = taikoRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 2, CircleSize = 2,
@ -282,16 +294,15 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 2.23, StarDifficulty = 2.23,
Version = @"Futsuu", Version = @"Futsuu",
Ruleset = taiko, Ruleset = taikoRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 2, CircleSize = 2,
@ -309,16 +320,15 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 3.19, StarDifficulty = 3.19,
Version = @"Muzukashii", Version = @"Muzukashii",
Ruleset = taiko, Ruleset = taikoRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 2, CircleSize = 2,
@ -336,16 +346,15 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 3.97, StarDifficulty = 3.97,
Version = @"Charlotte's Oni", Version = @"Charlotte's Oni",
Ruleset = taiko, Ruleset = taikoRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 5, CircleSize = 5,
@ -363,16 +372,15 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
new BeatmapInfo new BeatmapInfo
{ {
StarDifficulty = 5.08, StarDifficulty = 5.08,
Version = @"Labyrinth Oni", Version = @"Labyrinth Oni",
Ruleset = taiko, Ruleset = taikoRuleset,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
CircleSize = 5, CircleSize = 5,
@ -390,16 +398,24 @@ namespace osu.Game.Tests.Visual.Online
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}, },
}, },
}); });
}); });
}
[Test]
public void TestHide()
{
AddStep(@"hide", overlay.Hide); AddStep(@"hide", overlay.Hide);
}
[Test]
public void TestShowWithNoReload()
{
AddStep(@"show without reload", overlay.Show); AddStep(@"show without reload", overlay.Show);
} }
} }

View File

@ -0,0 +1,69 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Screens.Select.Details;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneBeatmapSetOverlayDetails : OsuTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(Details)
};
private RatingsExposingDetails details;
[SetUp]
public void Setup() => Schedule(() =>
{
Child = details = new RatingsExposingDetails
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre
};
});
[Test]
public void TestMetrics()
{
var firstSet = createSet();
var secondSet = createSet();
AddStep("set first set", () => details.BeatmapSet = firstSet);
AddAssert("ratings set", () => details.Ratings.Metrics == firstSet.Metrics);
AddStep("set second set", () => details.BeatmapSet = secondSet);
AddAssert("ratings set", () => details.Ratings.Metrics == secondSet.Metrics);
BeatmapSetInfo createSet() => new BeatmapSetInfo
{
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).Select(_ => RNG.Next(10)).ToArray() },
Beatmaps = new List<BeatmapInfo>
{
new BeatmapInfo
{
Metrics = new BeatmapMetrics
{
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
}
}
}
};
}
private class RatingsExposingDetails : Details
{
public new UserRatings Ratings => base.Ratings;
}
}
}

View File

@ -0,0 +1,82 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Screens.Select.Details;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneBeatmapSetOverlaySuccessRate : OsuTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(Details)
};
private GraphExposingSuccessRate successRate;
[SetUp]
public void Setup() => Schedule(() =>
{
Child = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(275, 220),
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Gray,
},
successRate = new GraphExposingSuccessRate
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(275, 220),
Padding = new MarginPadding(20)
}
}
};
});
[Test]
public void TestMetrics()
{
var firstBeatmap = createBeatmap();
var secondBeatmap = createBeatmap();
AddStep("set first set", () => successRate.Beatmap = firstBeatmap);
AddAssert("ratings set", () => successRate.Graph.Metrics == firstBeatmap.Metrics);
AddStep("set second set", () => successRate.Beatmap = secondBeatmap);
AddAssert("ratings set", () => successRate.Graph.Metrics == secondBeatmap.Metrics);
BeatmapInfo createBeatmap() => new BeatmapInfo
{
Metrics = new BeatmapMetrics
{
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
}
};
}
private class GraphExposingSuccessRate : SuccessRate
{
public new FailRetryGraph Graph => base.Graph;
}
}
}

View File

@ -32,6 +32,10 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null) AddStep("all metrics", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{ {
BeatmapSetInfo =
{
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
},
BeatmapInfo = BeatmapInfo =
{ {
Version = "All Metrics", Version = "All Metrics",
@ -50,9 +54,8 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 5.3f, StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
} }
} }
@ -60,6 +63,10 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("all except source", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null) AddStep("all except source", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{ {
BeatmapSetInfo =
{
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
},
BeatmapInfo = BeatmapInfo =
{ {
Version = "All Metrics", Version = "All Metrics",
@ -77,15 +84,18 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 5.3f, StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
} }
}); });
AddStep("ratings", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null) AddStep("ratings", () => detailsArea.Beatmap = new DummyWorkingBeatmap(null, null)
{ {
BeatmapSetInfo =
{
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
},
BeatmapInfo = BeatmapInfo =
{ {
Version = "Only Ratings", Version = "Only Ratings",
@ -101,11 +111,7 @@ namespace osu.Game.Tests.Visual.SongSelect
OverallDifficulty = 6, OverallDifficulty = 6,
ApproachRate = 6, ApproachRate = 6,
}, },
StarDifficulty = 4.8f, StarDifficulty = 4.8f
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 11),
},
} }
}); });
@ -129,8 +135,8 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 2.91f, StarDifficulty = 2.91f,
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
}, },
} }
}); });

View File

@ -1,28 +1,38 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.ComponentModel;
using System.Linq; using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect namespace osu.Game.Tests.Visual.SongSelect
{ {
[Description("PlaySongSelect beatmap details")] [System.ComponentModel.Description("PlaySongSelect beatmap details")]
public class TestSceneBeatmapDetails : OsuTestScene public class TestSceneBeatmapDetails : OsuTestScene
{ {
public TestSceneBeatmapDetails() private BeatmapDetails details;
[SetUp]
public void Setup() => Schedule(() =>
{ {
BeatmapDetails details; Child = details = new BeatmapDetails
Add(details = new BeatmapDetails
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(150), Padding = new MarginPadding(150),
}); };
});
[Test]
public void TestAllMetrics()
{
AddStep("all metrics", () => details.Beatmap = new BeatmapInfo AddStep("all metrics", () => details.Beatmap = new BeatmapInfo
{ {
BeatmapSet = new BeatmapSetInfo
{
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
},
Version = "All Metrics", Version = "All Metrics",
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
@ -39,14 +49,21 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 5.3f, StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}); });
}
[Test]
public void TestAllMetricsExceptSource()
{
AddStep("all except source", () => details.Beatmap = new BeatmapInfo AddStep("all except source", () => details.Beatmap = new BeatmapInfo
{ {
BeatmapSet = new BeatmapSetInfo
{
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
},
Version = "All Metrics", Version = "All Metrics",
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
@ -62,14 +79,21 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 5.3f, StarDifficulty = 5.3f,
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}); });
}
[Test]
public void TestOnlyRatings()
{
AddStep("ratings", () => details.Beatmap = new BeatmapInfo AddStep("ratings", () => details.Beatmap = new BeatmapInfo
{ {
BeatmapSet = new BeatmapSetInfo
{
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() }
},
Version = "Only Ratings", Version = "Only Ratings",
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
@ -84,12 +108,12 @@ namespace osu.Game.Tests.Visual.SongSelect
ApproachRate = 6, ApproachRate = 6,
}, },
StarDifficulty = 4.8f, StarDifficulty = 4.8f,
Metrics = new BeatmapMetrics
{
Ratings = Enumerable.Range(0, 11),
},
}); });
}
[Test]
public void TestOnlyFailsAndRetries()
{
AddStep("fails retries", () => details.Beatmap = new BeatmapInfo AddStep("fails retries", () => details.Beatmap = new BeatmapInfo
{ {
Version = "Only Retries and Fails", Version = "Only Retries and Fails",
@ -108,11 +132,15 @@ namespace osu.Game.Tests.Visual.SongSelect
StarDifficulty = 2.91f, StarDifficulty = 2.91f,
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
}, },
}); });
}
[Test]
public void TestNoMetrics()
{
AddStep("no metrics", () => details.Beatmap = new BeatmapInfo AddStep("no metrics", () => details.Beatmap = new BeatmapInfo
{ {
Version = "No Metrics", Version = "No Metrics",
@ -129,10 +157,22 @@ namespace osu.Game.Tests.Visual.SongSelect
ApproachRate = 6.5f, ApproachRate = 6.5f,
}, },
StarDifficulty = 1.97f, StarDifficulty = 1.97f,
Metrics = new BeatmapMetrics(),
}); });
}
[Test]
public void TestNullBeatmap()
{
AddStep("null beatmap", () => details.Beatmap = null); AddStep("null beatmap", () => details.Beatmap = null);
} }
[Test]
public void TestOnlineMetrics()
{
AddStep("online ratings/retries/fails", () => details.Beatmap = new BeatmapInfo
{
OnlineBeatmapID = 162,
});
}
} }
} }

View File

@ -270,9 +270,8 @@ namespace osu.Game.Tests.Visual.SongSelect
}, },
Metrics = new BeatmapMetrics Metrics = new BeatmapMetrics
{ {
Ratings = Enumerable.Range(0, 11), Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6).ToArray(),
Fails = Enumerable.Range(1, 100).Select(i => i % 12 - 6), Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(i => i % 12 - 6),
}, },
}; };
} }

View File

@ -1,31 +1,26 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic; using System;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
/// <summary> /// <summary>
/// Beatmap metrics based on acculumated online data from community plays. /// Beatmap metrics based on accumulated online data from community plays.
/// </summary> /// </summary>
public class BeatmapMetrics public class BeatmapMetrics
{ {
/// <summary>
/// Total vote counts of user ratings on a scale of 0..10 where 0 is unused (probably will be fixed at API?).
/// </summary>
public IEnumerable<int> Ratings { get; set; }
/// <summary> /// <summary>
/// Points of failure on a relative time scale (usually 0..100). /// Points of failure on a relative time scale (usually 0..100).
/// </summary> /// </summary>
[JsonProperty(@"fail")] [JsonProperty(@"fail")]
public IEnumerable<int> Fails { get; set; } public int[] Fails { get; set; } = Array.Empty<int>();
/// <summary> /// <summary>
/// Points of retry on a relative time scale (usually 0..100). /// Points of retry on a relative time scale (usually 0..100).
/// </summary> /// </summary>
[JsonProperty(@"exit")] [JsonProperty(@"exit")]
public IEnumerable<int> Retries { get; set; } public int[] Retries { get; set; } = Array.Empty<int>();
} }
} }

View File

@ -32,6 +32,9 @@ namespace osu.Game.Beatmaps
[NotMapped] [NotMapped]
public BeatmapSetOnlineInfo OnlineInfo { get; set; } public BeatmapSetOnlineInfo OnlineInfo { get; set; }
[NotMapped]
public BeatmapSetMetrics Metrics { get; set; }
public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarDifficulty) ?? 0; public double MaxStarDifficulty => Beatmaps?.Max(b => b.StarDifficulty) ?? 0;
[NotMapped] [NotMapped]

View File

@ -0,0 +1,17 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using Newtonsoft.Json;
namespace osu.Game.Beatmaps
{
public class BeatmapSetMetrics
{
/// <summary>
/// Total vote counts of user ratings on a scale of 0..10 where 0 is unused (probably will be fixed at API?).
/// </summary>
[JsonProperty("ratings")]
public int[] Ratings { get; set; } = Array.Empty<int>();
}
}

View File

@ -1,20 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class GetBeatmapDetailsRequest : APIRequest<APIBeatmapMetrics>
{
private readonly BeatmapInfo beatmap;
public GetBeatmapDetailsRequest(BeatmapInfo beatmap)
{
this.beatmap = beatmap;
}
protected override string Target => $@"beatmaps/{beatmap.OnlineBeatmapID}";
}
}

View File

@ -57,6 +57,9 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"version")] [JsonProperty(@"version")]
private string version { get; set; } private string version { get; set; }
[JsonProperty(@"failtimes")]
private BeatmapMetrics metrics { get; set; }
public BeatmapInfo ToBeatmap(RulesetStore rulesets) public BeatmapInfo ToBeatmap(RulesetStore rulesets)
{ {
var set = BeatmapSet?.ToBeatmapSet(rulesets); var set = BeatmapSet?.ToBeatmapSet(rulesets);
@ -70,6 +73,7 @@ namespace osu.Game.Online.API.Requests.Responses
Version = version, Version = version,
Status = Status, Status = Status,
BeatmapSet = set, BeatmapSet = set,
Metrics = metrics,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {
DrainRate = drainRate, DrainRate = drainRate,

View File

@ -1,29 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using Newtonsoft.Json;
using osu.Game.Beatmaps;
namespace osu.Game.Online.API.Requests.Responses
{
public class APIBeatmapMetrics : BeatmapMetrics
{
//the online API returns some metrics as a nested object.
[JsonProperty(@"failtimes")]
private BeatmapMetrics failTimes
{
set
{
Fails = value.Fails;
Retries = value.Retries;
}
}
//and other metrics in the beatmap set.
[JsonProperty(@"beatmapset")]
private BeatmapMetrics beatmapSet
{
set => Ratings = value.Ratings;
}
}
}

View File

@ -54,6 +54,9 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"last_updated")] [JsonProperty(@"last_updated")]
private DateTimeOffset lastUpdated { get; set; } private DateTimeOffset lastUpdated { get; set; }
[JsonProperty(@"ratings")]
private int[] ratings { get; set; }
[JsonProperty(@"user_id")] [JsonProperty(@"user_id")]
private long creatorId private long creatorId
{ {
@ -70,6 +73,7 @@ namespace osu.Game.Online.API.Requests.Responses
OnlineBeatmapSetID = OnlineBeatmapSetID, OnlineBeatmapSetID = OnlineBeatmapSetID,
Metadata = this, Metadata = this,
Status = Status, Status = Status,
Metrics = ratings == null ? null : new BeatmapSetMetrics { Ratings = ratings },
OnlineInfo = new BeatmapSetOnlineInfo OnlineInfo = new BeatmapSetOnlineInfo
{ {
Covers = covers, Covers = covers,

View File

@ -50,7 +50,7 @@ namespace osu.Game.Overlays.BeatmapSet
private void updateDisplay() private void updateDisplay()
{ {
bpm.Value = BeatmapSet?.OnlineInfo.BPM.ToString(@"0.##") ?? "-"; bpm.Value = BeatmapSet?.OnlineInfo?.BPM.ToString(@"0.##") ?? "-";
if (beatmap == null) if (beatmap == null)
{ {

View File

@ -16,10 +16,11 @@ namespace osu.Game.Overlays.BeatmapSet
{ {
public class Details : FillFlowContainer public class Details : FillFlowContainer
{ {
protected readonly UserRatings Ratings;
private readonly PreviewButton preview; private readonly PreviewButton preview;
private readonly BasicStats basic; private readonly BasicStats basic;
private readonly AdvancedStats advanced; private readonly AdvancedStats advanced;
private readonly UserRatings ratings;
private BeatmapSetInfo beatmapSet; private BeatmapSetInfo beatmapSet;
@ -33,6 +34,7 @@ namespace osu.Game.Overlays.BeatmapSet
beatmapSet = value; beatmapSet = value;
basic.BeatmapSet = preview.BeatmapSet = BeatmapSet; basic.BeatmapSet = preview.BeatmapSet = BeatmapSet;
updateDisplay();
} }
} }
@ -46,13 +48,12 @@ namespace osu.Game.Overlays.BeatmapSet
if (value == beatmap) return; if (value == beatmap) return;
basic.Beatmap = advanced.Beatmap = beatmap = value; basic.Beatmap = advanced.Beatmap = beatmap = value;
updateDisplay();
} }
} }
private void updateDisplay() private void updateDisplay()
{ {
ratings.Metrics = Beatmap?.Metrics; Ratings.Metrics = BeatmapSet?.Metrics;
} }
public Details() public Details()
@ -87,7 +88,7 @@ namespace osu.Game.Overlays.BeatmapSet
}, },
new DetailBox new DetailBox
{ {
Child = ratings = new UserRatings Child = Ratings = new UserRatings
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = 95, Height = 95,

View File

@ -14,11 +14,12 @@ namespace osu.Game.Overlays.BeatmapSet
{ {
public class SuccessRate : Container public class SuccessRate : Container
{ {
protected readonly FailRetryGraph Graph;
private readonly FillFlowContainer header; private readonly FillFlowContainer header;
private readonly OsuSpriteText successRateLabel, successPercent, graphLabel; private readonly OsuSpriteText successRateLabel, successPercent, graphLabel;
private readonly Bar successRate; private readonly Bar successRate;
private readonly Container percentContainer; private readonly Container percentContainer;
private readonly FailRetryGraph graph;
private BeatmapInfo beatmap; private BeatmapInfo beatmap;
@ -37,15 +38,15 @@ namespace osu.Game.Overlays.BeatmapSet
private void updateDisplay() private void updateDisplay()
{ {
int passCount = beatmap?.OnlineInfo.PassCount ?? 0; int passCount = beatmap?.OnlineInfo?.PassCount ?? 0;
int playCount = beatmap?.OnlineInfo.PlayCount ?? 0; int playCount = beatmap?.OnlineInfo?.PlayCount ?? 0;
var rate = playCount != 0 ? (float)passCount / playCount : 0; var rate = playCount != 0 ? (float)passCount / playCount : 0;
successPercent.Text = rate.ToString("P0"); successPercent.Text = rate.ToString("P0");
successRate.Length = rate; successRate.Length = rate;
percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic);
graph.Metrics = beatmap?.Metrics; Graph.Metrics = beatmap?.Metrics;
} }
public SuccessRate() public SuccessRate()
@ -94,7 +95,7 @@ namespace osu.Game.Overlays.BeatmapSet
}, },
}, },
}, },
graph = new FailRetryGraph Graph = new FailRetryGraph
{ {
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
@ -117,7 +118,7 @@ namespace osu.Game.Overlays.BeatmapSet
{ {
base.UpdateAfterChildren(); base.UpdateAfterChildren();
graph.Padding = new MarginPadding { Top = header.DrawHeight }; Graph.Padding = new MarginPadding { Top = header.DrawHeight };
} }
} }
} }

View File

@ -10,7 +10,6 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using System.Linq; using System.Linq;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
@ -18,6 +17,8 @@ using osu.Game.Screens.Select.Details;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
namespace osu.Game.Screens.Select namespace osu.Game.Screens.Select
{ {
@ -40,6 +41,9 @@ namespace osu.Game.Screens.Select
private ScheduledDelegate pendingBeatmapSwitch; private ScheduledDelegate pendingBeatmapSwitch;
[Resolved]
private RulesetStore rulesets { get; set; }
private BeatmapInfo beatmap; private BeatmapInfo beatmap;
public BeatmapInfo Beatmap public BeatmapInfo Beatmap
@ -181,57 +185,79 @@ namespace osu.Game.Screens.Select
tags.Text = Beatmap?.Metadata?.Tags; tags.Text = Beatmap?.Metadata?.Tags;
// metrics may have been previously fetched // metrics may have been previously fetched
if (Beatmap?.Metrics != null) if (Beatmap?.BeatmapSet?.Metrics != null && Beatmap?.Metrics != null)
{ {
updateMetrics(Beatmap.Metrics); updateMetrics();
return; return;
} }
// metrics may not be fetched but can be // for now, let's early abort if an OnlineBeatmapID is not present (should have been populated at import time).
if (Beatmap?.OnlineBeatmapID != null) if (Beatmap?.OnlineBeatmapID == null)
{ {
var requestedBeatmap = Beatmap; updateMetrics();
var lookup = new GetBeatmapDetailsRequest(requestedBeatmap); return;
lookup.Success += res => }
var requestedBeatmap = Beatmap;
var lookup = new GetBeatmapRequest(requestedBeatmap);
lookup.Success += res =>
{
Schedule(() =>
{ {
if (beatmap != requestedBeatmap) if (beatmap != requestedBeatmap)
//the beatmap has been changed since we started the lookup. //the beatmap has been changed since we started the lookup.
return; return;
requestedBeatmap.Metrics = res; var b = res.ToBeatmap(rulesets);
Schedule(() => updateMetrics(res));
};
lookup.Failure += e => Schedule(() => updateMetrics());
api.Queue(lookup);
loading.Show();
return;
}
updateMetrics(); if (requestedBeatmap.BeatmapSet == null)
requestedBeatmap.BeatmapSet = b.BeatmapSet;
else
requestedBeatmap.BeatmapSet.Metrics = b.BeatmapSet.Metrics;
requestedBeatmap.Metrics = b.Metrics;
updateMetrics();
});
};
lookup.Failure += e =>
{
Schedule(() =>
{
if (beatmap != requestedBeatmap)
//the beatmap has been changed since we started the lookup.
return;
updateMetrics();
});
};
api.Queue(lookup);
loading.Show();
} }
private void updateMetrics(BeatmapMetrics metrics = null) private void updateMetrics()
{ {
var hasRatings = metrics?.Ratings?.Any() ?? false; var hasRatings = beatmap?.BeatmapSet?.Metrics?.Ratings?.Any() ?? false;
var hasRetriesFails = (metrics?.Retries?.Any() ?? false) && (metrics.Fails?.Any() ?? false); var hasRetriesFails = (beatmap?.Metrics?.Retries?.Any() ?? false) && (beatmap?.Metrics.Fails?.Any() ?? false);
if (hasRatings) if (hasRatings)
{ {
ratings.Metrics = metrics; ratings.Metrics = beatmap.BeatmapSet.Metrics;
ratingsContainer.FadeIn(transition_duration); ratingsContainer.FadeIn(transition_duration);
} }
else else
{ {
ratings.Metrics = new BeatmapMetrics ratings.Metrics = new BeatmapSetMetrics { Ratings = new int[10] };
{
Ratings = new int[10],
};
ratingsContainer.FadeTo(0.25f, transition_duration); ratingsContainer.FadeTo(0.25f, transition_duration);
} }
if (hasRetriesFails) if (hasRetriesFails)
{ {
failRetryGraph.Metrics = metrics; failRetryGraph.Metrics = beatmap.Metrics;
failRetryContainer.FadeIn(transition_duration); failRetryContainer.FadeIn(transition_duration);
} }
else else

View File

@ -20,9 +20,9 @@ namespace osu.Game.Screens.Select.Details
private readonly Container graphContainer; private readonly Container graphContainer;
private readonly BarGraph graph; private readonly BarGraph graph;
private BeatmapMetrics metrics; private BeatmapSetMetrics metrics;
public BeatmapMetrics Metrics public BeatmapSetMetrics Metrics
{ {
get => metrics; get => metrics;
set set