This commit is contained in:
2021-06-13 10:28:03 +02:00
parent eb70603c85
commit df2d24cbd3
7487 changed files with 943244 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
using System;
using UnityEngine;
namespace UnityEditor.ShaderGraph.Serialization
{
[Serializable]
public class FakeJsonObject
{
[SerializeField]
string m_Type;
[SerializeField]
string m_ObjectId;
public string id
{
get => m_ObjectId;
set => m_ObjectId = value;
}
public string type
{
get => m_Type;
set => m_Type = value;
}
public void Reset()
{
m_ObjectId = null;
m_Type = null;
}
}
}

View File

@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.ShaderGraph.Serialization
{
[Serializable]
struct JsonData<T> : ISerializationCallbackReceiver
where T : JsonObject
{
[NonSerialized]
T m_Value;
[SerializeField]
string m_Id;
public T value => m_Value;
public void OnBeforeSerialize()
{
if (MultiJsonInternal.isSerializing && m_Value != null && MultiJsonInternal.serializedSet.Add(m_Id))
{
MultiJsonInternal.serializationQueue.Add(m_Value);
}
}
public void OnAfterDeserialize()
{
if (MultiJsonInternal.isDeserializing)
{
try
{
if (MultiJsonInternal.valueMap.TryGetValue(m_Id, out var value))
{
m_Value = value.CastTo<T>();
// cast may fail for unknown types, but we can still grab the id from the original UnknownType
m_Id = value.objectId;
}
else
{
Debug.LogError($"Missing {typeof(T).FullName} {m_Id}");
}
}
catch (Exception e)
{
// TODO: Allow custom logging function
Debug.LogException(e);
}
}
}
public static implicit operator T(JsonData<T> jsonRef)
{
return jsonRef.m_Value;
}
public static implicit operator JsonData<T>(T value)
{
return new JsonData<T> { m_Value = value, m_Id = value.objectId };
}
public bool Equals(JsonData<T> other)
{
return EqualityComparer<T>.Default.Equals(m_Value, other.m_Value);
}
public bool Equals(T other)
{
return EqualityComparer<T>.Default.Equals(m_Value, other);
}
public override bool Equals(object obj)
{
return obj is JsonData<T> other && Equals(other) || obj is T otherValue && Equals(otherValue);
}
public override int GetHashCode()
{
return EqualityComparer<T>.Default.GetHashCode(m_Value);
}
public static bool operator==(JsonData<T> left, JsonData<T> right)
{
return left.value == right.value;
}
public static bool operator!=(JsonData<T> left, JsonData<T> right)
{
return left.value != right.value;
}
public static bool operator==(JsonData<T> left, T right)
{
return left.value == right;
}
public static bool operator!=(JsonData<T> left, T right)
{
return left.value != right;
}
public static bool operator==(T left, JsonData<T> right)
{
return left == right.value;
}
public static bool operator!=(T left, JsonData<T> right)
{
return left != right.value;
}
public static bool operator==(JsonData<T> left, JsonRef<T> right)
{
return left.value == right.value;
}
public static bool operator!=(JsonData<T> left, JsonRef<T> right)
{
return left.value != right.value;
}
public static bool operator==(JsonRef<T> left, JsonData<T> right)
{
return left.value == right.value;
}
public static bool operator!=(JsonRef<T> left, JsonData<T> right)
{
return left.value != right.value;
}
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
namespace UnityEditor.ShaderGraph.Serialization
{
[Serializable]
public class JsonObject : ISerializationCallbackReceiver
{
public virtual int latestVersion { get; } = 0;
[SerializeField]
protected int m_SGVersion = 0;
public virtual int sgVersion { get => m_SGVersion; protected set => m_SGVersion = value; }
internal protected delegate void VersionChange(int newVersion);
internal protected VersionChange onBeforeVersionChange;
internal protected Action onAfterVersionChange;
internal void ChangeVersion(int newVersion)
{
if (newVersion == sgVersion)
{
return;
}
if (newVersion < 0)
{
Debug.LogError("Cant downgrade past version 0");
return;
}
if (newVersion > latestVersion)
{
Debug.LogError("Cant upgrade to a version >= the current latest version");
return;
}
onBeforeVersionChange?.Invoke(newVersion);
sgVersion = newVersion;
onAfterVersionChange?.Invoke();
}
public JsonObject()
{
sgVersion = latestVersion;
}
public static readonly string emptyObjectId = Guid.Empty.ToString("N");
[SerializeField]
string m_Type;
[SerializeField]
string m_ObjectId = Guid.NewGuid().ToString("N");
internal void OverrideObjectId(string namespaceUid, string newObjectId) { m_ObjectId = GenerateNamespaceUUID(namespaceUid, newObjectId).ToString("N"); }
internal void OverrideObjectId(string newObjectId) { m_ObjectId = newObjectId; }
public string objectId => m_ObjectId;
public bool objectIdIsEmpty => m_ObjectId.Equals(emptyObjectId);
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
m_Type = $"{GetType().FullName}";
OnBeforeSerialize();
}
public virtual T CastTo<T>() where T : JsonObject { return (T)this; }
public virtual string Serialize() { return EditorJsonUtility.ToJson(this, true); }
public virtual void Deserailize(string typeInfo, string jsonData) { EditorJsonUtility.FromJsonOverwrite(jsonData, this); }
public virtual void OnBeforeSerialize() {}
public virtual void OnBeforeDeserialize() {}
public virtual void OnAfterDeserialize() {}
public virtual void OnAfterDeserialize(string json) {}
public virtual void OnAfterMultiDeserialize(string json) {}
internal static Guid GenerateNamespaceUUID(string Namespace, string Name)
{
Guid namespaceGuid;
if (!Guid.TryParse(Namespace, out namespaceGuid))
{
// Fallback namespace in case the one provided is invalid.
// If an object ID was used as the namespace, this shouldn't normally be reachable.
namespaceGuid = new Guid("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
}
return GenerateNamespaceUUID(namespaceGuid, Name);
}
internal static Guid GenerateNamespaceUUID(Guid Namespace, string Name)
{
// Generate a deterministic guid using namespace guids: RFC 4122 §4.3 version 5.
void FlipByNetworkOrder(byte[] bytes)
{ bytes = new byte[] { bytes[3], bytes[2], bytes[1], bytes[0], bytes[5], bytes[4], bytes[7], bytes[6] }; }
var namespaceBytes = Namespace.ToByteArray();
FlipByNetworkOrder(namespaceBytes);
var nameBytes = Encoding.UTF8.GetBytes(Name);
var hash = SHA1.Create().ComputeHash(namespaceBytes.Concat(nameBytes).ToArray());
byte[] newguid = new byte[16];
Array.Copy(hash, newguid, 16);
newguid[6] = (byte)((newguid[6] & 0x0F) | 0x80);
newguid[8] = (byte)((newguid[8] & 0x3F) | 0x80);
FlipByNetworkOrder(newguid);
return new Guid(newguid);
}
}
}

View File

@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.ShaderGraph.Serialization
{
[Serializable]
struct JsonRef<T> : ISerializationCallbackReceiver
where T : JsonObject
{
[NonSerialized]
T m_Value;
[SerializeField]
string m_Id;
public T value => m_Value;
public void OnBeforeSerialize()
{
}
public void OnAfterDeserialize()
{
if (MultiJsonInternal.isDeserializing)
{
try
{
if (MultiJsonInternal.valueMap.TryGetValue(m_Id, out var value))
{
m_Value = value.CastTo<T>();
m_Id = m_Value.objectId;
}
else
{
m_Value = null;
m_Id = null;
}
}
catch (Exception e)
{
Debug.LogException(e);
}
}
}
public static implicit operator T(JsonRef<T> jsonRef)
{
return jsonRef.m_Value;
}
public static implicit operator JsonRef<T>(T value)
{
return new JsonRef<T> { m_Value = value, m_Id = value?.objectId };
}
public bool Equals(JsonRef<T> other)
{
return EqualityComparer<T>.Default.Equals(m_Value, other.m_Value);
}
public bool Equals(T other)
{
return EqualityComparer<T>.Default.Equals(m_Value, other);
}
public override bool Equals(object obj)
{
return obj is JsonRef<T> other && Equals(other) || obj is T otherValue && Equals(otherValue);
}
public override int GetHashCode()
{
return EqualityComparer<T>.Default.GetHashCode(m_Value);
}
public static bool operator==(JsonRef<T> left, JsonRef<T> right)
{
return left.value == right.value;
}
public static bool operator!=(JsonRef<T> left, JsonRef<T> right)
{
return left.value != right.value;
}
public static bool operator==(JsonRef<T> left, T right)
{
return left.value == right;
}
public static bool operator!=(JsonRef<T> left, T right)
{
return left.value != right;
}
public static bool operator==(T left, JsonRef<T> right)
{
return left == right.value;
}
public static bool operator!=(T left, JsonRef<T> right)
{
return left != right.value;
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using UnityEngine;
namespace UnityEditor.ShaderGraph.Serialization
{
static class MultiJson
{
public static void Deserialize<T>(T objectToOverwrite, string json, JsonObject referenceRoot = null, bool rewriteIds = false) where T : JsonObject
{
var entries = MultiJsonInternal.Parse(json);
if (referenceRoot != null)
{
MultiJsonInternal.PopulateValueMap(referenceRoot);
}
MultiJsonInternal.Deserialize(objectToOverwrite, entries, rewriteIds);
}
public static string Serialize(JsonObject mainObject)
{
return MultiJsonInternal.Serialize(mainObject);
}
public static Type ParseType(string typeString)
{
return MultiJsonInternal.ParseType(typeString);
}
}
}

View File

@@ -0,0 +1,42 @@
namespace UnityEditor.ShaderGraph.Serialization
{
struct MultiJsonEntry
{
public string id { get; }
public string type { get; }
public string json { get; }
public MultiJsonEntry(string type, string id, string json)
{
this.id = id;
this.type = type;
this.json = json;
}
public bool Equals(MultiJsonEntry other)
{
return id == other.id && type == other.type && json == other.json;
}
public override bool Equals(object obj)
{
return obj is MultiJsonEntry other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (id != null ? id.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (type != null ? type.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (json != null ? json.GetHashCode() : 0);
return hashCode;
}
}
public override string ToString()
{
return $"{nameof(id)}: {id}, {nameof(type)}: {type}, {nameof(json)}:\n{json}";
}
}
}

View File

@@ -0,0 +1,727 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor.ShaderGraph.Internal;
using UnityEditor.Graphing;
namespace UnityEditor.ShaderGraph.Serialization
{
static class MultiJsonInternal
{
#region Unknown Data Handling
public class UnknownJsonObject : JsonObject
{
public string typeInfo;
public string jsonData;
public JsonData<JsonObject> castedObject;
public UnknownJsonObject(string typeInfo)
{
this.typeInfo = typeInfo;
}
public override void Deserailize(string typeInfo, string jsonData)
{
this.jsonData = jsonData;
}
public override string Serialize()
{
return jsonData;
}
public override void OnAfterDeserialize(string json)
{
if (castedObject.value != null)
{
Enqueue(castedObject, json.Trim());
}
}
public override void OnAfterMultiDeserialize(string json)
{
if (castedObject.value == null)
{
//Never got casted so nothing ever reffed this object
//likely that some other unknown json object had a ref
//to this thing. Need to include it in the serialization
//step of the object still.
if (jsonBlobs.TryGetValue(currentRoot.objectId, out var blobs))
{
blobs[objectId] = jsonData.Trim();
}
else
{
var lookup = new Dictionary<string, string>();
lookup[objectId] = jsonData.Trim();
jsonBlobs.Add(currentRoot.objectId, lookup);
}
}
}
public override T CastTo<T>()
{
if (castedObject.value != null)
return castedObject.value.CastTo<T>();
Type t = typeof(T);
if (t == typeof(AbstractMaterialNode) || t.IsSubclassOf(typeof(AbstractMaterialNode)))
{
UnknownNodeType unt = new UnknownNodeType(jsonData);
valueMap[objectId] = unt;
s_ObjectIdField.SetValue(unt, objectId);
castedObject = unt;
return unt.CastTo<T>();
}
else if (t == typeof(Target) || t.IsSubclassOf(typeof(Target)))
{
UnknownTargetType utt = new UnknownTargetType(typeInfo, jsonData);
valueMap[objectId] = utt;
s_ObjectIdField.SetValue(utt, objectId);
castedObject = utt;
return utt.CastTo<T>();
}
else if (t == typeof(SubTarget) || t.IsSubclassOf(typeof(SubTarget)))
{
UnknownSubTargetType ustt = new UnknownSubTargetType(typeInfo, jsonData);
valueMap[objectId] = ustt;
s_ObjectIdField.SetValue(ustt, objectId);
castedObject = ustt;
return ustt.CastTo<T>();
}
else if (t == typeof(ShaderInput) || t.IsSubclassOf(typeof(ShaderInput)))
{
UnknownShaderPropertyType usp = new UnknownShaderPropertyType(typeInfo, jsonData);
valueMap[objectId] = usp;
s_ObjectIdField.SetValue(usp, objectId);
castedObject = usp;
return usp.CastTo<T>();
}
else if (t == typeof(MaterialSlot) || t.IsSubclassOf(typeof(MaterialSlot)))
{
UnknownMaterialSlotType umst = new UnknownMaterialSlotType(typeInfo, jsonData);
valueMap[objectId] = umst;
s_ObjectIdField.SetValue(umst, objectId);
castedObject = umst;
return umst.CastTo<T>();
}
else
{
Debug.LogError($"Unable to evaluate type {typeInfo} : {jsonData}");
}
return null;
}
}
public class UnknownTargetType : Target
{
public string jsonData;
public UnknownTargetType() : base()
{
isHidden = true;
}
private List<BlockFieldDescriptor> m_activeBlocks = null;
public UnknownTargetType(string displayName, string jsonData)
{
var split = displayName.Split('.');
var last = split[split.Length - 1];
this.displayName = last.Replace("Target", "") + " (Unknown)";
isHidden = false;
this.jsonData = jsonData;
}
public override void Deserailize(string typeInfo, string jsonData)
{
this.jsonData = jsonData;
base.Deserailize(typeInfo, jsonData);
}
public override string Serialize()
{
return jsonData.Trim();
}
//When we first call GetActiveBlocks, we assume any unknown blockfielddescriptors are owned by this target
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
{
if (m_activeBlocks == null)
{
m_activeBlocks = new List<BlockFieldDescriptor>();
foreach (var cur in context.currentBlocks)
{
if (cur.isUnknown && !string.IsNullOrEmpty(cur.displayName))
{
m_activeBlocks.Add(cur);
}
}
}
foreach (var block in m_activeBlocks)
{
context.AddBlock(block);
}
}
public override void GetFields(ref TargetFieldContext context)
{
}
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<string> registerUndo)
{
context.AddHelpBox(MessageType.Warning, "Cannot find the code for this Target, a package may be missing.");
}
public override bool IsActive() => false;
public override void Setup(ref TargetSetupContext context)
{
}
public override bool WorksWithSRP(RenderPipelineAsset scriptableRenderPipeline) => false;
}
private class UnknownSubTargetType : SubTarget
{
public string jsonData;
public UnknownSubTargetType() : base()
{
isHidden = true;
}
public UnknownSubTargetType(string displayName, string jsonData) : base()
{
isHidden = false;
this.displayName = displayName;
this.jsonData = jsonData;
}
public override void Deserailize(string typeInfo, string jsonData)
{
this.jsonData = jsonData;
base.Deserailize(typeInfo, jsonData);
}
public override string Serialize()
{
return jsonData.Trim();
}
internal override Type targetType => typeof(UnknownTargetType);
public override void GetActiveBlocks(ref TargetActiveBlockContext context)
{
}
public override void GetFields(ref TargetFieldContext context)
{
}
public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<string> registerUndo)
{
context.AddHelpBox(MessageType.Warning, "Cannot find the code for this SubTarget, a package may be missing.");
}
public override bool IsActive() => false;
public override void Setup(ref TargetSetupContext context)
{
}
}
internal class UnknownShaderPropertyType : AbstractShaderProperty
{
public string jsonData;
public UnknownShaderPropertyType(string displayName, string jsonData) : base()
{
this.displayName = displayName;
this.jsonData = jsonData;
}
public override void Deserailize(string typeInfo, string jsonData)
{
this.jsonData = jsonData;
base.Deserailize(typeInfo, jsonData);
}
public override string Serialize()
{
return jsonData.Trim();
}
internal override ConcreteSlotValueType concreteShaderValueType => ConcreteSlotValueType.Vector1;
internal override bool isExposable => false;
internal override bool isRenamable => false;
internal override ShaderInput Copy()
{
// we CANNOT copy ourselves, as the serialized GUID in the jsonData would not match the json GUID
return null;
}
public override PropertyType propertyType => PropertyType.Float;
internal override void GetPropertyReferenceNames(List<string> result) {}
internal override void GetPropertyDisplayNames(List<string> result) {}
internal override string GetPropertyBlockString() { return ""; }
internal override void AppendPropertyBlockStrings(ShaderStringBuilder builder)
{
builder.AppendLine("/* UNKNOWN PROPERTY: " + referenceName + " */");
}
internal override bool AllowHLSLDeclaration(HLSLDeclaration decl) => false;
internal override void ForeachHLSLProperty(Action<HLSLProperty> action)
{
action(new HLSLProperty(HLSLType._float, referenceName, HLSLDeclaration.Global, concretePrecision));
}
internal override string GetPropertyAsArgumentString() { return ""; }
internal override AbstractMaterialNode ToConcreteNode() { return null; }
internal override PreviewProperty GetPreviewMaterialProperty()
{
return new PreviewProperty(propertyType)
{
name = referenceName,
floatValue = 0.0f
};
}
public override string GetPropertyTypeString() { return ""; }
}
internal class UnknownMaterialSlotType : MaterialSlot
{
// used to deserialize some data out of an unknown MaterialSlot
class SerializerHelper
{
[SerializeField]
public string m_DisplayName = null;
[SerializeField]
public SlotType m_SlotType = SlotType.Input;
[SerializeField]
public bool m_Hidden = false;
[SerializeField]
public string m_ShaderOutputName = null;
[SerializeField]
public ShaderStageCapability m_StageCapability = ShaderStageCapability.All;
}
public string jsonData;
public UnknownMaterialSlotType(string displayName, string jsonData) : base()
{
// copy some minimal information to try to keep the UI as similar as possible
var helper = new SerializerHelper();
JsonUtility.FromJsonOverwrite(jsonData, helper);
this.displayName = helper.m_DisplayName;
this.hidden = helper.m_Hidden;
this.stageCapability = helper.m_StageCapability;
this.SetInternalData(helper.m_SlotType, helper.m_ShaderOutputName);
// save the original json for saving
this.jsonData = jsonData;
}
public override void Deserailize(string typeInfo, string jsonData)
{
this.jsonData = jsonData;
base.Deserailize(typeInfo, jsonData);
}
public override string Serialize()
{
return jsonData.Trim();
}
public override bool isDefaultValue => true;
public override SlotValueType valueType => SlotValueType.Vector1;
public override ConcreteSlotValueType concreteValueType => ConcreteSlotValueType.Vector1;
public override void AddDefaultProperty(PropertyCollector properties, GenerationMode generationMode) {}
public override void CopyValuesFrom(MaterialSlot foundSlot)
{
// we CANNOT copy data from another slot, as the GUID in the serialized jsonData would not match our real GUID
throw new NotSupportedException();
}
}
[NeverAllowedByTarget]
internal class UnknownNodeType : AbstractMaterialNode
{
public string jsonData;
public UnknownNodeType() : base()
{
jsonData = null;
isValid = false;
SetOverrideActiveState(ActiveState.ExplicitInactive, false);
SetActive(false, false);
}
public UnknownNodeType(string jsonData)
{
this.jsonData = jsonData;
isValid = false;
SetOverrideActiveState(ActiveState.ExplicitInactive, false);
SetActive(false, false);
}
public override void OnAfterDeserialize(string json)
{
jsonData = json;
base.OnAfterDeserialize(json);
}
public override string Serialize()
{
EnqueSlotsForSerialization();
return jsonData.Trim();
}
public override void ValidateNode()
{
base.ValidateNode();
owner.AddValidationError(objectId, "This node type could not be found. No function will be generated in the shader.", ShaderCompilerMessageSeverity.Warning);
}
// unknown node types cannot be copied, or else their GUID would not match the GUID in the serialized jsonDAta
public override bool canCutNode => false;
public override bool canCopyNode => false;
}
#endregion //Unknown Data Handling
static readonly Dictionary<string, Type> k_TypeMap = CreateTypeMap();
internal static bool isDeserializing;
internal static readonly Dictionary<string, JsonObject> valueMap = new Dictionary<string, JsonObject>();
static List<MultiJsonEntry> s_Entries;
internal static bool isSerializing;
internal static readonly List<JsonObject> serializationQueue = new List<JsonObject>();
internal static readonly HashSet<string> serializedSet = new HashSet<string>();
static JsonObject currentRoot = null;
static Dictionary<string, Dictionary<string, string>> jsonBlobs = new Dictionary<string, Dictionary<string, string>>();
static Dictionary<string, Type> CreateTypeMap()
{
var map = new Dictionary<string, Type>();
foreach (var type in TypeCache.GetTypesDerivedFrom<JsonObject>())
{
if (type.FullName != null)
{
map[type.FullName] = type;
}
}
foreach (var type in TypeCache.GetTypesWithAttribute(typeof(FormerNameAttribute)))
{
if (type.IsAbstract || !typeof(JsonObject).IsAssignableFrom(type))
{
continue;
}
foreach (var attribute in type.GetCustomAttributes(typeof(FormerNameAttribute), false))
{
var legacyAttribute = (FormerNameAttribute)attribute;
map[legacyAttribute.fullName] = type;
}
}
return map;
}
public static Type ParseType(string typeString)
{
k_TypeMap.TryGetValue(typeString, out var type);
return type;
}
public static List<MultiJsonEntry> Parse(string str)
{
var result = new List<MultiJsonEntry>();
const string separatorStr = "\n\n";
var startIndex = 0;
var raw = new FakeJsonObject();
while (startIndex < str.Length)
{
var jsonBegin = str.IndexOf("{", startIndex, StringComparison.Ordinal);
if (jsonBegin == -1)
{
break;
}
var jsonEnd = str.IndexOf(separatorStr, jsonBegin, StringComparison.Ordinal);
if (jsonEnd == -1)
{
jsonEnd = str.IndexOf("\n\r\n", jsonBegin, StringComparison.Ordinal);
if (jsonEnd == -1)
{
jsonEnd = str.LastIndexOf("}", StringComparison.Ordinal) + 1;
}
}
var json = str.Substring(jsonBegin, jsonEnd - jsonBegin);
JsonUtility.FromJsonOverwrite(json, raw);
if (startIndex != 0 && string.IsNullOrWhiteSpace(raw.type))
{
throw new InvalidOperationException($"Type is null or whitespace in JSON:\n{json}");
}
result.Add(new MultiJsonEntry(raw.type, raw.id, json));
raw.Reset();
startIndex = jsonEnd + separatorStr.Length;
}
return result;
}
public static void Enqueue(JsonObject jsonObject, string json)
{
if (s_Entries == null)
{
throw new InvalidOperationException("Can only Enqueue during JsonObject.OnAfterDeserialize.");
}
valueMap.Add(jsonObject.objectId, jsonObject);
s_Entries.Add(new MultiJsonEntry(jsonObject.GetType().FullName, jsonObject.objectId, json));
}
public static JsonObject CreateInstanceForDeserialization(string typeString)
{
if (!k_TypeMap.TryGetValue(typeString, out var type))
{
return new UnknownJsonObject(typeString);
}
var output = (JsonObject)Activator.CreateInstance(type, true);
//This CreateInstance function is supposed to essentially create a blank copy of whatever class we end up deserializing into.
//when we typically create new JsonObjects in all other cases, we want that object to be assumed to be the latest version.
//This doesn't work if any json object was serialized before we had the idea of version, as the blank copy would have the
//latest version on creation and since the serialized version wouldn't have a version member, it would not get overwritten
//and we would automatically upgrade all previously serialized json objects incorrectly and without user action. To avoid this,
//we default jsonObject version to 0, and if the serialized value has a different saved version it gets changed and if the serialized
//version does not have a different saved value it remains 0 (earliest version)
output.ChangeVersion(0);
output.OnBeforeDeserialize();
return output;
}
private static FieldInfo s_ObjectIdField =
typeof(JsonObject).GetField("m_ObjectId", BindingFlags.Instance | BindingFlags.NonPublic);
public static void Deserialize(JsonObject root, List<MultiJsonEntry> entries, bool rewriteIds)
{
if (isDeserializing)
{
throw new InvalidOperationException("Nested MultiJson deserialization is not supported.");
}
try
{
isDeserializing = true;
currentRoot = root;
root.ChangeVersion(0); //Same issue as described in CreateInstance
for (var index = 0; index < entries.Count; index++)
{
var entry = entries[index];
try
{
JsonObject value = null;
if (index == 0)
{
value = root;
}
else
{
value = CreateInstanceForDeserialization(entry.type);
}
var id = entry.id;
if (id != null)
{
// Need to make sure that references looking for the old ID will find it in spite of
// ID rewriting.
valueMap[id] = value;
}
if (rewriteIds || entry.id == null)
{
id = value.objectId;
entries[index] = new MultiJsonEntry(entry.type, id, entry.json);
valueMap[id] = value;
}
s_ObjectIdField.SetValue(value, id);
}
catch (Exception e)
{
// External code could throw exceptions, but we don't want that to fail the whole thing.
// Potentially, the fallback type should also be used here.
Debug.LogException(e);
}
}
s_Entries = entries;
// Not a foreach because `entries` can be populated by calls to `Enqueue` as we go.
for (var i = 0; i < entries.Count; i++)
{
var entry = entries[i];
try
{
var value = valueMap[entry.id];
value.Deserailize(entry.type, entry.json);
// Set ID again as it could be overwritten from JSON.
s_ObjectIdField.SetValue(value, entry.id);
value.OnAfterDeserialize(entry.json);
}
catch (Exception e)
{
if (!String.IsNullOrEmpty(entry.id))
{
var value = valueMap[entry.id];
if (value != null)
{
Debug.LogError($"Exception thrown while deserialize object of type {entry.type}: {e.Message}");
}
}
Debug.LogException(e);
}
}
s_Entries = null;
foreach (var entry in entries)
{
try
{
var value = valueMap[entry.id];
value.OnAfterMultiDeserialize(entry.json);
}
catch (Exception e)
{
Debug.LogException(e);
}
}
}
finally
{
valueMap.Clear();
currentRoot = null;
isDeserializing = false;
}
}
public static string Serialize(JsonObject mainObject)
{
if (isSerializing)
{
throw new InvalidOperationException("Nested MultiJson serialization is not supported.");
}
try
{
isSerializing = true;
serializedSet.Add(mainObject.objectId);
serializationQueue.Add(mainObject);
var idJsonList = new List<(string, string)>();
// Not a foreach because the queue is populated by `JsonData<T>`s as we go.
for (var i = 0; i < serializationQueue.Count; i++)
{
var value = serializationQueue[i];
var json = value.Serialize();
idJsonList.Add((value.objectId, json));
}
if (jsonBlobs.TryGetValue(mainObject.objectId, out var blobs))
{
foreach (var blob in blobs)
{
if (!idJsonList.Contains((blob.Key, blob.Value)))
idJsonList.Add((blob.Key, blob.Value));
}
}
idJsonList.Sort((x, y) =>
// Main object needs to be placed first
x.Item1 == mainObject.objectId ? -1 :
y.Item1 == mainObject.objectId ? 1 :
// We sort everything else by ID to consistently maintain positions in the output
x.Item1.CompareTo(y.Item1));
const string k_NewLineString = "\n";
var sb = new StringBuilder();
foreach (var(id, json) in idJsonList)
{
sb.Append(json);
sb.Append(k_NewLineString);
sb.Append(k_NewLineString);
}
return sb.ToString();
}
finally
{
serializationQueue.Clear();
serializedSet.Clear();
isSerializing = false;
}
}
public static void PopulateValueMap(JsonObject mainObject)
{
if (isSerializing)
{
throw new InvalidOperationException("Nested MultiJson serialization is not supported.");
}
try
{
isSerializing = true;
serializedSet.Add(mainObject.objectId);
serializationQueue.Add(mainObject);
// Not a foreach because the queue is populated by `JsonRef<T>`s as we go.
for (var i = 0; i < serializationQueue.Count; i++)
{
var value = serializationQueue[i];
value.Serialize();
valueMap[value.objectId] = value;
}
}
finally
{
serializationQueue.Clear();
serializedSet.Clear();
isSerializing = false;
}
}
}
}

View File

@@ -0,0 +1,47 @@
using System.Collections;
using System.Collections.Generic;
namespace UnityEditor.ShaderGraph.Serialization
{
struct DataValueEnumerable<T> : IEnumerable<T>
where T : JsonObject
{
List<JsonData<T>> m_List;
public DataValueEnumerable(List<JsonData<T>> list)
{
m_List = list;
}
public void Sort(System.Comparison<T> comparison)
{
m_List?.Sort((a, b) => comparison(a.value, b.value));
}
public Enumerator GetEnumerator() => new Enumerator(m_List.GetEnumerator());
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public struct Enumerator : IEnumerator<T>
{
List<JsonData<T>>.Enumerator m_Enumerator;
public Enumerator(List<JsonData<T>>.Enumerator enumerator)
{
m_Enumerator = enumerator;
}
public bool MoveNext() => m_Enumerator.MoveNext();
void IEnumerator.Reset() => ((IEnumerator)m_Enumerator).Reset();
public T Current => m_Enumerator.Current.value;
object IEnumerator.Current => Current;
public void Dispose() => m_Enumerator.Dispose();
}
}
}

View File

@@ -0,0 +1,42 @@
using System.Collections;
using System.Collections.Generic;
namespace UnityEditor.ShaderGraph.Serialization
{
struct RefValueEnumerable<T> : IEnumerable<T>
where T : JsonObject
{
List<JsonRef<T>> m_List;
public RefValueEnumerable(List<JsonRef<T>> list)
{
m_List = list;
}
public Enumerator GetEnumerator() => new Enumerator(m_List.GetEnumerator());
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public struct Enumerator : IEnumerator<T>
{
List<JsonRef<T>>.Enumerator m_Enumerator;
public Enumerator(List<JsonRef<T>>.Enumerator enumerator)
{
m_Enumerator = enumerator;
}
public bool MoveNext() => m_Enumerator.MoveNext();
void IEnumerator.Reset() => ((IEnumerator)m_Enumerator).Reset();
public T Current => m_Enumerator.Current.value;
object IEnumerator.Current => Current;
public void Dispose() => m_Enumerator.Dispose();
}
}
}

View File

@@ -0,0 +1,40 @@
using System.Collections.Generic;
namespace UnityEditor.ShaderGraph.Serialization
{
static class SerializationExtensions
{
public static RefValueEnumerable<T> SelectValue<T>(this List<JsonRef<T>> list) where T : JsonObject =>
new RefValueEnumerable<T>(list);
public static DataValueEnumerable<T> SelectValue<T>(this List<JsonData<T>> list) where T : JsonObject =>
new DataValueEnumerable<T>(list);
public static void AddRange<T>(this List<JsonRef<T>> list, IEnumerable<T> enumerable)
where T : JsonObject
{
foreach (var jsonObject in enumerable)
{
list.Add(jsonObject);
}
}
public static void AddRange<T>(this List<JsonRef<T>> list, List<T> enumerable)
where T : JsonObject
{
foreach (var jsonObject in enumerable)
{
list.Add(jsonObject);
}
}
public static void AddRange<T>(this List<T> list, List<JsonRef<T>> enumerable)
where T : JsonObject
{
foreach (var jsonObject in enumerable)
{
list.Add(jsonObject);
}
}
}
}