using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using UnityEditor.ShaderGraph.Serialization; using UnityEngine; namespace UnityEditor.Graphing { static class SerializationHelper { [Serializable] public struct TypeSerializationInfo { [SerializeField] public string fullName; public bool IsValid() { return !string.IsNullOrEmpty(fullName); } } [Serializable] public struct JSONSerializedElement { [SerializeField] public TypeSerializationInfo typeInfo; [SerializeField] public string JSONnodeData; } public static JSONSerializedElement nullElement { get { return new JSONSerializedElement(); } } public static TypeSerializationInfo GetTypeSerializableAsString(Type type) { return new TypeSerializationInfo { fullName = type.FullName }; } static Type GetTypeFromSerializedString(TypeSerializationInfo typeInfo) { if (!typeInfo.IsValid()) return null; var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { var type = assembly.GetType(typeInfo.fullName); if (type != null) return type; } return null; } public static JSONSerializedElement Serialize(T item) { if (item is JsonObject jsonObject) return new JSONSerializedElement() { JSONnodeData = jsonObject.Serialize() }; if (item == null) throw new ArgumentNullException("item", "Can not serialize null element"); //check if unknownnode type - if so, return saved metadata //unknown node type will need onbeforeserialize to set guid and edges and all the things var typeInfo = GetTypeSerializableAsString(item.GetType()); var data = JsonUtility.ToJson(item, true); if (string.IsNullOrEmpty(data)) throw new ArgumentException(string.Format("Can not serialize {0}", item)); return new JSONSerializedElement { typeInfo = typeInfo, JSONnodeData = data }; } static TypeSerializationInfo DoTypeRemap(TypeSerializationInfo info, Dictionary remapper) { TypeSerializationInfo foundInfo; if (remapper.TryGetValue(info, out foundInfo)) return foundInfo; return info; } public static T Deserialize(JSONSerializedElement item, Dictionary remapper, params object[] constructorArgs) where T : class { T instance; if (typeof(T) == typeof(JsonObject) || typeof(T).IsSubclassOf(typeof(JsonObject))) { try { var culture = CultureInfo.CurrentCulture; var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; instance = Activator.CreateInstance(typeof(T), flags, null, constructorArgs, culture) as T; } catch (Exception e) { throw new Exception(string.Format("Could not construct instance of: {0}", typeof(T)), e); } MultiJson.Deserialize(instance as JsonObject, item.JSONnodeData); return instance; } if (!item.typeInfo.IsValid() || string.IsNullOrEmpty(item.JSONnodeData)) throw new ArgumentException(string.Format("Can not deserialize {0}, it is invalid", item)); TypeSerializationInfo info = item.typeInfo; info.fullName = info.fullName.Replace("UnityEngine.MaterialGraph", "UnityEditor.ShaderGraph"); info.fullName = info.fullName.Replace("UnityEngine.Graphing", "UnityEditor.Graphing"); if (remapper != null) info = DoTypeRemap(info, remapper); var type = GetTypeFromSerializedString(info); //if type is null but T is an abstract material node, instead we create an unknowntype node if (type == null) { throw new ArgumentException(string.Format("Can not deserialize ({0}), type is invalid", info.fullName)); } try { var culture = CultureInfo.CurrentCulture; var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; instance = Activator.CreateInstance(type, flags, null, constructorArgs, culture) as T; } catch (Exception e) { throw new Exception(string.Format("Could not construct instance of: {0}", type), e); } if (instance != null) { JsonUtility.FromJsonOverwrite(item.JSONnodeData, instance); return instance; } Debug.Log("UhOh"); return null; } public static List Serialize(IEnumerable list) { var result = new List(); if (list == null) return result; foreach (var element in list) { try { result.Add(Serialize(element)); } catch (Exception e) { Debug.LogException(e); } } return result; } public static List Deserialize(IEnumerable list, Dictionary remapper, params object[] constructorArgs) where T : class { var result = new List(); if (list == null) return result; foreach (var element in list) { try { result.Add(Deserialize(element, remapper)); } catch (Exception e) { Debug.LogException(e); Debug.LogError(element.JSONnodeData); } } return result; } } }