Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Test/jsonRule.cs

117 lines
5.8 KiB
C#
Raw Normal View History

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<Object>
{
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;
}
}