Files
FlaxEngine/Source/Engine/Serialization/JsonConverters.cs

466 lines
16 KiB
C#

// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using FlaxEngine.GUI;
using Newtonsoft.Json;
namespace FlaxEngine.Json
{
/// <summary>
/// Serialize references to the <see cref="FlaxEngine.Object"/> as Guid.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class FlaxObjectConverter : JsonConverter
{
/// <inheritdoc />
public override unsafe void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
Guid id = Guid.Empty;
if (value is Object obj)
id = obj.ID;
writer.WriteValue(JsonSerializer.GetStringID(&id));
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
JsonSerializer.ParseID((string)reader.Value, out var id);
return Object.Find(ref id, objectType);
}
return null;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
// Skip serialization as reference id for the root object serialization (eg. Script)
var cache = JsonSerializer.Current.Value;
if (cache != null && cache.IsWriting && cache.SerializerWriter.SerializeStackSize == 0)
{
return false;
}
return typeof(Object).IsAssignableFrom(objectType);
}
}
/// <summary>
/// Serialize <see cref="SceneReference"/> as Guid in internal format.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class SceneReferenceConverter : JsonConverter
{
/// <inheritdoc />
public override unsafe void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
Guid id = ((SceneReference)value).ID;
writer.WriteValue(JsonSerializer.GetStringID(&id));
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
SceneReference result = new SceneReference();
if (reader.TokenType == JsonToken.String)
{
JsonSerializer.ParseID((string)reader.Value, out result.ID);
}
return result;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SceneReference);
}
}
/// <summary>
/// Serialize <see cref="SoftObjectReference"/> as Guid in internal format.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class SoftObjectReferenceConverter : JsonConverter
{
/// <inheritdoc />
public override unsafe void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
var id = ((SoftObjectReference)value).ID;
writer.WriteValue(JsonSerializer.GetStringID(&id));
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var result = new SoftObjectReference();
if (reader.TokenType == JsonToken.String)
{
JsonSerializer.ParseID((string)reader.Value, out var id);
result.ID = id;
}
return result;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SoftObjectReference);
}
}
/// <summary>
/// Serialize <see cref="SoftTypeReference"/> as typename string in internal format.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class SoftTypeReferenceConverter : JsonConverter
{
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
writer.WriteValue(((SoftTypeReference)value).TypeName);
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var result = new SoftTypeReference();
if (reader.TokenType == JsonToken.String)
result.TypeName = (string)reader.Value;
return result;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SoftTypeReference);
}
}
/// <summary>
/// Serialize <see cref="BehaviorKnowledgeSelectorAny"/> as path string in internal format.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class BehaviorKnowledgeSelectorAnyConverter : JsonConverter
{
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
writer.WriteValue(((BehaviorKnowledgeSelectorAny)value).Path);
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var result = new BehaviorKnowledgeSelectorAny();
if (reader.TokenType == JsonToken.String)
result.Path = (string)reader.Value;
else if (reader.TokenType == JsonToken.StartObject)
{
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
{
var propertyName = (string)reader.Value;
switch (propertyName)
{
case "Path":
result.Path = reader.ReadAsString();
break;
}
break;
}
case JsonToken.Comment: break;
case JsonToken.String: break;
default: return result;
}
}
}
return result;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(BehaviorKnowledgeSelectorAny);
}
}
/// <summary>
/// Serialize <see cref="Margin"/> as Guid in internal format.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class MarginConverter : JsonConverter
{
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
var valueMargin = (Margin)value;
writer.WriteStartObject();
{
#if FLAX_EDITOR
if ((serializer.TypeNameHandling & TypeNameHandling.Objects) == TypeNameHandling.Objects)
{
writer.WritePropertyName("$type");
writer.WriteValue("FlaxEngine.GUI.Margin, FlaxEngine.CSharp");
}
#endif
writer.WritePropertyName("Left");
writer.WriteValue(valueMargin.Left);
writer.WritePropertyName("Right");
writer.WriteValue(valueMargin.Right);
writer.WritePropertyName("Top");
writer.WriteValue(valueMargin.Top);
writer.WritePropertyName("Bottom");
writer.WriteValue(valueMargin.Bottom);
}
writer.WriteEndObject();
}
/// <inheritdoc />
public override void WriteJsonDiff(JsonWriter writer, object value, object other, Newtonsoft.Json.JsonSerializer serializer)
{
var valueMargin = (Margin)value;
var otherMargin = (Margin)other;
writer.WriteStartObject();
if (!Mathf.NearEqual(valueMargin.Left, otherMargin.Left))
{
writer.WritePropertyName("Left");
writer.WriteValue(valueMargin.Left);
}
if (!Mathf.NearEqual(valueMargin.Right, otherMargin.Right))
{
writer.WritePropertyName("Right");
writer.WriteValue(valueMargin.Right);
}
if (!Mathf.NearEqual(valueMargin.Top, otherMargin.Top))
{
writer.WritePropertyName("Top");
writer.WriteValue(valueMargin.Top);
}
if (!Mathf.NearEqual(valueMargin.Bottom, otherMargin.Bottom))
{
writer.WritePropertyName("Bottom");
writer.WriteValue(valueMargin.Bottom);
}
writer.WriteEndObject();
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var value = (Margin?)existingValue ?? new Margin();
if (reader.TokenType == JsonToken.StartObject)
{
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
{
var propertyName = (string)reader.Value;
reader.Read();
switch (reader.TokenType)
{
case JsonToken.Integer:
case JsonToken.Float:
{
var propertyValue = Convert.ToSingle(reader.Value);
switch (propertyName)
{
case "Left":
value.Left = propertyValue;
break;
case "Right":
value.Right = propertyValue;
break;
case "Top":
value.Top = propertyValue;
break;
case "Bottom":
value.Bottom = propertyValue;
break;
}
break;
}
}
break;
}
case JsonToken.Comment: break;
case JsonToken.String: break;
default: return value;
}
}
}
return value;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Margin);
}
/// <inheritdoc />
public override bool CanRead => true;
/// <inheritdoc />
public override bool CanWrite => true;
/// <inheritdoc />
public override bool CanWriteDiff => true;
}
/// <summary>
/// Serialize <see cref="LocalizedString"/> as inlined text is not using localization (Id member is empty).
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class LocalizedStringConverter : JsonConverter
{
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
#if FLAX_EDITOR
bool writeTypename = (serializer.TypeNameHandling & TypeNameHandling.Objects) == TypeNameHandling.Objects;
#else
bool writeTypename = false;
#endif
var str = (LocalizedString)value;
if (string.IsNullOrEmpty(str.Id) && !writeTypename)
{
writer.WriteValue(str.Value ?? string.Empty);
}
else
{
writer.WriteStartObject();
#if FLAX_EDITOR
if (writeTypename)
{
writer.WritePropertyName("$type");
writer.WriteValue("FlaxEngine.LocalizedString, FlaxEngine.CSharp");
}
#endif
writer.WritePropertyName("Id");
writer.WriteValue(str.Id);
writer.WritePropertyName("Value");
writer.WriteValue(str.Value);
writer.WriteEndObject();
}
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var str = existingValue as LocalizedString ?? new LocalizedString();
if (reader.TokenType == JsonToken.String)
{
str.Id = null;
str.Value = (string)reader.Value;
}
else if (reader.TokenType == JsonToken.StartObject)
{
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
{
var propertyName = (string)reader.Value;
switch (propertyName)
{
case "Id":
str.Id = reader.ReadAsString();
break;
case "Value":
str.Value = reader.ReadAsString();
break;
}
break;
}
case JsonToken.Comment: break;
case JsonToken.String: break;
default: return str;
}
}
}
else
return null;
if (existingValue == null && str.Id == null && str.Value == null)
return null;
return str;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(LocalizedString);
}
}
/// <summary>
/// Serialize <see cref="Tag"/> as inlined text.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class TagConverter : JsonConverter
{
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
var tag = (Tag)value;
writer.WriteValue(tag.ToString());
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
return Tags.Get((string)reader.Value);
return Tag.Default;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Tag);
}
}
/*
/// <summary>
/// Serialize Guid values using `N` format
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
internal class GuidConverter : JsonConverter
{
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
Guid id = (Guid)value;
writer.WriteValue(id.ToString("N"));
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
var id = Guid.Parse((string)reader.Value);
return id;
}
return Guid.Empty;
}
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Guid);
}
}
*/
}