1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 10:07:52 +08:00

Decouple APILegacyScoreInfo from ScoreInfo

This commit is contained in:
Dean Herbert 2019-12-03 15:28:10 +09:00
parent 8a6b2e681a
commit f0d49d0cdf
14 changed files with 254 additions and 227 deletions

View File

@ -34,12 +34,10 @@ namespace osu.Game.Rulesets.Catch.Difficulty
{
mods = Score.Mods;
var legacyScore = Score as LegacyScoreInfo;
fruitsHit = legacyScore?.Count300 ?? Score.Statistics[HitResult.Perfect];
ticksHit = legacyScore?.Count100 ?? 0;
tinyTicksHit = legacyScore?.Count50 ?? 0;
tinyTicksMissed = legacyScore?.CountKatu ?? 0;
fruitsHit = Score?.GetCount300() ?? Score.Statistics[HitResult.Perfect];
ticksHit = Score?.GetCount100() ?? 0;
tinyTicksHit = Score?.GetCount50() ?? 0;
tinyTicksMissed = Score?.GetCountKatu() ?? 0;
misses = Score.Statistics[HitResult.Miss];
// Don't count scores made with supposedly unranked mods

View File

@ -5,11 +5,12 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Osu;
using osu.Game.Scoring;
using osu.Game.Users;
using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Rulesets;
using osu.Game.Screens.Ranking.Pages;
namespace osu.Game.Tests.Visual.Gameplay
@ -17,6 +18,9 @@ namespace osu.Game.Tests.Visual.Gameplay
[TestFixture]
public class TestSceneReplayDownloadButton : OsuTestScene
{
[Resolved]
private RulesetStore rulesets { get; set; }
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(ReplayDownloadButton)
@ -49,16 +53,15 @@ namespace osu.Game.Tests.Visual.Gameplay
{
return new APILegacyScoreInfo
{
ID = 1,
OnlineScoreID = 2553163309,
Ruleset = new OsuRuleset().RulesetInfo,
OnlineRulesetID = 0,
Replay = replayAvailable,
User = new User
{
Id = 39828,
Username = @"WubWoofWolf",
}
};
}.CreateScoreInfo(rulesets);
}
private class TestReplayDownloadButton : ReplayDownloadButton

View File

@ -1,4 +1,4 @@
// 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.
using System;
@ -9,9 +9,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.MathUtils;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
using osuTK.Graphics;
@ -66,12 +64,12 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"ES",
},
},
Mods = new Mod[]
Mods = new[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
new OsuModFlashlight(),
new OsuModHardRock(),
new OsuModDoubleTime().Acronym,
new OsuModHidden().Acronym,
new OsuModFlashlight().Acronym,
new OsuModHardRock().Acronym,
},
Rank = ScoreRank.XH,
PP = 200,
@ -91,11 +89,11 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"BR",
},
},
Mods = new Mod[]
Mods = new[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
new OsuModFlashlight(),
new OsuModDoubleTime().Acronym,
new OsuModHidden().Acronym,
new OsuModFlashlight().Acronym,
},
Rank = ScoreRank.S,
PP = 190,
@ -115,10 +113,10 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"JP",
},
},
Mods = new Mod[]
Mods = new[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
new OsuModDoubleTime().Acronym,
new OsuModHidden().Acronym,
},
Rank = ScoreRank.B,
PP = 180,
@ -138,9 +136,9 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"CA",
},
},
Mods = new Mod[]
Mods = new[]
{
new OsuModDoubleTime(),
new OsuModDoubleTime().Acronym,
},
Rank = ScoreRank.C,
PP = 170,
@ -208,12 +206,12 @@ namespace osu.Game.Tests.Visual.Online
FlagName = @"ES",
},
},
Mods = new Mod[]
Mods = new[]
{
new OsuModDoubleTime(),
new OsuModHidden(),
new OsuModFlashlight(),
new OsuModHardRock(),
new OsuModDoubleTime().Acronym,
new OsuModHidden().Acronym,
new OsuModFlashlight().Acronym,
new OsuModHardRock().Acronym,
},
Rank = ScoreRank.XH,
PP = 200,
@ -226,10 +224,10 @@ namespace osu.Game.Tests.Visual.Online
foreach (var s in allScores.Scores)
{
s.Statistics.Add(HitResult.Great, RNG.Next(2000));
s.Statistics.Add(HitResult.Good, RNG.Next(2000));
s.Statistics.Add(HitResult.Meh, RNG.Next(2000));
s.Statistics.Add(HitResult.Miss, RNG.Next(2000));
s.Statistics.Add("count_300", RNG.Next(2000));
s.Statistics.Add("count_100", RNG.Next(2000));
s.Statistics.Add("count_50", RNG.Next(2000));
s.Statistics.Add("count_miss", RNG.Next(2000));
}
AddStep("Load all scores", () =>

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Select.Leaderboards;
@ -62,7 +61,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
User = new User
{
Id = 6602580,

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics.Shapes;
using osuTK.Graphics;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Scoring;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
@ -52,7 +51,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
User = new User
{
Id = 6602580,

View File

@ -9,6 +9,7 @@ using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Mods;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
namespace osu.Game.Online.API.Requests
{
@ -37,10 +38,12 @@ namespace osu.Game.Online.API.Requests
private void onSuccess(APILegacyScores r)
{
Debug.Assert(ruleset.ID != null, "ruleset.ID != null");
foreach (APILegacyScoreInfo score in r.Scores)
{
score.Beatmap = beatmap;
score.Ruleset = ruleset;
score.OnlineRulesetID = ruleset.ID.Value;
}
var userScore = r.UserScore;
@ -48,7 +51,7 @@ namespace osu.Game.Online.API.Requests
if (userScore != null)
{
userScore.Score.Beatmap = beatmap;
userScore.Score.Ruleset = ruleset;
userScore.Score.OnlineRulesetID = ruleset.ID.Value;
}
}

View File

@ -5,56 +5,103 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Scoring.Legacy;
using osu.Game.Users;
namespace osu.Game.Online.API.Requests.Responses
{
public class APILegacyScoreInfo : LegacyScoreInfo
public class APILegacyScoreInfo
{
[JsonProperty(@"score")]
private int totalScore
public ScoreInfo CreateScoreInfo(RulesetStore rulesets)
{
set => TotalScore = value;
var ruleset = rulesets.GetRuleset(OnlineRulesetID);
var mods = Mods != null ? ruleset.CreateInstance().GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty<Mod>();
var scoreInfo = new ScoreInfo
{
TotalScore = TotalScore,
MaxCombo = MaxCombo,
User = User,
Accuracy = Accuracy,
OnlineScoreID = OnlineScoreID,
Date = Date,
PP = PP,
Beatmap = Beatmap,
RulesetID = OnlineRulesetID,
Hash = "online", // todo: temporary?
Rank = Rank,
Ruleset = ruleset,
Mods = mods,
};
foreach (var kvp in Statistics)
{
switch (kvp.Key)
{
case @"count_geki":
scoreInfo.SetCountGeki(kvp.Value);
break;
case @"count_300":
scoreInfo.SetCount300(kvp.Value);
break;
case @"count_katu":
scoreInfo.SetCountKatu(kvp.Value);
break;
case @"count_100":
scoreInfo.SetCount100(kvp.Value);
break;
case @"count_50":
scoreInfo.SetCount50(kvp.Value);
break;
case @"count_miss":
scoreInfo.SetCountMiss(kvp.Value);
break;
}
}
return scoreInfo;
}
[JsonProperty(@"score")]
public int TotalScore { get; set; }
[JsonProperty(@"max_combo")]
private int maxCombo
{
set => MaxCombo = value;
}
public int MaxCombo { get; set; }
[JsonProperty(@"user")]
private User user
{
set => User = value;
}
public User User { get; set; }
[JsonProperty(@"id")]
private long onlineScoreID
{
set => OnlineScoreID = value;
}
public long OnlineScoreID { get; set; }
[JsonProperty(@"replay")]
public bool Replay { get; set; }
[JsonProperty(@"created_at")]
private DateTimeOffset date
{
set => Date = value;
}
public DateTimeOffset Date { get; set; }
[JsonProperty(@"beatmap")]
private BeatmapInfo beatmap
{
set => Beatmap = value;
}
public BeatmapInfo Beatmap { get; set; }
[JsonProperty("accuracy")]
public double Accuracy { get; set; }
[JsonProperty(@"pp")]
public double? PP { get; set; }
[JsonProperty(@"beatmapset")]
private BeatmapMetadata metadata
public BeatmapMetadata Metadata
{
set
{
@ -67,68 +114,16 @@ namespace osu.Game.Online.API.Requests.Responses
}
[JsonProperty(@"statistics")]
private Dictionary<string, int> jsonStats
{
set
{
foreach (var kvp in value)
{
switch (kvp.Key)
{
case @"count_geki":
CountGeki = kvp.Value;
break;
case @"count_300":
Count300 = kvp.Value;
break;
case @"count_katu":
CountKatu = kvp.Value;
break;
case @"count_100":
Count100 = kvp.Value;
break;
case @"count_50":
Count50 = kvp.Value;
break;
case @"count_miss":
CountMiss = kvp.Value;
break;
default:
continue;
}
}
}
}
public Dictionary<string, int> Statistics { get; set; }
[JsonProperty(@"mode_int")]
public int OnlineRulesetID
{
get => RulesetID;
set => RulesetID = value;
}
public int OnlineRulesetID { get; set; }
[JsonProperty(@"mods")]
private string[] modStrings { get; set; }
public string[] Mods { get; set; }
public override RulesetInfo Ruleset
{
get => base.Ruleset;
set
{
base.Ruleset = value;
if (modStrings != null)
{
// Evaluate the mod string
Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.Acronym)).ToArray();
}
}
}
[JsonProperty("rank")]
[JsonConverter(typeof(StringEnumConverter))]
public ScoreRank Rank { get; set; }
}
}

View File

@ -41,6 +41,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
[Resolved]
private IAPIProvider api { get; set; }
[Resolved]
private RulesetStore rulesets { get; set; }
private GetScoresRequest getScoresRequest;
protected APILegacyScores Scores
@ -56,16 +59,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
return;
}
scoreTable.Scores = value.Scores;
var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList();
scoreTable.Scores = scoreInfos;
scoreTable.Show();
var topScore = value.Scores.First();
var topScore = scoreInfos.First();
var userScore = value.UserScore;
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets);
topScoresContainer.Add(new DrawableTopScore(topScore));
if (userScore != null && userScore.Score.OnlineScoreID != topScore.OnlineScoreID)
topScoresContainer.Add(new DrawableTopScore(userScore.Score, userScore.Position));
if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID)
topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position));
});
}

