如何通过GUID自定义序列化GameObject引用?

时间:2016-09-30 15:23:51

标签: c# unity3d json.net

我正在使用JSON .NET为Unity3D游戏编写自定义序列化程序。我们可以有一些GameObject类型的字段,它是一个Unity3D内部类,它将引用游戏中的资源资源。我们需要能够仅通过其'GUID字符串序列化GameObject属性。使用此信息,我们可以利用Unity3D的AssetDatabase来检索资产并将其加载到属性中。

public class Blueprint {
    public IList<IComponent> Components = new List<IComponent>();
}

public class UnityPrefabs : IComponent {
    public GameObject ViewPrefab;
    public GameObject ModelPrefab;
}

我用于使用JSON .NET序列化的方法:

public void Serialize(Blueprint blueprint) {
    blueprintData = JsonConvert.SerializeObject(blueprint, Formatting.Indented,
        new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.All,
            Converters = new List<JsonConverter>() { new UnityPrefabConverter() },
            //ContractResolver = new ConverterContractResolver()
        });
}

public Blueprint Deserialize() {
    var blueprint = string.IsNullOrEmpty(blueprintData)
        ? new Blueprint() : JsonConvert.DeserializeObject<Blueprint>(blueprintData,
        new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.All,
            //TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
            NullValueHandling = NullValueHandling.Include,
            Converters = new List<JsonConverter>() { new UnityPrefabConverter() },
        });
    return blueprint;
}

我确实尝试编写自定义转换器,但没有调用Write()方法,只有Read()是:

public class UnityPrefabConverter : JsonConverter {
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var go = value as GameObject;
        var guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(go));

        writer.WriteValue(guid);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        Debug.Log("Reading json");
        if (existingValue == null) return null;

        return AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(existingValue as string));
    }

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(GameObject));
    }
}

我现在能找到的唯一奇怪的是它没有为GameObject字段序列化JSON中的类型:

{\r\n \"$type\": \"CubeBasic.Model.UnityPrefabs, Assembly-CSharp\",\r\n \ \"ViewPrefab\": \"\",\r\n \"ModelPrefab\": null\r\n }\r\n \ ]\r\n }\r\n}"

2 个答案:

答案 0 :(得分:1)

您应该尝试使用Newtonsoft(可以将其作为Nuget包添加到项目中),然后编写一个通用的JSonSerializer类

using Newtonsoft.Json;

public class JSonSerializer : IObjectSerializer
{
    public string ToJson<T>(T obj)
    {
        return JsonConvert.SerializeObject(obj);
    }

    public T FromJson<T>(string json)
    {
        try
        {
            return JsonConvert.DeserializeObject<T>(json);
        }
        catch(JsonReaderException e)
        {
            throw new ObjectSerializationException(e);
        }
    }
}

答案 1 :(得分:1)

您的转换器未被调用,因为在序列化期间,objectType是被序列化的GameObject的实际类型,因此是GameObject的子类型。修改CanConvert以使用Type.IsAssignableFrom(Type)

public override bool CanConvert(Type objectType)
{
    return typeof(GameObject).IsAssignableFrom(objectType);
}

此外,在您的ReadJson中,您可能不想检查existingValue是否为空,而是您想要这样做:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    Debug.Log("Reading json");
    if (reader.TokenType == JsonToken.Null)
        return null;
    var guid = (string)JToken.Load(reader); // Load the GUID value

    return AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(guid));
}

existingValue是对包含对象的构造函数中预先分配的POCO的引用。

由于您已为JsonConverter编写了自己的GameObject,因此除非您在转换器中明确这样做,否则不会写object types。但是,由于您实际上并未对对象进行反序列化,而只是从某个数据库中获取该对象,因此我认为没有必要。