From 3b95fbab7db0761dc0177512f311c953c34ab213 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Apr 2017 15:40:10 +0900 Subject: [PATCH 1/8] Add score statistic tracking (osu!). --- .../Tests/TestCaseResults.cs | 7 +- osu.Game.Rulesets.Osu/Scoring/OsuScore.cs | 14 +++- .../Scoring/OsuScoreProcessor.cs | 36 +++++++++++ osu.Game/Database/ScoreDatabase.cs | 2 +- osu.Game/Rulesets/Scoring/Score.cs | 17 +---- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 29 ++++++--- osu.Game/Rulesets/Scoring/ScoreStatistic.cs | 17 +++++ osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Ranking/ResultsPageScore.cs | 64 ++++++++++++++++++- osu.Game/osu.Game.csproj | 1 + 10 files changed, 158 insertions(+), 31 deletions(-) create mode 100644 osu.Game/Rulesets/Scoring/ScoreStatistic.cs diff --git a/osu.Desktop.VisualTests/Tests/TestCaseResults.cs b/osu.Desktop.VisualTests/Tests/TestCaseResults.cs index 93e0646255..e023b54abe 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseResults.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseResults.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; +using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Ranking; using osu.Game.Users; @@ -40,13 +41,17 @@ namespace osu.Desktop.VisualTests.Tests base.Reset(); - Add(new Results(new Score + Add(new Results(new OsuScore { TotalScore = 2845370, Accuracy = 0.98, MaxCombo = 123, Rank = ScoreRank.A, Date = DateTime.Now, + Count300 = 100, + Count100 = 10, + Count50 = 1, + CountMiss = 2, User = new User { Username = "peppy", diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScore.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScore.cs index c73cfe3338..248576b21d 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScore.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScore.cs @@ -1,11 +1,23 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Scoring { - internal class OsuScore : Score + public class OsuScore : Score { + public int Count300; + public int Count100; + public int Count50; + public int CountMiss; + + public override IEnumerable Statistics => new[] { + new ScoreStatistic(@"300", Count300), + new ScoreStatistic(@"100", Count100), + new ScoreStatistic(@"50", Count50), + new ScoreStatistic(@"x", CountMiss), + }; } } diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 0c38f66abe..45253e0793 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -1,9 +1,11 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; @@ -26,12 +28,46 @@ namespace osu.Game.Rulesets.Osu.Scoring Health.Value = 1; Accuracy.Value = 1; + + scoreResultCounts.Clear(); + comboResultCounts.Clear(); + } + + private readonly Dictionary scoreResultCounts = new Dictionary(); + private readonly Dictionary comboResultCounts = new Dictionary(); + + public override Score CreateEmptyScore() => new OsuScore(); + + public override Score GetPopulatedScore() + { + var score = (OsuScore)base.GetPopulatedScore(); + + scoreResultCounts.TryGetValue(OsuScoreResult.Hit300, out score.Count300); + scoreResultCounts.TryGetValue(OsuScoreResult.Hit100, out score.Count100); + scoreResultCounts.TryGetValue(OsuScoreResult.Hit50, out score.Count50); + scoreResultCounts.TryGetValue(OsuScoreResult.Miss, out score.CountMiss); + + return score; } protected override void OnNewJudgement(OsuJudgement judgement) { if (judgement != null) { + if (judgement.Result != HitResult.None) + { + int count; + if (scoreResultCounts.TryGetValue(judgement.Score, out count)) + scoreResultCounts[judgement.Score] = count + 1; + else + scoreResultCounts[judgement.Score] = 0; + + if (comboResultCounts.TryGetValue(judgement.Combo, out count)) + comboResultCounts[judgement.Combo] = count + 1; + else + comboResultCounts[judgement.Combo] = 0; + } + switch (judgement.Result) { case HitResult.Hit: diff --git a/osu.Game/Database/ScoreDatabase.cs b/osu.Game/Database/ScoreDatabase.cs index 359728070f..9dacf26e33 100644 --- a/osu.Game/Database/ScoreDatabase.cs +++ b/osu.Game/Database/ScoreDatabase.cs @@ -43,7 +43,7 @@ namespace osu.Game.Database using (SerializationReader sr = new SerializationReader(s)) { var ruleset = rulesets.GetRuleset(sr.ReadByte()).CreateInstance(); - score = ruleset.CreateScoreProcessor().CreateScore(); + score = ruleset.CreateScoreProcessor().CreateEmptyScore(); /* score.Pass = true;*/ var version = sr.ReadInt32(); diff --git a/osu.Game/Rulesets/Scoring/Score.cs b/osu.Game/Rulesets/Scoring/Score.cs index cb7831b04a..bb72237524 100644 --- a/osu.Game/Rulesets/Scoring/Score.cs +++ b/osu.Game/Rulesets/Scoring/Score.cs @@ -93,21 +93,6 @@ namespace osu.Game.Rulesets.Scoring return new Replay { Frames = frames }; } - // [JsonProperty(@"count50")] 0, - //[JsonProperty(@"count100")] 0, - //[JsonProperty(@"count300")] 100, - //[JsonProperty(@"countmiss")] 0, - //[JsonProperty(@"countkatu")] 0, - //[JsonProperty(@"countgeki")] 31, - //[JsonProperty(@"perfect")] true, - //[JsonProperty(@"enabled_mods")] [ - // "DT", - // "FL", - // "HD", - // "HR" - //], - //[JsonProperty(@"rank")] "XH", - //[JsonProperty(@"pp")] 26.1816, - //[JsonProperty(@"replay")] true + public virtual IEnumerable Statistics => new ScoreStatistic[] { }; } } diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 39008c5889..1fe21c8724 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -65,16 +65,7 @@ namespace osu.Game.Rulesets.Scoring /// Creates a Score applicable to the ruleset in which this ScoreProcessor resides. /// /// The Score. - public virtual Score CreateScore() => new Score - { - TotalScore = TotalScore, - Combo = Combo, - MaxCombo = HighestCombo, - Accuracy = Accuracy, - Rank = rankFrom(Accuracy), - Date = DateTime.Now, - Health = Health, - }; + public virtual Score CreateEmptyScore() => new Score(); private ScoreRank rankFrom(double acc) { @@ -119,6 +110,24 @@ namespace osu.Game.Rulesets.Scoring alreadyFailed = true; Failed?.Invoke(); } + + /// + /// Retrieve a score populated with data for the current play this processor is responsible for. + /// + public virtual Score GetPopulatedScore() + { + var score = CreateEmptyScore(); + + score.TotalScore = TotalScore; + score.Combo = Combo; + score.MaxCombo = HighestCombo; + score.Accuracy = Accuracy; + score.Rank = rankFrom(Accuracy); + score.Date = DateTime.Now; + score.Health = Health; + + return score; + } } public abstract class ScoreProcessor : ScoreProcessor diff --git a/osu.Game/Rulesets/Scoring/ScoreStatistic.cs b/osu.Game/Rulesets/Scoring/ScoreStatistic.cs new file mode 100644 index 0000000000..5d1011e829 --- /dev/null +++ b/osu.Game/Rulesets/Scoring/ScoreStatistic.cs @@ -0,0 +1,17 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Scoring +{ + public class ScoreStatistic + { + public readonly string Name; + public readonly object Value; + + public ScoreStatistic(string name, object value) + { + Name = name; + Value = value; + } + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 52518180d9..8c3f3da58a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -266,7 +266,7 @@ namespace osu.Game.Screens.Play Delay(1000); onCompletionEvent = Schedule(delegate { - var score = scoreProcessor.CreateScore(); + var score = scoreProcessor.GetPopulatedScore(); score.User = HitRenderer.Replay?.User ?? (Game as OsuGame)?.API?.LocalUser?.Value; Push(new Results(score)); }); diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index 0874767f05..0d485121ed 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -23,6 +23,7 @@ using osu.Game.Beatmaps; using osu.Game.Screens.Play; using osu.Game.Rulesets.Scoring; using osu.Framework.Graphics.Colour; +using System.Linq; namespace osu.Game.Screens.Ranking { @@ -32,6 +33,8 @@ namespace osu.Game.Screens.Ranking public ResultsPageScore(Score score, WorkingBeatmap beatmap) : base(score, beatmap) { } + private FillFlowContainer statisticsContainer; + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -148,15 +151,74 @@ namespace osu.Game.Screens.Ranking }, } }, + statisticsContainer = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Direction = FillDirection.Horizontal, + LayoutDuration = 200, + LayoutEasing = EasingTypes.OutQuint + } } } }; + + statisticsContainer.Children = Score.Statistics.Select(s => new DrawableScoreStatistic(s)); } protected override void LoadComplete() { base.LoadComplete(); - Schedule(() => scoreCounter.Increment(Score.TotalScore)); + + Schedule(() => + { + scoreCounter.Increment(Score.TotalScore); + + int delay = 0; + foreach (var s in statisticsContainer.Children) + { + s.FadeOut(); + s.Delay(delay += 200); + s.FadeIn(300 + delay, EasingTypes.Out); + } + }); + } + + private class DrawableScoreStatistic : Container + { + private readonly ScoreStatistic statistic; + + public DrawableScoreStatistic(ScoreStatistic statistic) + { + this.statistic = statistic; + + AutoSizeAxes = Axes.Both; + Margin = new MarginPadding { Left = 5, Right = 5 }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Children = new Drawable[] + { + new SpriteText { + Text = statistic.Value.ToString().PadLeft(4, '0'), + Colour = colours.Gray7, + TextSize = 30, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + new SpriteText { + Text = statistic.Name, + Colour = colours.Gray7, + Font = @"Exo2.0-Bold", + Y = 26, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + }; + } } private class DateDisplay : Container diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fe331c6356..4ee1aa0b32 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -153,6 +153,7 @@ + From efbe471cdafe77cbf47b7b93715339f14f1c31ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Apr 2017 20:28:51 +0900 Subject: [PATCH 2/8] Update framework. --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 21a97586f7..dc4ea5be42 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 21a97586f7fa8d9aa65b4131824151d88a70b520 +Subproject commit dc4ea5be425d37f3a0dd09f6acdf6799d42e3d74 From 3e65cab9b723d7999f515ab1c9595cf1749047cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Apr 2017 10:25:07 +0900 Subject: [PATCH 3/8] Move replay creation logic to ScoreDatabase. --- osu.Game/Database/ScoreDatabase.cs | 34 +++++++++++++++++++++++++++++- osu.Game/Rulesets/Scoring/Score.cs | 30 -------------------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/osu.Game/Database/ScoreDatabase.cs b/osu.Game/Database/ScoreDatabase.cs index 9dacf26e33..2ffe12d50e 100644 --- a/osu.Game/Database/ScoreDatabase.cs +++ b/osu.Game/Database/ScoreDatabase.cs @@ -2,11 +2,13 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.IO; using System.Linq; using osu.Framework.Platform; using osu.Game.IO.Legacy; using osu.Game.IPC; +using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; using SharpCompress.Compressors.LZMA; using SQLite.Net; @@ -104,13 +106,43 @@ namespace osu.Game.Database using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize)) using (var reader = new StreamReader(lzma)) - score.Replay = score.CreateReplay(reader); + score.Replay = createReplay(reader); } } return score; } + /// + /// Creates a replay which is read from a stream. + /// + /// The stream reader. + /// The replay. + private Replay createReplay(StreamReader reader) + { + var frames = new List(); + + float lastTime = 0; + + foreach (var l in reader.ReadToEnd().Split(',')) + { + var split = l.Split('|'); + + if (split.Length < 4 || float.Parse(split[0]) < 0) continue; + + lastTime += float.Parse(split[0]); + + frames.Add(new ReplayFrame( + lastTime, + float.Parse(split[1]), + 384 - float.Parse(split[2]), + (ReplayButtonState)int.Parse(split[3]) + )); + } + + return new Replay { Frames = frames }; + } + protected override void Prepare(bool reset = false) { } diff --git a/osu.Game/Rulesets/Scoring/Score.cs b/osu.Game/Rulesets/Scoring/Score.cs index 5496057304..a87c59606b 100644 --- a/osu.Game/Rulesets/Scoring/Score.cs +++ b/osu.Game/Rulesets/Scoring/Score.cs @@ -49,36 +49,6 @@ namespace osu.Game.Rulesets.Scoring [JsonProperty(@"created_at")] public DateTime Date; - /// - /// Creates a replay which is read from a stream. - /// - /// The stream reader. - /// The replay. - public virtual Replay CreateReplay(StreamReader reader) - { - var frames = new List(); - - float lastTime = 0; - - foreach (var l in reader.ReadToEnd().Split(',')) - { - var split = l.Split('|'); - - if (split.Length < 4 || float.Parse(split[0]) < 0) continue; - - lastTime += float.Parse(split[0]); - - frames.Add(new ReplayFrame( - lastTime, - float.Parse(split[1]), - 384 - float.Parse(split[2]), - (ReplayButtonState)int.Parse(split[3]) - )); - } - - return new Replay { Frames = frames }; - } - public virtual IEnumerable Statistics => new ScoreStatistic[] { }; } } From 6cf026e5c1afe461c5b9d6788e51dd85f6375210 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Apr 2017 11:02:56 +0900 Subject: [PATCH 4/8] Remove OsuScore and change the way statistics are stored (dynamic dictionary). --- osu-framework | 2 +- .../Tests/TestCaseResults.cs | 17 ++++++++------ osu.Game.Rulesets.Osu/Scoring/OsuScore.cs | 23 ------------------- .../Scoring/OsuScoreProcessor.cs | 13 +++++------ .../osu.Game.Rulesets.Osu.csproj | 1 - osu.Game/Rulesets/Scoring/Score.cs | 3 +-- osu.Game/Screens/Ranking/ResultsPageScore.cs | 7 +++--- osu.Game/osu.Game.csproj | 1 + 8 files changed, 23 insertions(+), 44 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Scoring/OsuScore.cs diff --git a/osu-framework b/osu-framework index dc4ea5be42..ccf0ff40d1 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit dc4ea5be425d37f3a0dd09f6acdf6799d42e3d74 +Subproject commit ccf0ff40d1261ad328d0182467a1f0c1a858b099 diff --git a/osu.Desktop.VisualTests/Tests/TestCaseResults.cs b/osu.Desktop.VisualTests/Tests/TestCaseResults.cs index e023b54abe..aa3a117667 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseResults.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseResults.cs @@ -2,12 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Database; -using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Ranking; using osu.Game.Users; @@ -41,17 +41,20 @@ namespace osu.Desktop.VisualTests.Tests base.Reset(); - Add(new Results(new OsuScore + Add(new Results(new Score { TotalScore = 2845370, Accuracy = 0.98, MaxCombo = 123, Rank = ScoreRank.A, Date = DateTime.Now, - Count300 = 100, - Count100 = 10, - Count50 = 1, - CountMiss = 2, + Statistics = new Dictionary() + { + { "300", 50 }, + { "100", 20 }, + { "50", 50 }, + { "x", 1 } + }, User = new User { Username = "peppy", @@ -62,4 +65,4 @@ namespace osu.Desktop.VisualTests.Tests }); } } - } +} diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScore.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScore.cs deleted file mode 100644 index 248576b21d..0000000000 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScore.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using System.Collections.Generic; -using osu.Game.Rulesets.Scoring; - -namespace osu.Game.Rulesets.Osu.Scoring -{ - public class OsuScore : Score - { - public int Count300; - public int Count100; - public int Count50; - public int CountMiss; - - public override IEnumerable Statistics => new[] { - new ScoreStatistic(@"300", Count300), - new ScoreStatistic(@"100", Count100), - new ScoreStatistic(@"50", Count50), - new ScoreStatistic(@"x", CountMiss), - }; - } -} diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 45253e0793..470086bf78 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using osu.Framework.Extensions; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; @@ -36,16 +37,14 @@ namespace osu.Game.Rulesets.Osu.Scoring private readonly Dictionary scoreResultCounts = new Dictionary(); private readonly Dictionary comboResultCounts = new Dictionary(); - public override Score CreateEmptyScore() => new OsuScore(); - public override Score GetPopulatedScore() { - var score = (OsuScore)base.GetPopulatedScore(); + var score = base.GetPopulatedScore(); - scoreResultCounts.TryGetValue(OsuScoreResult.Hit300, out score.Count300); - scoreResultCounts.TryGetValue(OsuScoreResult.Hit100, out score.Count100); - scoreResultCounts.TryGetValue(OsuScoreResult.Hit50, out score.Count50); - scoreResultCounts.TryGetValue(OsuScoreResult.Miss, out score.CountMiss); + score.Statistics[@"300"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit300); + score.Statistics[@"100"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit100); + score.Statistics[@"50"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit50); + score.Statistics[@"x"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Miss); return score; } diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 272a35c286..fcad0061e4 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -72,7 +72,6 @@ - diff --git a/osu.Game/Rulesets/Scoring/Score.cs b/osu.Game/Rulesets/Scoring/Score.cs index a87c59606b..fbbd766a18 100644 --- a/osu.Game/Rulesets/Scoring/Score.cs +++ b/osu.Game/Rulesets/Scoring/Score.cs @@ -7,7 +7,6 @@ using Newtonsoft.Json; using osu.Game.Database; using osu.Game.Rulesets.Mods; using osu.Game.Users; -using System.IO; using osu.Game.Rulesets.Replays; namespace osu.Game.Rulesets.Scoring @@ -49,6 +48,6 @@ namespace osu.Game.Rulesets.Scoring [JsonProperty(@"created_at")] public DateTime Date; - public virtual IEnumerable Statistics => new ScoreStatistic[] { }; + public Dictionary Statistics = new Dictionary(); } } diff --git a/osu.Game/Screens/Ranking/ResultsPageScore.cs b/osu.Game/Screens/Ranking/ResultsPageScore.cs index c6953a88fa..88c9da802e 100644 --- a/osu.Game/Screens/Ranking/ResultsPageScore.cs +++ b/osu.Game/Screens/Ranking/ResultsPageScore.cs @@ -18,6 +18,7 @@ using osu.Game.Users; using OpenTK; using OpenTK.Graphics; using System; +using System.Collections.Generic; using osu.Framework.Extensions.Color4Extensions; using osu.Game.Beatmaps; using osu.Game.Screens.Play; @@ -187,9 +188,9 @@ namespace osu.Game.Screens.Ranking private class DrawableScoreStatistic : Container { - private readonly ScoreStatistic statistic; + private readonly KeyValuePair statistic; - public DrawableScoreStatistic(ScoreStatistic statistic) + public DrawableScoreStatistic(KeyValuePair statistic) { this.statistic = statistic; @@ -210,7 +211,7 @@ namespace osu.Game.Screens.Ranking Origin = Anchor.TopCentre, }, new SpriteText { - Text = statistic.Name, + Text = statistic.Key, Colour = colours.Gray7, Font = @"Exo2.0-Bold", Y = 26, diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fb88dba29c..de6c889f95 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -57,6 +57,7 @@ $(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll True + From a47870b376e59e8d495b5a29067c4a6ef5611526 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Apr 2017 11:16:08 +0900 Subject: [PATCH 5/8] Apply Ruleset to Scores. Reduce complexity of score creation. --- .../Scoring/OsuScoreProcessor.cs | 6 ++--- osu.Game/Database/ScoreDatabase.cs | 2 +- osu.Game/Rulesets/Scoring/Score.cs | 2 ++ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 12 +--------- osu.Game/Screens/Play/Player.cs | 23 +++++++++++++------ 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 470086bf78..7c6bf8344b 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -37,16 +37,14 @@ namespace osu.Game.Rulesets.Osu.Scoring private readonly Dictionary scoreResultCounts = new Dictionary(); private readonly Dictionary comboResultCounts = new Dictionary(); - public override Score GetPopulatedScore() + public override void PopulateScore(Score score) { - var score = base.GetPopulatedScore(); + base.PopulateScore(score); score.Statistics[@"300"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit300); score.Statistics[@"100"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit100); score.Statistics[@"50"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Hit50); score.Statistics[@"x"] = scoreResultCounts.GetOrDefault(OsuScoreResult.Miss); - - return score; } protected override void OnNewJudgement(OsuJudgement judgement) diff --git a/osu.Game/Database/ScoreDatabase.cs b/osu.Game/Database/ScoreDatabase.cs index 2ffe12d50e..affbaf4e2b 100644 --- a/osu.Game/Database/ScoreDatabase.cs +++ b/osu.Game/Database/ScoreDatabase.cs @@ -45,7 +45,7 @@ namespace osu.Game.Database using (SerializationReader sr = new SerializationReader(s)) { var ruleset = rulesets.GetRuleset(sr.ReadByte()).CreateInstance(); - score = ruleset.CreateScoreProcessor().CreateEmptyScore(); + score = new Score(); /* score.Pass = true;*/ var version = sr.ReadInt32(); diff --git a/osu.Game/Rulesets/Scoring/Score.cs b/osu.Game/Rulesets/Scoring/Score.cs index fbbd766a18..5d94fde03b 100644 --- a/osu.Game/Rulesets/Scoring/Score.cs +++ b/osu.Game/Rulesets/Scoring/Score.cs @@ -32,6 +32,8 @@ namespace osu.Game.Rulesets.Scoring [JsonProperty(@"mods")] protected string[] ModStrings { get; set; } //todo: parse to Mod objects + public RulesetInfo Ruleset { get; set; } + public Mod[] Mods { get; set; } [JsonProperty(@"user")] diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 1fe21c8724..f31a1a11aa 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -61,12 +61,6 @@ namespace osu.Game.Rulesets.Scoring Reset(); } - /// - /// Creates a Score applicable to the ruleset in which this ScoreProcessor resides. - /// - /// The Score. - public virtual Score CreateEmptyScore() => new Score(); - private ScoreRank rankFrom(double acc) { if (acc == 1) @@ -114,10 +108,8 @@ namespace osu.Game.Rulesets.Scoring /// /// Retrieve a score populated with data for the current play this processor is responsible for. /// - public virtual Score GetPopulatedScore() + public virtual void PopulateScore(Score score) { - var score = CreateEmptyScore(); - score.TotalScore = TotalScore; score.Combo = Combo; score.MaxCombo = HighestCombo; @@ -125,8 +117,6 @@ namespace osu.Game.Rulesets.Scoring score.Rank = rankFrom(Accuracy); score.Date = DateTime.Now; score.Health = Health; - - return score; } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 8c3f3da58a..fc7cbe170a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Play private IAdjustableClock sourceClock; private IFrameBasedClock interpolatedSourceClock; - private Ruleset ruleset; + private RulesetInfo ruleset; private ScoreProcessor scoreProcessor; protected HitRenderer HitRenderer; @@ -68,6 +68,8 @@ namespace osu.Game.Screens.Play dimLevel = config.GetBindable(OsuConfig.DimLevel); mouseWheelDisabled = config.GetBindable(OsuConfig.MouseDisableWheel); + Ruleset rulesetInstance; + try { if (Beatmap == null) @@ -82,15 +84,17 @@ namespace osu.Game.Screens.Play try { // Try using the preferred user ruleset - ruleset = osu == null ? Beatmap.BeatmapInfo.Ruleset.CreateInstance() : osu.Ruleset.Value.CreateInstance(); - HitRenderer = ruleset.CreateHitRendererWith(Beatmap); + ruleset = osu == null ? Beatmap.BeatmapInfo.Ruleset : osu.Ruleset.Value; } catch (BeatmapInvalidForModeException) { // Default to the beatmap ruleset - ruleset = Beatmap.BeatmapInfo.Ruleset.CreateInstance(); - HitRenderer = ruleset.CreateHitRendererWith(Beatmap); + ruleset = Beatmap.BeatmapInfo.Ruleset; } + + rulesetInstance = ruleset.CreateInstance(); + + HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap); } catch (Exception e) { @@ -125,7 +129,7 @@ namespace osu.Game.Screens.Play Origin = Anchor.Centre }; - hudOverlay.KeyCounter.Add(ruleset.CreateGameplayKeys()); + hudOverlay.KeyCounter.Add(rulesetInstance.CreateGameplayKeys()); hudOverlay.BindProcessor(scoreProcessor); hudOverlay.BindHitRenderer(HitRenderer); @@ -266,7 +270,12 @@ namespace osu.Game.Screens.Play Delay(1000); onCompletionEvent = Schedule(delegate { - var score = scoreProcessor.GetPopulatedScore(); + var score = new Score + { + Beatmap = Beatmap.BeatmapInfo, + Ruleset = ruleset + }; + scoreProcessor.PopulateScore(score); score.User = HitRenderer.Replay?.User ?? (Game as OsuGame)?.API?.LocalUser?.Value; Push(new Results(score)); }); From 2d5f0f6b76d737f1a2809fbfb12a8950bb3b68f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Apr 2017 11:23:40 +0900 Subject: [PATCH 6/8] Fix off-by-one counts. --- osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 7c6bf8344b..079ee928af 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -53,16 +53,8 @@ namespace osu.Game.Rulesets.Osu.Scoring { if (judgement.Result != HitResult.None) { - int count; - if (scoreResultCounts.TryGetValue(judgement.Score, out count)) - scoreResultCounts[judgement.Score] = count + 1; - else - scoreResultCounts[judgement.Score] = 0; - - if (comboResultCounts.TryGetValue(judgement.Combo, out count)) - comboResultCounts[judgement.Combo] = count + 1; - else - comboResultCounts[judgement.Combo] = 0; + scoreResultCounts[judgement.Score] = scoreResultCounts.GetOrDefault(judgement.Score) + 1; + comboResultCounts[judgement.Combo] = comboResultCounts.GetOrDefault(judgement.Combo) + 1; } switch (judgement.Result) From 2a422ca5fa9ec0c5015cfa3afc0cb6106fb34c39 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Apr 2017 11:26:02 +0900 Subject: [PATCH 7/8] Remove ScoreStatistic. --- osu.Game/Rulesets/Scoring/ScoreStatistic.cs | 17 ----------------- osu.Game/osu.Game.csproj | 1 - 2 files changed, 18 deletions(-) delete mode 100644 osu.Game/Rulesets/Scoring/ScoreStatistic.cs diff --git a/osu.Game/Rulesets/Scoring/ScoreStatistic.cs b/osu.Game/Rulesets/Scoring/ScoreStatistic.cs deleted file mode 100644 index 5d1011e829..0000000000 --- a/osu.Game/Rulesets/Scoring/ScoreStatistic.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -namespace osu.Game.Rulesets.Scoring -{ - public class ScoreStatistic - { - public readonly string Name; - public readonly object Value; - - public ScoreStatistic(string name, object value) - { - Name = name; - Value = value; - } - } -} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index de6c889f95..752290769d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -156,7 +156,6 @@ - From 873599b359cb74d839f6047b49687c8b6c234343 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Apr 2017 11:36:50 +0900 Subject: [PATCH 8/8] Fix conversion regression. --- osu.Game/Database/ScoreDatabase.cs | 6 ++++-- osu.Game/Rulesets/Ruleset.cs | 6 ++++++ osu.Game/Screens/Play/Player.cs | 15 ++++++++------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game/Database/ScoreDatabase.cs b/osu.Game/Database/ScoreDatabase.cs index affbaf4e2b..99fa9fbf9a 100644 --- a/osu.Game/Database/ScoreDatabase.cs +++ b/osu.Game/Database/ScoreDatabase.cs @@ -44,8 +44,10 @@ namespace osu.Game.Database using (Stream s = storage.GetStream(Path.Combine(replay_folder, replayFilename))) using (SerializationReader sr = new SerializationReader(s)) { - var ruleset = rulesets.GetRuleset(sr.ReadByte()).CreateInstance(); - score = new Score(); + score = new Score + { + Ruleset = rulesets.GetRuleset(sr.ReadByte()) + }; /* score.Pass = true;*/ var version = sr.ReadInt32(); diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 5e92d25297..ea35e61b36 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -17,6 +17,12 @@ namespace osu.Game.Rulesets public abstract IEnumerable GetModsFor(ModType type); + /// + /// Attempt to create a HitRenderer for the provided beatmap. + /// + /// + /// Unable to successfully load the beatmap to be usable with this ruleset. + /// public abstract HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap); public abstract DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index fc7cbe170a..ca27e07262 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -81,20 +81,21 @@ namespace osu.Game.Screens.Play if (Beatmap == null) throw new Exception("Beatmap was not loaded"); + ruleset = osu?.Ruleset.Value ?? Beatmap.BeatmapInfo.Ruleset; + rulesetInstance = ruleset.CreateInstance(); + try { - // Try using the preferred user ruleset - ruleset = osu == null ? Beatmap.BeatmapInfo.Ruleset : osu.Ruleset.Value; + HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap); } catch (BeatmapInvalidForModeException) { - // Default to the beatmap ruleset + // we may fail to create a HitRenderer if the beatmap cannot be loaded with the user's preferred ruleset + // let's try again forcing the beatmap's ruleset. ruleset = Beatmap.BeatmapInfo.Ruleset; + rulesetInstance = ruleset.CreateInstance(); + HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap); } - - rulesetInstance = ruleset.CreateInstance(); - - HitRenderer = rulesetInstance.CreateHitRendererWith(Beatmap); } catch (Exception e) {