// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; using FlaxEngine.GUI; using Newtonsoft.Json; namespace FlaxEngine.Json { /// /// Serialize references to the as Guid. /// /// internal class FlaxObjectConverter : JsonConverter { /// 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)); } /// 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; } /// 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); } } /// /// Serialize as Guid in internal format. /// /// internal class SceneReferenceConverter : JsonConverter { /// public override unsafe void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { Guid id = ((SceneReference)value).ID; writer.WriteValue(JsonSerializer.GetStringID(&id)); } /// 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; } /// public override bool CanConvert(Type objectType) { return objectType == typeof(SceneReference); } } /// /// Serialize as Guid in internal format. /// /// internal class SoftObjectReferenceConverter : JsonConverter { /// public override unsafe void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { var id = ((SoftObjectReference)value).ID; writer.WriteValue(JsonSerializer.GetStringID(&id)); } /// 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; } /// public override bool CanConvert(Type objectType) { return objectType == typeof(SoftObjectReference); } } /// /// Serialize as typename string in internal format. /// /// internal class SoftTypeReferenceConverter : JsonConverter { /// public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { writer.WriteValue(((SoftTypeReference)value).TypeName); } /// 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; } /// public override bool CanConvert(Type objectType) { return objectType == typeof(SoftTypeReference); } } /// /// Serialize as Guid in internal format. /// /// internal class MarginConverter : JsonConverter { /// 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(); } /// 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(); } /// 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; } /// public override bool CanConvert(Type objectType) { return objectType == typeof(Margin); } /// public override bool CanRead => true; /// public override bool CanWrite => true; /// public override bool CanWriteDiff => true; } /// /// Serialize as inlined text is not using localization (Id member is empty). /// /// internal class LocalizedStringConverter : JsonConverter { /// 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(); } } /// 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; } /// public override bool CanConvert(Type objectType) { return objectType == typeof(LocalizedString); } } /// /// Serialize as inlined text. /// /// internal class TagConverter : JsonConverter { /// public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { var tag = (Tag)value; writer.WriteValue(tag.ToString()); } /// 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; } /// public override bool CanConvert(Type objectType) { return objectType == typeof(Tag); } } /* /// /// Serialize Guid values using `N` format /// /// internal class GuidConverter : JsonConverter { /// public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { Guid id = (Guid)value; writer.WriteValue(id.ToString("N")); } /// 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; } /// public override bool CanConvert(Type objectType) { return objectType == typeof(Guid); } } */ }