View File

@ -29,14 +29,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
ItemsContainer.Direction = FillDirection.Vertical;
}
protected override void UpdateItems(List<APILegacyScoreInfo> items)
{
foreach (var item in items)
item.Ruleset = Rulesets.GetRuleset(item.RulesetID);
base.UpdateItems(items);
}
protected override APIRequest<List<APILegacyScoreInfo>> CreateRequest() =>
new GetUserScoresRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
@ -45,10 +37,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
switch (type)
{
default:
return new DrawablePerformanceScore(model, includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null);
return new DrawablePerformanceScore(model.CreateScoreInfo(Rulesets), includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null);
case ScoreType.Recent:
return new DrawableTotalScore(model);
return new DrawableTotalScore(model.CreateScoreInfo(Rulesets));
}
}
}

View File

@ -5,114 +5,139 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Scoring.Legacy
{
public class LegacyScoreInfo : ScoreInfo
public static class ScoreInfoLegacyExtensions
{
private int countGeki;
public int CountGeki
public static int? GetCountGeki(this ScoreInfo scoreInfo)
{
get => countGeki;
set
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
countGeki = value;
case 3:
return scoreInfo.Statistics[HitResult.Perfect];
}
switch (Ruleset?.ID ?? RulesetID)
{
case 3:
Statistics[HitResult.Perfect] = value;
break;
}
return null;
}
public static void SetCountGeki(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 3:
scoreInfo.Statistics[HitResult.Perfect] = value;
break;
}
}
private int count300;
public int Count300
public static int? GetCount300(this ScoreInfo scoreInfo)
{
get => count300;
set
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
count300 = value;
case 0:
case 1:
case 3:
return scoreInfo.Statistics[HitResult.Great];
switch (Ruleset?.ID ?? RulesetID)
{
case 0:
case 1:
case 3:
Statistics[HitResult.Great] = value;
break;
case 2:
return scoreInfo.Statistics[HitResult.Perfect];
}
case 2:
Statistics[HitResult.Perfect] = value;
break;
}
return null;
}
public static void SetCount300(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 0:
case 1:
case 3:
scoreInfo.Statistics[HitResult.Great] = value;
break;
case 2:
scoreInfo.Statistics[HitResult.Perfect] = value;
break;
}
}
private int countKatu;
public int CountKatu
public static int? GetCountKatu(this ScoreInfo scoreInfo)
{
get => countKatu;
set
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
countKatu = value;
case 3:
return scoreInfo.Statistics[HitResult.Good];
}
switch (Ruleset?.ID ?? RulesetID)
{
case 3:
Statistics[HitResult.Good] = value;
break;
}
return null;
}
public static void SetCountKatu(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 3:
scoreInfo.Statistics[HitResult.Good] = value;
break;
}
}
private int count100;
public int Count100
public static int? GetCount100(this ScoreInfo scoreInfo)
{
get => count100;
set
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
count100 = value;
case 0:
case 1:
return scoreInfo.Statistics[HitResult.Good];
switch (Ruleset?.ID ?? RulesetID)
{
case 0:
case 1:
Statistics[HitResult.Good] = value;
break;
case 3:
return scoreInfo.Statistics[HitResult.Ok];
}
case 3:
Statistics[HitResult.Ok] = value;
break;
}
return null;
}
public static void SetCount100(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 0:
case 1:
scoreInfo.Statistics[HitResult.Good] = value;
break;
case 3:
scoreInfo.Statistics[HitResult.Ok] = value;
break;
}
}
private int count50;
public int Count50
public static int? GetCount50(this ScoreInfo scoreInfo)
{
get => count50;
set
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
count50 = value;
case 0:
case 3:
return scoreInfo.Statistics[HitResult.Meh];
}
switch (Ruleset?.ID ?? RulesetID)
{
case 0:
case 3:
Statistics[HitResult.Meh] = value;
break;
}
return null;
}
public static void SetCount50(this ScoreInfo scoreInfo, int value)
{
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
{
case 0:
case 3:
scoreInfo.Statistics[HitResult.Meh] = value;
break;
}
}
public int CountMiss
{
get => Statistics[HitResult.Miss];
set => Statistics[HitResult.Miss] = value;
}
public static int? GetCountMiss(this ScoreInfo scoreInfo) =>
scoreInfo.Statistics[HitResult.Miss];
public static void SetCountMiss(this ScoreInfo scoreInfo, int value) =>
scoreInfo.Statistics[HitResult.Miss] = value;
}
}

