using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace Uigenx.Protocol
{
/// Shared JSON settings for every bridge message. The wire form is camelCase.
public static class UgxJson
{
/// Bumped only for incompatible changes. Unknown message types are ignored, so minors are additive.
public const int ProtocolVersion = 1;
static readonly JsonSerializerSettings SettingsInstance = Build();
public static JsonSerializerSettings Settings => SettingsInstance;
static readonly JsonSerializer SerializerInstance = JsonSerializer.CreateDefault(SettingsInstance);
/// Reuse this rather than creating a serializer per message; construction is not cheap.
public static JsonSerializer Serializer => SerializerInstance;
static JsonSerializerSettings Build()
{
// ProcessDictionaryKeys must stay false: dictionary keys carry data paths (`player.hp`)
// and payload keys that the daemon matches verbatim.
var resolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy
{
ProcessDictionaryKeys = false,
OverrideSpecifiedNames = false,
},
};
var settings = new JsonSerializerSettings
{
ContractResolver = resolver,
NullValueHandling = NullValueHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Formatting = Formatting.None,
MissingMemberHandling = MissingMemberHandling.Ignore,
};
// No naming strategy on the enum converter: every wire name is spelled out with
// [EnumMember] so the JSON text never depends on the C# member spelling.
settings.Converters.Add(new StringEnumConverter());
return settings;
}
public static string Serialize(object value) => JsonConvert.SerializeObject(value, SettingsInstance);
public static T Deserialize(string json) => JsonConvert.DeserializeObject(json, SettingsInstance);
///
/// Unwraps the JObject and JArray values Newtonsoft leaves inside an
/// object valued dictionary into plain dictionaries, lists and primitives, so code
/// outside Uigenx.Protocol never has to know about Newtonsoft's tree.
///
public static object ToPlain(object value)
{
switch (value)
{
case Newtonsoft.Json.Linq.JObject map:
{
var result = new System.Collections.Generic.Dictionary(map.Count);
foreach (var property in map) result[property.Key] = ToPlain(property.Value);
return result;
}
case Newtonsoft.Json.Linq.JArray array:
{
var result = new System.Collections.Generic.List