using UnityEngine; using System; using System.Reflection; // 确保你已经通过 Package Manager 或手动导入了 Newtonsoft.Json using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Object = UnityEngine.Object; // 用于自定义序列化,可选但推荐 public class UnityObjectConverter : JsonConverter { public override void WriteJson(JsonWriter writer, Object value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); } else { // 对于 Unity 对象,最简单的序列化方式是它们的名称。 // 也可以选择序列化 InstanceID 或 Asset Path (在编辑器环境下)。 writer.WriteValue(value.name); // 如果你需要 Asset Path (仅在 Unity 编辑器中可用) // #if UNITY_EDITOR // string path = UnityEditor.AssetDatabase.GetAssetPath(value); // writer.WriteValue(path); // #else // writer.WriteValue(value.name); // #endif } } public override Object ReadJson(JsonReader reader, Type objectType, Object existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) { return null; } string objectIdentifier = reader.Value?.ToString(); if (string.IsNullOrEmpty(objectIdentifier)) { return null; } // 示例反序列化:尝试从 Resources 文件夹加载同名对象 // 这需要你的对象位于 "Resources/" 路径下 // 并且 objectType 必须是正确的目标类型 (如 Sprite, GameObject等) return Resources.Load(objectIdentifier, objectType); // 如果你的对象不是通过 Resources 加载的,你可能需要自定义查找逻辑 // 例如: // if (objectType == typeof(Sprite)) // { // // 假设你有一个方法可以根据名称找到 Sprite Asset // return MyAssetManager.LoadSpriteByName(objectIdentifier); // } // return null; } } public class UnityPropertyContractResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty property = base.CreateProperty(member, memberSerialization); // --- 1. 处理 Unity 数学结构体及其循环引用问题 --- // Vector3, Vector2, Bounds, Rect 都是 struct,但它们的某些属性返回新实例,导致 JsonConvert 误判循环。 if (member.DeclaringType == typeof(Vector3) || member.DeclaringType == typeof(Vector2)) { // 明确忽略 normalized, magnitude, sqrMagnitude 等计算属性 if (member.Name == "normalized" || member.Name == "magnitude" || member.Name == "sqrMagnitude") { property.ShouldSerialize = instance => false; } } else if (member.DeclaringType == typeof(Bounds)) { // Bounds 结构体在内部引用 Vector3,也可能有一些我们不希望序列化的计算属性 // 例如,min/max 可以通过 center 和 extents 计算得出,通常不需单独序列化 if (member.Name == "min" || member.Name == "max") { property.ShouldSerialize = instance => false; } } else if (member.DeclaringType == typeof(Rect)) { // Rect 也有一些计算属性,如果不需要可以忽略 // 例如,xMax, yMax, center, position, size if (member.Name.EndsWith("Max") || member.Name == "center" || member.Name == "position" || member.Name == "size") { property.ShouldSerialize = instance => false; } } // --- 2. 处理 UnityEditor 命名空间中的类型 (在运行时通常不序列化) --- // 这些通常是编辑器专属数据,不应包含在运行时序列化中。 if (property.DeclaringType != null && property.DeclaringType.Namespace != null && property.DeclaringType.Namespace.StartsWith("UnityEditor")) { property.ShouldSerialize = instance => false; } // --- 3. 处理 Unity.Mathematics 命名空间中的类型 (如果有使用 DOTS/Job System) --- // 尽管 Unity.Mathematics 类型通常没有循环引用,但如果你只想序列化原始字段,可以这样做。 // if (property.DeclaringType != null && property.DeclaringType.Namespace != null && property.DeclaringType.Namespace.StartsWith("Unity.Mathematics")) // { /* ... */ } // --- 4. 确保 Unity Object 引用由专门的 Converter 处理,而不是默认序列化器 --- // 虽然我们已经提供了 UnityObjectConverter,但这一步可以作为补充。 // 如果某个属性的类型是 UnityEngine.Object 或其派生,但又没有显式地被 Converter 捕获 // 我们可以禁用其默认序列化,以避免尝试序列化内部数据。 // 但由于我们注册了 UnityObjectConverter,它应该会优先处理。 // 这一部分通常是多余的,除非你的 Converter 只能处理特定的 Unity Object 类型 (例如只处理 Sprite)。 /* if (typeof(Object).IsAssignableFrom(property.PropertyType) && !property.PropertyType.IsPrimitive && !property.PropertyType.IsEnum) { // 除非你有一个针对特定 Unity Object 类型的自定义转换器,否则通常不应该直接序列化它们。 // 这里我们假设 UnityObjectConverter 会处理所有 Object 类型。 // 如果你有特定的 Object 类型需要排除,可以在这里添加逻辑。 } */ return property; } }