View File

@ -35,7 +35,7 @@ namespace osu.Game.Scoring.Legacy
using (SerializationReader sr = new SerializationReader(stream))
{
currentRuleset = GetRuleset(sr.ReadByte());
var scoreInfo = new LegacyScoreInfo { Ruleset = currentRuleset.RulesetInfo };
var scoreInfo = new ScoreInfo { Ruleset = currentRuleset.RulesetInfo };
score.ScoreInfo = scoreInfo;
@ -53,12 +53,12 @@ namespace osu.Game.Scoring.Legacy
// MD5Hash
sr.ReadString();
scoreInfo.Count300 = sr.ReadUInt16();
scoreInfo.Count100 = sr.ReadUInt16();
scoreInfo.Count50 = sr.ReadUInt16();
scoreInfo.CountGeki = sr.ReadUInt16();
scoreInfo.CountKatu = sr.ReadUInt16();
scoreInfo.CountMiss = sr.ReadUInt16();
scoreInfo.SetCount300(sr.ReadUInt16());
scoreInfo.SetCount100(sr.ReadUInt16());
scoreInfo.SetCount50(sr.ReadUInt16());
scoreInfo.SetCountGeki(sr.ReadUInt16());
scoreInfo.SetCountKatu(sr.ReadUInt16());
scoreInfo.SetCountMiss(sr.ReadUInt16());
scoreInfo.TotalScore = sr.ReadInt32();
scoreInfo.MaxCombo = sr.ReadUInt16();

View File

@ -6,7 +6,6 @@ using osu.Framework.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Scoring;
using osuTK;
@ -24,7 +23,7 @@ namespace osu.Game.Screens.Ranking.Pages
if (State.Value == DownloadState.LocallyAvailable)
return ReplayAvailability.Local;
if (Model.Value is APILegacyScoreInfo apiScore && apiScore.Replay)
if (!string.IsNullOrEmpty(Model.Value.Hash))
return ReplayAvailability.Online;
return ReplayAvailability.NotAvailable;

View File

@ -21,6 +21,9 @@ namespace osu.Game.Screens.Select.Leaderboards
{
public Action<ScoreInfo> ScoreSelected;
[Resolved]
private RulesetStore rulesets { get; set; }
private BeatmapInfo beatmap;
public BeatmapInfo Beatmap
@ -172,7 +175,7 @@ namespace osu.Game.Screens.Select.Leaderboards
req.Success += r =>
{
scoresCallback?.Invoke(r.Scores);
scoresCallback?.Invoke(r.Scores.Select(s => s.CreateScoreInfo(rulesets)));
TopScore = r.UserScore;
};

View File

@ -3,6 +3,7 @@
using System;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -10,6 +11,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.Rulesets;
using osu.Game.Scoring;
using osuTK;
@ -27,6 +29,9 @@ namespace osu.Game.Screens.Select.Leaderboards
protected override bool StartHidden => true;
[Resolved]
private RulesetStore rulesets { get; set; }
public UserTopScoreContainer()
{
RelativeSizeAxes = Axes.X;
@ -77,9 +82,11 @@ namespace osu.Game.Screens.Select.Leaderboards
if (newScore == null)
return;
LoadComponentAsync(new LeaderboardScore(newScore.Score, newScore.Position, false)
var scoreInfo = newScore.Score.CreateScoreInfo(rulesets);
LoadComponentAsync(new LeaderboardScore(scoreInfo, newScore.Position, false)
{
Action = () => ScoreSelected?.Invoke(newScore.Score)
Action = () => ScoreSelected?.Invoke(scoreInfo)
}, drawableScore =>
{
scoreContainer.Child = drawableScore;