testss
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user