1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 07:33:20 +08:00

Isolate score submissions model and remove serialisation from ScoreInfo

This commit is contained in:
Dean Herbert 2021-10-29 13:02:19 +09:00
parent 1944c255a7
commit 54073d8a1e
2 changed files with 68 additions and 39 deletions

View File

@ -1,12 +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.Collections.Generic;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using osu.Framework.IO.Network;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
namespace osu.Game.Online.Solo
{
@ -16,13 +21,13 @@ namespace osu.Game.Online.Solo
private readonly int beatmapId;
private readonly ScoreInfo scoreInfo;
private readonly SubmittableScore score;
public SubmitSoloScoreRequest(int beatmapId, long scoreId, ScoreInfo scoreInfo)
{
this.beatmapId = beatmapId;
this.scoreId = scoreId;
this.scoreInfo = scoreInfo;
score = new SubmittableScore(scoreInfo);
}
protected override WebRequest CreateWebRequest()
@ -32,7 +37,7 @@ namespace osu.Game.Online.Solo
req.ContentType = "application/json";
req.Method = HttpMethod.Put;
req.AddRaw(JsonConvert.SerializeObject(scoreInfo, new JsonSerializerSettings
req.AddRaw(JsonConvert.SerializeObject(score, new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}));
@ -42,4 +47,57 @@ namespace osu.Game.Online.Solo
protected override string Target => $@"beatmaps/{beatmapId}/solo/scores/{scoreId}";
}
/// <summary>
/// A class specifically for sending scores to the API during score submission.
/// This is used instead of <see cref="APIScoreInfo"/> due to marginally different serialisation naming requirements.
/// </summary>
public class SubmittableScore
{
[JsonProperty("rank")]
[JsonConverter(typeof(StringEnumConverter))]
public ScoreRank Rank { get; }
[JsonProperty("total_score")]
public long TotalScore { get; }
[JsonProperty("accuracy")]
public double Accuracy { get; }
[JsonProperty(@"pp")]
public double? PP { get; }
[JsonProperty("max_combo")]
public int MaxCombo { get; }
[JsonProperty("ruleset_id")]
public int RulesetID { get; }
[JsonProperty("passed")]
public bool Passed { get; }
// Used for API serialisation/deserialisation.
[JsonProperty("mods")]
public APIMod[] Mods { get; }
[JsonProperty("user")]
public User User { get; }
[JsonProperty("statistics")]
public Dictionary<HitResult, int> Statistics { get; }
public SubmittableScore(ScoreInfo score)
{
Rank = score.Rank;
TotalScore = score.TotalScore;
Accuracy = score.Accuracy;
PP = score.PP;
MaxCombo = score.MaxCombo;
RulesetID = score.RulesetID;
Passed = score.Passed;
Mods = score.APIMods;
User = score.User;
Statistics = score.Statistics;
}
}
}

View File

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Database;
@ -23,44 +22,32 @@ namespace osu.Game.Scoring
{
public int ID { get; set; }
[JsonProperty("rank")]
[JsonConverter(typeof(StringEnumConverter))]
public ScoreRank Rank { get; set; }
[JsonProperty("total_score")]
public long TotalScore { get; set; }
[JsonProperty("accuracy")]
[Column(TypeName = "DECIMAL(1,4)")] // TODO: This data type is wrong (should contain more precision). But at the same time, we probably don't need to be storing this in the database.
public double Accuracy { get; set; }
[JsonIgnore]
public LocalisableString DisplayAccuracy => Accuracy.FormatAccuracy();
[JsonProperty(@"pp")]
public double? PP { get; set; }
[JsonProperty("max_combo")]
public int MaxCombo { get; set; }
[JsonIgnore]
public int Combo { get; set; } // Todo: Shouldn't exist in here
[JsonProperty("ruleset_id")]
public int RulesetID { get; set; }
[JsonProperty("passed")]
[NotMapped]
public bool Passed { get; set; } = true;
[JsonIgnore]
public RulesetInfo Ruleset { get; set; }
private APIMod[] localAPIMods;
private Mod[] mods;
[JsonIgnore]
[NotMapped]
public Mod[] Mods
{
@ -75,7 +62,7 @@ namespace osu.Game.Scoring
if (mods != null)
scoreMods = mods;
else if (localAPIMods != null)
scoreMods = apiMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
scoreMods = APIMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
return scoreMods;
}
@ -87,9 +74,8 @@ namespace osu.Game.Scoring
}
// Used for API serialisation/deserialisation.
[JsonProperty("mods")]
[NotMapped]
private APIMod[] apiMods
public APIMod[] APIMods
{
get
{
@ -111,19 +97,16 @@ namespace osu.Game.Scoring
}
// Used for database serialisation/deserialisation.
[JsonIgnore]
[Column("Mods")]
public string ModsJson
{
get => JsonConvert.SerializeObject(apiMods);
set => apiMods = JsonConvert.DeserializeObject<APIMod[]>(value);
get => JsonConvert.SerializeObject(APIMods);
set => APIMods = JsonConvert.DeserializeObject<APIMod[]>(value);
}
[NotMapped]
[JsonProperty("user")]
public User User { get; set; }
[JsonIgnore]
[Column("User")]
public string UserString
{
@ -135,7 +118,6 @@ namespace osu.Game.Scoring
}
}
[JsonIgnore]
[Column("UserID")]
public int? UserID
{
@ -147,23 +129,18 @@ namespace osu.Game.Scoring
}
}
[JsonIgnore]
public int BeatmapInfoID { get; set; }
[JsonIgnore]
[Column("Beatmap")]
public virtual BeatmapInfo BeatmapInfo { get; set; }
public BeatmapInfo BeatmapInfo { get; set; }
[JsonIgnore]
public long? OnlineScoreID { get; set; }
[JsonIgnore]
public DateTimeOffset Date { get; set; }
[JsonProperty("statistics")]
[NotMapped]
public Dictionary<HitResult, int> Statistics { get; set; } = new Dictionary<HitResult, int>();
[JsonIgnore]
[Column("Statistics")]
public string StatisticsJson
{
@ -181,29 +158,23 @@ namespace osu.Game.Scoring
}
[NotMapped]
[JsonIgnore]
public List<HitEvent> HitEvents { get; set; }
[JsonIgnore]
public List<ScoreFileInfo> Files { get; set; }
[JsonIgnore]
public string Hash { get; set; }
[JsonIgnore]
public bool DeletePending { get; set; }
/// <summary>
/// The position of this score, starting at 1.
/// </summary>
[NotMapped]
[JsonProperty("position")]
public int? Position { get; set; }
public int? Position { get; set; } // TODO: remove after all calls to `CreateScoreInfo` are gone.
/// <summary>
/// Whether this <see cref="ScoreInfo"/> represents a legacy (osu!stable) score.
/// </summary>
[JsonIgnore]
[NotMapped]
public bool IsLegacyScore => Mods.OfType<ModClassic>().Any();