Delta-v/Content.Server/_CD/Records/RecordsSerialization.cs

94 lines
4.0 KiB
C#

using Content.Server.Database;
using Content.Shared._CD.Records;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.Json;
namespace Content.Server._CD.Records;
public static class RecordsSerialization
{
private static int DeserializeInt(JsonElement e, string key, int def)
{
if (e.TryGetProperty(key, out var prop) && prop.TryGetInt32(out var v))
{
return v;
}
return def;
}
private static bool DeserializeBool(JsonElement e, string key, bool def)
{
if (!e.TryGetProperty(key, out var v))
return def;
return v.ValueKind switch
{
JsonValueKind.True => true,
JsonValueKind.False => false,
_ => def,
};
}
[return: NotNullIfNotNull(nameof(def))]
private static string? DeserializeString(JsonElement e, string key, string? def)
{
if (!e.TryGetProperty(key, out var v))
return def;
if (v.ValueKind == JsonValueKind.String)
return v.GetString() ?? def;
return def;
}
private static List<PlayerProvidedCharacterRecords.RecordEntry> DeserializeEntries(List<CDModel.CharacterRecordEntry> entries, CDModel.DbRecordEntryType ty)
{
return entries.Where(e => e.Type == ty)
.OrderBy(e => e.Id) // attempt at fixing the record order changing bug.
.Select(e => new PlayerProvidedCharacterRecords.RecordEntry(e.Title, e.Involved, e.Description))
.ToList();
}
/// <summary>
/// We need to manually deserialize CharacterRecords because the easy JSON deserializer does not
/// do exactly what we want. More specifically, we need to more robustly handle missing and extra fields
/// <br />
/// <br />
/// Missing fields are filled in with their default value, extra fields are simply ignored
/// </summary>
public static PlayerProvidedCharacterRecords Deserialize(JsonDocument json, List<CDModel.CharacterRecordEntry> entries)
{
var e = json.RootElement;
var def = PlayerProvidedCharacterRecords.DefaultRecords();
return new PlayerProvidedCharacterRecords(
height: DeserializeInt(e, nameof(def.Height), def.Height),
weight: DeserializeInt(e, nameof(def.Weight), def.Weight),
emergencyContactName: DeserializeString(e, nameof(def.EmergencyContactName), def.EmergencyContactName),
hasWorkAuthorization: DeserializeBool(e, nameof(def.HasWorkAuthorization), def.HasWorkAuthorization),
identifyingFeatures: DeserializeString(e, nameof(def.IdentifyingFeatures), def.IdentifyingFeatures),
allergies: DeserializeString(e, nameof(def.Allergies), def.Allergies),
drugAllergies: DeserializeString(e, nameof(def.DrugAllergies), def.DrugAllergies),
postmortemInstructions: DeserializeString(e, nameof(def.PostmortemInstructions), def.PostmortemInstructions),
medicalEntries: DeserializeEntries(entries, CDModel.DbRecordEntryType.Medical),
securityEntries: DeserializeEntries(entries, CDModel.DbRecordEntryType.Security),
employmentEntries: DeserializeEntries(entries, CDModel.DbRecordEntryType.Employment));
}
private static CDModel.CharacterRecordEntry ConvertEntry(PlayerProvidedCharacterRecords.RecordEntry entry, CDModel.DbRecordEntryType type)
{
entry.EnsureValid();
return new CDModel.CharacterRecordEntry()
{ Title = entry.Title, Involved = entry.Involved, Description = entry.Description, Type = type };
}
public static List<CDModel.CharacterRecordEntry> GetEntries(PlayerProvidedCharacterRecords records)
{
return records.MedicalEntries.Select(medical => ConvertEntry(medical, CDModel.DbRecordEntryType.Medical))
.Concat(records.SecurityEntries.Select(security => ConvertEntry(security, CDModel.DbRecordEntryType.Security)))
.Concat(records.EmploymentEntries.Select(employment => ConvertEntry(employment, CDModel.DbRecordEntryType.Employment)))
.ToList();
}
}