Initial Commit

This commit is contained in:
Sebastian Cabrera 2021-08-02 05:44:37 -04:00
parent 53eb92e9af
commit 270ab7d11f
15341 changed files with 700234 additions and 0 deletions

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d9533b5df35dc4eb1ae391f2b0f7fede
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,213 @@
// Copyright Christophe Bertrand.
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Unity.VisualScripting.AssemblyQualifiedNameParser
{
public class ParsedAssemblyQualifiedName
{
public string AssemblyDescriptionString { get; }
public string TypeName { get; private set; }
public string ShortAssemblyName { get; }
public string Version { get; }
public string Culture { get; }
public string PublicKeyToken { get; }
public List<ParsedAssemblyQualifiedName> GenericParameters { get; } = new List<ParsedAssemblyQualifiedName>();
public int GenericParameterCount { get; }
public ParsedAssemblyQualifiedName(string AssemblyQualifiedName)
{
var typeNameLength = AssemblyQualifiedName.Length;
var hasAssemblyDescription = false;
var rootBlock = new Block();
{
var depth = 0;
var currentBlock = rootBlock;
for (var index = 0; index < AssemblyQualifiedName.Length; ++index)
{
var c = AssemblyQualifiedName[index];
if (c == '[')
{
if (AssemblyQualifiedName[index + 1] == ']') // Array type // TODO (LAZLO): This won't detect multidimensional array, but FS can't handle them anyway
{
index++;
}
else
{
if (depth == 0)
{
typeNameLength = index;
}
++depth;
var innerBlock = new Block
{
startIndex = index + 1,
level = depth,
parentBlock = currentBlock
};
currentBlock.innerBlocks.Add(innerBlock);
currentBlock = innerBlock;
}
}
else if (c == ']')
{
currentBlock.endIndex = index - 1;
if (AssemblyQualifiedName[currentBlock.startIndex] != '[')
{
currentBlock.parsedAssemblyQualifiedName = new ParsedAssemblyQualifiedName(AssemblyQualifiedName.Substring(currentBlock.startIndex, index - currentBlock.startIndex));
if (depth == 2)
{
GenericParameters.Add(currentBlock.parsedAssemblyQualifiedName);
}
}
currentBlock = currentBlock.parentBlock;
--depth;
}
else if (depth == 0 && c == ',')
{
typeNameLength = index;
hasAssemblyDescription = true;
break;
}
}
}
TypeName = AssemblyQualifiedName.Substring(0, typeNameLength);
var tickIndex = TypeName.IndexOf('`');
if (tickIndex >= 0)
{
GenericParameterCount = int.Parse(TypeName.Substring(tickIndex + 1));
TypeName = TypeName.Substring(0, tickIndex);
}
if (hasAssemblyDescription)
{
AssemblyDescriptionString = AssemblyQualifiedName.Substring(typeNameLength + 2);
var parts = AssemblyDescriptionString.Split(',')
.Select(x => x.Trim())
.ToList();
Version = LookForPairThenRemove(parts, "Version");
Culture = LookForPairThenRemove(parts, "Culture");
PublicKeyToken = LookForPairThenRemove(parts, "PublicKeyToken");
if (parts.Count > 0)
{
ShortAssemblyName = parts[0];
}
}
}
private class Block
{
internal int startIndex;
internal int endIndex;
internal int level;
internal Block parentBlock;
internal readonly List<Block> innerBlocks = new List<Block>();
internal ParsedAssemblyQualifiedName parsedAssemblyQualifiedName;
}
private static string LookForPairThenRemove(List<string> strings, string Name)
{
for (var istr = 0; istr < strings.Count; istr++)
{
var s = strings[istr];
var i = s.IndexOf(Name);
if (i == 0)
{
var i2 = s.IndexOf('=');
if (i2 > 0)
{
var ret = s.Substring(i2 + 1);
strings.RemoveAt(istr);
return ret;
}
}
}
return null;
}
public void Replace(string oldTypeName, string newTypeName)
{
if (TypeName == oldTypeName)
{
TypeName = newTypeName;
}
foreach (var genericParameter in GenericParameters)
{
genericParameter.Replace(oldTypeName, newTypeName);
}
}
private string ToString(bool includeAssemblyDescription)
{
var sb = new StringBuilder();
sb.Append(TypeName);
if (GenericParameters.Count > 0)
{
sb.Append("`");
sb.Append(GenericParameterCount);
sb.Append("[[");
foreach (var genericParameter in GenericParameters)
{
sb.Append(genericParameter.ToString(true));
}
sb.Append("]]");
}
if (includeAssemblyDescription)
{
sb.Append(", ");
sb.Append(AssemblyDescriptionString);
}
return sb.ToString();
}
public override string ToString()
{
return ToString(false);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5d92a04ad12d04b89acd2055df01a8b2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: febf30edd777246c5afbf74d55f387d7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d987e9d47d9a848d181e7806e6c9013f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 50b35552dbca348bc84a9fcbd885547c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,51 @@
#if !NO_UNITY
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
public static AnimationCurve_DirectConverter Register_AnimationCurve_DirectConverter;
}
public class AnimationCurve_DirectConverter : fsDirectConverter<AnimationCurve>
{
protected override fsResult DoSerialize(AnimationCurve model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "keys", model.keys);
result += SerializeMember(serialized, null, "preWrapMode", model.preWrapMode);
result += SerializeMember(serialized, null, "postWrapMode", model.postWrapMode);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref AnimationCurve model)
{
var result = fsResult.Success;
var t0 = model.keys;
result += DeserializeMember(data, null, "keys", out t0);
model.keys = t0;
var t1 = model.preWrapMode;
result += DeserializeMember(data, null, "preWrapMode", out t1);
model.preWrapMode = t1;
var t2 = model.postWrapMode;
result += DeserializeMember(data, null, "postWrapMode", out t2);
model.postWrapMode = t2;
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new AnimationCurve();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4f71cb511b7b0451c9b23f8b4399ea27
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,47 @@
#if !NO_UNITY
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
public static Bounds_DirectConverter Register_Bounds_DirectConverter;
}
public class Bounds_DirectConverter : fsDirectConverter<Bounds>
{
protected override fsResult DoSerialize(Bounds model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "center", model.center);
result += SerializeMember(serialized, null, "size", model.size);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref Bounds model)
{
var result = fsResult.Success;
var t0 = model.center;
result += DeserializeMember(data, null, "center", out t0);
model.center = t0;
var t1 = model.size;
result += DeserializeMember(data, null, "size", out t1);
model.size = t1;
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new Bounds();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c8baf67a14784077be24b77996cc717
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,46 @@
#if !NO_UNITY
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
public static GUIStyleState_DirectConverter Register_GUIStyleState_DirectConverter;
}
public class GUIStyleState_DirectConverter : fsDirectConverter<GUIStyleState>
{
protected override fsResult DoSerialize(GUIStyleState model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "background", model.background);
result += SerializeMember(serialized, null, "textColor", model.textColor);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref GUIStyleState model)
{
var result = fsResult.Success;
var t0 = model.background;
result += DeserializeMember(data, null, "background", out t0);
model.background = t0;
var t2 = model.textColor;
result += DeserializeMember(data, null, "textColor", out t2);
model.textColor = t2;
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new GUIStyleState();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f0ec7b8aa104e452a82dedb597e2d987
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,166 @@
#if !NO_UNITY
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
public static GUIStyle_DirectConverter Register_GUIStyle_DirectConverter;
}
public class GUIStyle_DirectConverter : fsDirectConverter<GUIStyle>
{
protected override fsResult DoSerialize(GUIStyle model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "active", model.active);
result += SerializeMember(serialized, null, "alignment", model.alignment);
result += SerializeMember(serialized, null, "border", model.border);
result += SerializeMember(serialized, null, "clipping", model.clipping);
result += SerializeMember(serialized, null, "contentOffset", model.contentOffset);
result += SerializeMember(serialized, null, "fixedHeight", model.fixedHeight);
result += SerializeMember(serialized, null, "fixedWidth", model.fixedWidth);
result += SerializeMember(serialized, null, "focused", model.focused);
result += SerializeMember(serialized, null, "font", model.font);
result += SerializeMember(serialized, null, "fontSize", model.fontSize);
result += SerializeMember(serialized, null, "fontStyle", model.fontStyle);
result += SerializeMember(serialized, null, "hover", model.hover);
result += SerializeMember(serialized, null, "imagePosition", model.imagePosition);
result += SerializeMember(serialized, null, "margin", model.margin);
result += SerializeMember(serialized, null, "name", model.name);
result += SerializeMember(serialized, null, "normal", model.normal);
result += SerializeMember(serialized, null, "onActive", model.onActive);
result += SerializeMember(serialized, null, "onFocused", model.onFocused);
result += SerializeMember(serialized, null, "onHover", model.onHover);
result += SerializeMember(serialized, null, "onNormal", model.onNormal);
result += SerializeMember(serialized, null, "overflow", model.overflow);
result += SerializeMember(serialized, null, "padding", model.padding);
result += SerializeMember(serialized, null, "richText", model.richText);
result += SerializeMember(serialized, null, "stretchHeight", model.stretchHeight);
result += SerializeMember(serialized, null, "stretchWidth", model.stretchWidth);
result += SerializeMember(serialized, null, "wordWrap", model.wordWrap);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref GUIStyle model)
{
var result = fsResult.Success;
var t0 = model.active;
result += DeserializeMember(data, null, "active", out t0);
model.active = t0;
var t2 = model.alignment;
result += DeserializeMember(data, null, "alignment", out t2);
model.alignment = t2;
var t3 = model.border;
result += DeserializeMember(data, null, "border", out t3);
model.border = t3;
var t4 = model.clipping;
result += DeserializeMember(data, null, "clipping", out t4);
model.clipping = t4;
var t5 = model.contentOffset;
result += DeserializeMember(data, null, "contentOffset", out t5);
model.contentOffset = t5;
var t6 = model.fixedHeight;
result += DeserializeMember(data, null, "fixedHeight", out t6);
model.fixedHeight = t6;
var t7 = model.fixedWidth;
result += DeserializeMember(data, null, "fixedWidth", out t7);
model.fixedWidth = t7;
var t8 = model.focused;
result += DeserializeMember(data, null, "focused", out t8);
model.focused = t8;
var t9 = model.font;
result += DeserializeMember(data, null, "font", out t9);
model.font = t9;
var t10 = model.fontSize;
result += DeserializeMember(data, null, "fontSize", out t10);
model.fontSize = t10;
var t11 = model.fontStyle;
result += DeserializeMember(data, null, "fontStyle", out t11);
model.fontStyle = t11;
var t12 = model.hover;
result += DeserializeMember(data, null, "hover", out t12);
model.hover = t12;
var t13 = model.imagePosition;
result += DeserializeMember(data, null, "imagePosition", out t13);
model.imagePosition = t13;
var t16 = model.margin;
result += DeserializeMember(data, null, "margin", out t16);
model.margin = t16;
var t17 = model.name;
result += DeserializeMember(data, null, "name", out t17);
model.name = t17;
var t18 = model.normal;
result += DeserializeMember(data, null, "normal", out t18);
model.normal = t18;
var t19 = model.onActive;
result += DeserializeMember(data, null, "onActive", out t19);
model.onActive = t19;
var t20 = model.onFocused;
result += DeserializeMember(data, null, "onFocused", out t20);
model.onFocused = t20;
var t21 = model.onHover;
result += DeserializeMember(data, null, "onHover", out t21);
model.onHover = t21;
var t22 = model.onNormal;
result += DeserializeMember(data, null, "onNormal", out t22);
model.onNormal = t22;
var t23 = model.overflow;
result += DeserializeMember(data, null, "overflow", out t23);
model.overflow = t23;
var t24 = model.padding;
result += DeserializeMember(data, null, "padding", out t24);
model.padding = t24;
var t25 = model.richText;
result += DeserializeMember(data, null, "richText", out t25);
model.richText = t25;
var t26 = model.stretchHeight;
result += DeserializeMember(data, null, "stretchHeight", out t26);
model.stretchHeight = t26;
var t27 = model.stretchWidth;
result += DeserializeMember(data, null, "stretchWidth", out t27);
model.stretchWidth = t27;
var t28 = model.wordWrap;
result += DeserializeMember(data, null, "wordWrap", out t28);
model.wordWrap = t28;
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new GUIStyle();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8baf6181321244e55ae38cb2427d1f31
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,46 @@
#if !NO_UNITY
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
public static Gradient_DirectConverter Register_Gradient_DirectConverter;
}
public class Gradient_DirectConverter : fsDirectConverter<Gradient>
{
protected override fsResult DoSerialize(Gradient model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "alphaKeys", model.alphaKeys);
result += SerializeMember(serialized, null, "colorKeys", model.colorKeys);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref Gradient model)
{
var result = fsResult.Success;
var t0 = model.alphaKeys;
result += DeserializeMember(data, null, "alphaKeys", out t0);
model.alphaKeys = t0;
var t1 = model.colorKeys;
result += DeserializeMember(data, null, "colorKeys", out t1);
model.colorKeys = t1;
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new Gradient();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c375abf85cf9e42a0b84b8a8449cdeae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,69 @@
#if !NO_UNITY
#if PACKAGE_INPUT_SYSTEM_EXISTS
using System;
using System.Collections.Generic;
using System.Reflection;
using JetBrains.Annotations;
using UnityEngine.InputSystem;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
[UsedImplicitly]
public static InputAction_DirectConverter Register_InputAction_DirectConverter;
}
[UsedImplicitly]
public class InputAction_DirectConverter : fsDirectConverter<InputAction>
{
protected override fsResult DoSerialize(InputAction model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "id", model.id.ToString());
result += SerializeMember(serialized, null, "name", model.name.ToString());
result += SerializeMember(serialized, null, "expectedControlType", model.expectedControlType);
result += SerializeMember(serialized, null, "type", model.type);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref InputAction model)
{
var result = fsResult.Success;
result += DeserializeMember(data, null, "id", out string actionId);
result += DeserializeMember(data, null, "name", out string actionName);
result += DeserializeMember(data, null, "expectedControlType", out string expectedControlType);
result += DeserializeMember(data, null, "type", out InputActionType type);
model = MakeInputActionWithId(actionId, actionName, expectedControlType, type);
return result;
}
/// <summary>
/// Creates a fake InputAction. Ports with an editor MUST serialize a value of the port's type, even if a GUID
/// would suffice in that case
/// </summary>
public static InputAction MakeInputActionWithId(string actionId, string actionName, string expectedControlType, InputActionType type)
{
var model = new InputAction();
typeof(InputAction).GetField("m_Id", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(model, actionId);
typeof(InputAction).GetField("m_Name", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(model, actionName);
typeof(InputAction).GetField("m_Type", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(model, type);
model.expectedControlType = expectedControlType;
return model;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new InputAction();
}
}
}
#endif
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 87d4a5472eeb90c42adb81dd8a4f18dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,62 @@
#if !NO_UNITY
#pragma warning disable 618
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
public static Keyframe_DirectConverter Register_Keyframe_DirectConverter;
}
public class Keyframe_DirectConverter : fsDirectConverter<Keyframe>
{
protected override fsResult DoSerialize(Keyframe model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "time", model.time);
result += SerializeMember(serialized, null, "value", model.value);
result += SerializeMember(serialized, null, "tangentMode", model.tangentMode);
result += SerializeMember(serialized, null, "inTangent", model.inTangent);
result += SerializeMember(serialized, null, "outTangent", model.outTangent);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref Keyframe model)
{
var result = fsResult.Success;
var t0 = model.time;
result += DeserializeMember(data, null, "time", out t0);
model.time = t0;
var t1 = model.value;
result += DeserializeMember(data, null, "value", out t1);
model.value = t1;
var t2 = model.tangentMode;
result += DeserializeMember(data, null, "tangentMode", out t2);
model.tangentMode = t2;
var t3 = model.inTangent;
result += DeserializeMember(data, null, "inTangent", out t3);
model.inTangent = t3;
var t4 = model.outTangent;
result += DeserializeMember(data, null, "outTangent", out t4);
model.outTangent = t4;
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new Keyframe();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d3b511699db3543da9f36148351d5ed0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,41 @@
#if !NO_UNITY
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
public static LayerMask_DirectConverter Register_LayerMask_DirectConverter;
}
public class LayerMask_DirectConverter : fsDirectConverter<LayerMask>
{
protected override fsResult DoSerialize(LayerMask model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "value", model.value);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref LayerMask model)
{
var result = fsResult.Success;
var t0 = model.value;
result += DeserializeMember(data, null, "value", out t0);
model.value = t0;
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new LayerMask();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e751b86c173aa4faeb9b50cd8051ccfd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,56 @@
#if !NO_UNITY
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
public static RectOffset_DirectConverter Register_RectOffset_DirectConverter;
}
public class RectOffset_DirectConverter : fsDirectConverter<RectOffset>
{
protected override fsResult DoSerialize(RectOffset model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "bottom", model.bottom);
result += SerializeMember(serialized, null, "left", model.left);
result += SerializeMember(serialized, null, "right", model.right);
result += SerializeMember(serialized, null, "top", model.top);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref RectOffset model)
{
var result = fsResult.Success;
var t0 = model.bottom;
result += DeserializeMember(data, null, "bottom", out t0);
model.bottom = t0;
var t2 = model.left;
result += DeserializeMember(data, null, "left", out t2);
model.left = t2;
var t3 = model.right;
result += DeserializeMember(data, null, "right", out t3);
model.right = t3;
var t4 = model.top;
result += DeserializeMember(data, null, "top", out t4);
model.top = t4;
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new RectOffset();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c5f6a2c1ca71a441b9bfcfa0403794b4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,56 @@
#if !NO_UNITY
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
public static Rect_DirectConverter Register_Rect_DirectConverter;
}
public class Rect_DirectConverter : fsDirectConverter<Rect>
{
protected override fsResult DoSerialize(Rect model, Dictionary<string, fsData> serialized)
{
var result = fsResult.Success;
result += SerializeMember(serialized, null, "xMin", model.xMin);
result += SerializeMember(serialized, null, "yMin", model.yMin);
result += SerializeMember(serialized, null, "xMax", model.xMax);
result += SerializeMember(serialized, null, "yMax", model.yMax);
return result;
}
protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref Rect model)
{
var result = fsResult.Success;
var t0 = model.xMin;
result += DeserializeMember(data, null, "xMin", out t0);
model.xMin = t0;
var t1 = model.yMin;
result += DeserializeMember(data, null, "yMin", out t1);
model.yMin = t1;
var t2 = model.xMax;
result += DeserializeMember(data, null, "xMax", out t2);
model.xMax = t2;
var t3 = model.yMax;
result += DeserializeMember(data, null, "yMax", out t3);
model.yMax = t3;
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new Rect();
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7f819e9b71fcc40da8cab6328e655887
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,56 @@
#if !NO_UNITY && UNITY_5_3_OR_NEWER
using System;
using UnityEngine;
using UnityEngine.Events;
namespace Unity.VisualScripting.FullSerializer
{
partial class fsConverterRegistrar
{
// Disable the converter for the time being. Unity's JsonUtility API
// cannot be called from within a C# ISerializationCallbackReceiver
// callback.
// public static Internal.Converters.UnityEvent_Converter
// Register_UnityEvent_Converter;
}
}
namespace Unity.VisualScripting.FullSerializer.Internal.Converters
{
// The standard FS reflection converter has started causing Unity to crash
// when processing UnityEvent. We can send the serialization through
// JsonUtility which appears to work correctly instead.
//
// We have to support legacy serialization formats so importing works as
// expected.
public class UnityEvent_Converter : fsConverter
{
public override bool CanProcess(Type type)
{
return typeof(UnityEvent).Resolve().IsAssignableFrom(type.Resolve()) && type.Resolve().IsGenericType == false;
}
public override bool RequestCycleSupport(Type storageType)
{
return false;
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
Type objectType = (Type)instance;
fsResult result = fsResult.Success;
instance = JsonUtility.FromJson(fsJsonPrinter.CompressedJson(data), objectType);
return result;
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
fsResult result = fsResult.Success;
serialized = fsJsonParser.Parse(JsonUtility.ToJson(instance));
return result;
}
}
}
#endif

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b805c9b714cc14a639d8dbb54ebbb81d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,106 @@
using System;
using System.Collections;
namespace Unity.VisualScripting.FullSerializer
{
public class fsArrayConverter : fsConverter
{
public override bool CanProcess(Type type)
{
return type.IsArray;
}
public override bool RequestCycleSupport(Type storageType)
{
return false;
}
public override bool RequestInheritanceSupport(Type storageType)
{
return false;
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
// note: IList[index] is **significantly** faster than Array.Get, so
// make sure we use that instead.
IList arr = (Array)instance;
var elementType = storageType.GetElementType();
var result = fsResult.Success;
serialized = fsData.CreateList(arr.Count);
var serializedList = serialized.AsList;
for (var i = 0; i < arr.Count; ++i)
{
var item = arr[i];
fsData serializedItem;
var itemResult = Serializer.TrySerialize(elementType, item, out serializedItem);
result.AddMessages(itemResult);
if (itemResult.Failed)
{
continue;
}
serializedList.Add(serializedItem);
}
return result;
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
var result = fsResult.Success;
// Verify that we actually have an List
if ((result += CheckType(data, fsDataType.Array)).Failed)
{
return result;
}
var elementType = storageType.GetElementType();
var serializedList = data.AsList;
var list = new ArrayList(serializedList.Count);
var existingCount = list.Count;
for (var i = 0; i < serializedList.Count; ++i)
{
var serializedItem = serializedList[i];
object deserialized = null;
if (i < existingCount)
{
deserialized = list[i];
}
var itemResult = Serializer.TryDeserialize(serializedItem, elementType, ref deserialized);
result.AddMessages(itemResult);
if (itemResult.Failed)
{
continue;
}
if (i < existingCount)
{
list[i] = deserialized;
}
else
{
list.Add(deserialized);
}
}
instance = list.ToArray(elementType);
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return fsMetaType.Get(Serializer.Config, storageType).CreateInstance();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5f4c650178b4b4b79a3b5cabd17c9307
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,113 @@
using System;
using System.Globalization;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// Supports serialization for DateTime, DateTimeOffset, and TimeSpan.
/// </summary>
public class fsDateConverter : fsConverter
{
private string DateTimeFormatString => Serializer.Config.CustomDateTimeFormatString ?? DefaultDateTimeFormatString;
public override bool CanProcess(Type type)
{
return
type == typeof(DateTime) ||
type == typeof(DateTimeOffset) ||
type == typeof(TimeSpan);
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
if (instance is DateTime)
{
var dateTime = (DateTime)instance;
serialized = new fsData(dateTime.ToString(DateTimeFormatString));
return fsResult.Success;
}
if (instance is DateTimeOffset)
{
var dateTimeOffset = (DateTimeOffset)instance;
serialized = new fsData(dateTimeOffset.ToString(DateTimeOffsetFormatString));
return fsResult.Success;
}
if (instance is TimeSpan)
{
var timeSpan = (TimeSpan)instance;
serialized = new fsData(timeSpan.ToString());
return fsResult.Success;
}
throw new InvalidOperationException("FullSerializer Internal Error -- Unexpected serialization type");
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
if (data.IsString == false)
{
return fsResult.Fail("Date deserialization requires a string, not " + data.Type);
}
if (storageType == typeof(DateTime))
{
DateTime result;
if (DateTime.TryParse(data.AsString, null, DateTimeStyles.RoundtripKind, out result))
{
instance = result;
return fsResult.Success;
}
// DateTime.TryParse can fail for some valid DateTime instances.
// Try to use Convert.ToDateTime.
if (fsGlobalConfig.AllowInternalExceptions)
{
try
{
instance = Convert.ToDateTime(data.AsString);
return fsResult.Success;
}
catch (Exception e)
{
return fsResult.Fail("Unable to parse " + data.AsString + " into a DateTime; got exception " + e);
}
}
return fsResult.Fail("Unable to parse " + data.AsString + " into a DateTime");
}
if (storageType == typeof(DateTimeOffset))
{
DateTimeOffset result;
if (DateTimeOffset.TryParse(data.AsString, null, DateTimeStyles.RoundtripKind, out result))
{
instance = result;
return fsResult.Success;
}
return fsResult.Fail("Unable to parse " + data.AsString + " into a DateTimeOffset");
}
if (storageType == typeof(TimeSpan))
{
TimeSpan result;
if (TimeSpan.TryParse(data.AsString, out result))
{
instance = result;
return fsResult.Success;
}
return fsResult.Fail("Unable to parse " + data.AsString + " into a TimeSpan");
}
throw new InvalidOperationException("FullSerializer Internal Error -- Unexpected deserialization type");
}
// The format strings that we use when serializing DateTime and
// DateTimeOffset types.
private const string DefaultDateTimeFormatString = @"o";
private const string DateTimeOffsetFormatString = @"o";
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b2cf6489d32e14b8ba1bec90f2dcc4bf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,232 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
// While the generic IEnumerable converter can handle dictionaries, we
// process them separately here because we support a few more advanced
// use-cases with dictionaries, such as inline strings. Further, dictionary
// processing in general is a bit more advanced because a few of the
// collection implementations are buggy.
public class fsDictionaryConverter : fsConverter
{
public override bool CanProcess(Type type)
{
return typeof(IDictionary).IsAssignableFrom(type);
}
public override object CreateInstance(fsData data, Type storageType)
{
return fsMetaType.Get(Serializer.Config, storageType).CreateInstance();
}
public override fsResult TryDeserialize(fsData data, ref object instance_, Type storageType)
{
var instance = (IDictionary)instance_;
var result = fsResult.Success;
Type keyStorageType, valueStorageType;
GetKeyValueTypes(instance.GetType(), out keyStorageType, out valueStorageType);
if (data.IsList)
{
var list = data.AsList;
for (var i = 0; i < list.Count; ++i)
{
var item = list[i];
fsData keyData, valueData;
if ((result += CheckType(item, fsDataType.Object)).Failed)
{
return result;
}
if ((result += CheckKey(item, "Key", out keyData)).Failed)
{
return result;
}
if ((result += CheckKey(item, "Value", out valueData)).Failed)
{
return result;
}
object keyInstance = null, valueInstance = null;
if ((result += Serializer.TryDeserialize(keyData, keyStorageType, ref keyInstance)).Failed)
{
return result;
}
if ((result += Serializer.TryDeserialize(valueData, valueStorageType, ref valueInstance)).Failed)
{
return result;
}
AddItemToDictionary(instance, keyInstance, valueInstance);
}
}
else if (data.IsDictionary)
{
foreach (var entry in data.AsDictionary)
{
if (fsSerializer.IsReservedKeyword(entry.Key))
{
continue;
}
fsData keyData = new fsData(entry.Key), valueData = entry.Value;
object keyInstance = null, valueInstance = null;
if ((result += Serializer.TryDeserialize(keyData, keyStorageType, ref keyInstance)).Failed)
{
return result;
}
if ((result += Serializer.TryDeserialize(valueData, valueStorageType, ref valueInstance)).Failed)
{
return result;
}
AddItemToDictionary(instance, keyInstance, valueInstance);
}
}
else
{
return FailExpectedType(data, fsDataType.Array, fsDataType.Object);
}
return result;
}
public override fsResult TrySerialize(object instance_, out fsData serialized, Type storageType)
{
serialized = fsData.Null;
var result = fsResult.Success;
var instance = (IDictionary)instance_;
Type keyStorageType, valueStorageType;
GetKeyValueTypes(instance.GetType(), out keyStorageType, out valueStorageType);
// No other way to iterate dictionaries and still have access to the
// key/value info
var enumerator = instance.GetEnumerator();
var allStringKeys = true;
var serializedKeys = new List<fsData>(instance.Count);
var serializedValues = new List<fsData>(instance.Count);
while (enumerator.MoveNext())
{
fsData keyData, valueData;
if ((result += Serializer.TrySerialize(keyStorageType, enumerator.Key, out keyData)).Failed)
{
return result;
}
if ((result += Serializer.TrySerialize(valueStorageType, enumerator.Value, out valueData)).Failed)
{
return result;
}
serializedKeys.Add(keyData);
serializedValues.Add(valueData);
allStringKeys &= keyData.IsString;
}
if (allStringKeys)
{
serialized = fsData.CreateDictionary();
var serializedDictionary = serialized.AsDictionary;
for (var i = 0; i < serializedKeys.Count; ++i)
{
var key = serializedKeys[i];
var value = serializedValues[i];
serializedDictionary[key.AsString] = value;
}
}
else
{
serialized = fsData.CreateList(serializedKeys.Count);
var serializedList = serialized.AsList;
for (var i = 0; i < serializedKeys.Count; ++i)
{
var key = serializedKeys[i];
var value = serializedValues[i];
var container = new Dictionary<string, fsData>();
container["Key"] = key;
container["Value"] = value;
serializedList.Add(new fsData(container));
}
}
return result;
}
private fsResult AddItemToDictionary(IDictionary dictionary, object key, object value)
{
// Because we're operating through the IDictionary interface by
// default (and not the generic one), we normally send items through
// IDictionary.Add(object, object). This works fine in the general
// case, except that the add method verifies that it's parameter
// types are proper types. However, mono is buggy and these type
// checks do not consider null a subtype of the parameter types, and
// exceptions get thrown. So, we have to special case adding null
// items via the generic functions (which do not do the null check),
// which is slow and messy.
//
// An example of a collection that fails deserialization without this
// method is `new SortedList<int, string> { { 0, null } }`.
// (SortedDictionary is fine because it properly handles null
// values).
if (key == null || value == null)
{
// Life would be much easier if we had MakeGenericType available,
// but we don't. So we're going to find the correct generic
// KeyValuePair type via a bit of trickery. All dictionaries
// extend ICollection<KeyValuePair<TKey, TValue>>, so we just
// fetch the ICollection<> type with the proper generic
// arguments, and then we take the KeyValuePair<> generic
// argument, and whola! we have our proper generic type.
var collectionType = fsReflectionUtility.GetInterface(dictionary.GetType(), typeof(ICollection<>));
if (collectionType == null)
{
return fsResult.Warn(dictionary.GetType() + " does not extend ICollection");
}
var keyValuePairType = collectionType.GetGenericArguments()[0];
var keyValueInstance = Activator.CreateInstance(keyValuePairType, key, value);
var add = collectionType.GetFlattenedMethod("Add");
add.Invoke(dictionary, new[] { keyValueInstance });
return fsResult.Success;
}
// We use the inline set methods instead of dictionary.Add;
// dictionary.Add will throw an exception if the key already exists.
dictionary[key] = value;
return fsResult.Success;
}
private static void GetKeyValueTypes(Type dictionaryType, out Type keyStorageType, out Type valueStorageType)
{
// All dictionaries extend IDictionary<TKey, TValue>, so we just
// fetch the generic arguments from it
var interfaceType = fsReflectionUtility.GetInterface(dictionaryType, typeof(IDictionary<,>));
if (interfaceType != null)
{
var genericArgs = interfaceType.GetGenericArguments();
keyStorageType = genericArgs[0];
valueStorageType = genericArgs[1];
}
else
{
// Fetching IDictionary<,> failed... we have to encode full type
// information :(
keyStorageType = typeof(object);
valueStorageType = typeof(object);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2deb045d480ac4959bcb46744de8db3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,161 @@
using System;
using System.Collections.Generic;
using System.Text;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// Serializes and deserializes enums by their current name.
/// </summary>
public class fsEnumConverter : fsConverter
{
public override bool CanProcess(Type type)
{
return type.Resolve().IsEnum;
}
public override bool RequestCycleSupport(Type storageType)
{
return false;
}
public override bool RequestInheritanceSupport(Type storageType)
{
return false;
}
public override object CreateInstance(fsData data, Type storageType)
{
// In .NET compact, Enum.ToObject(Type, Object) is defined but the
// overloads like Enum.ToObject(Type, int) are not -- so we get
// around this by boxing the value.
return Enum.ToObject(storageType, (object)0);
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
if (Serializer.Config.SerializeEnumsAsInteger)
{
serialized = new fsData(Convert.ToInt64(instance));
}
else if (fsPortableReflection.GetAttribute<FlagsAttribute>(storageType) != null)
{
var lValue = Convert.ToInt64(instance);
var result = new StringBuilder();
var first = true;
foreach (var flag in Enum.GetValues(storageType))
{
var lFlag = Convert.ToInt64(flag);
if (lFlag == 0)
{
continue;
}
var isSet = (lValue & lFlag) == lFlag;
if (isSet)
{
if (first == false)
{
result.Append(",");
}
first = false;
result.Append(flag.ToString());
}
}
serialized = new fsData(result.ToString());
}
else
{
serialized = new fsData(Enum.GetName(storageType, instance));
}
return fsResult.Success;
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
if (data.IsString)
{
var enumValues = data.AsString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < enumValues.Length; ++i)
{
var enumValue = enumValues[i];
// Verify that the enum name exists; Enum.TryParse is only
// available in .NET 4.0 and above :(.
if (ArrayContains(Enum.GetNames(storageType), enumValue) == false)
{
return fsResult.Fail("Cannot find enum name " + enumValue + " on type " + storageType);
}
}
var underlyingType = Enum.GetUnderlyingType(storageType);
if (underlyingType == typeof(ulong))
{
ulong instanceValue = 0;
for (var i = 0; i < enumValues.Length; ++i)
{
var enumValue = enumValues[i];
var flagValue = (ulong)Convert.ChangeType(Enum.Parse(storageType, enumValue), typeof(ulong));
instanceValue |= flagValue;
}
instance = Enum.ToObject(storageType, (object)instanceValue);
}
else
{
long instanceValue = 0;
for (var i = 0; i < enumValues.Length; ++i)
{
var enumValue = enumValues[i];
var flagValue = (long)Convert.ChangeType(Enum.Parse(storageType, enumValue), typeof(long));
instanceValue |= flagValue;
}
instance = Enum.ToObject(storageType, (object)instanceValue);
}
return fsResult.Success;
}
else if (data.IsInt64)
{
var enumValue = (int)data.AsInt64;
// In .NET compact, Enum.ToObject(Type, Object) is defined but
// the overloads like Enum.ToObject(Type, int) are not -- so we
// get around this by boxing the value.
instance = Enum.ToObject(storageType, (object)enumValue);
return fsResult.Success;
}
return fsResult.Fail($"EnumConverter encountered an unknown JSON data type for {storageType}: {data.Type}");
}
/// <summary>
/// Returns true if the given value is contained within the specified
/// array.
/// </summary>
private static bool ArrayContains<T>(T[] values, T value)
{
// note: We don't use LINQ because this function will *not* allocate
for (var i = 0; i < values.Length; ++i)
{
if (EqualityComparer<T>.Default.Equals(values[i], value))
{
return true;
}
}
return false;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ab94a630dd6e9441ba5d116d7c1bcfd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,107 @@
using System;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// This allows you to forward serialization of an object to one of its
/// members. For example,
/// [fsForward("Values")]
/// struct Wrapper {
/// public int[] Values;
/// }
/// Then `Wrapper` will be serialized into a JSON array of integers. It will
/// be as if `Wrapper` doesn't exist.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct)]
public sealed class fsForwardAttribute : Attribute
{
/// <summary>
/// Forward object serialization to an instance member. See class
/// comment.
/// </summary>
/// <param name="memberName">
/// The name of the member that we should serialize this object as.
/// </param>
public fsForwardAttribute(string memberName)
{
MemberName = memberName;
}
/// <summary>
/// The name of the member we should serialize as.
/// </summary>
public string MemberName;
}
public class fsForwardConverter : fsConverter
{
public fsForwardConverter(fsForwardAttribute attribute)
{
_memberName = attribute.MemberName;
}
private string _memberName;
public override bool CanProcess(Type type)
{
throw new NotSupportedException("Please use the [fsForward(...)] attribute.");
}
private fsResult GetProperty(object instance, out fsMetaProperty property)
{
var properties = fsMetaType.Get(Serializer.Config, instance.GetType()).Properties;
for (var i = 0; i < properties.Length; ++i)
{
if (properties[i].MemberName == _memberName)
{
property = properties[i];
return fsResult.Success;
}
}
property = default(fsMetaProperty);
return fsResult.Fail("No property named \"" + _memberName + "\" on " + fsTypeExtensions.CSharpName(instance.GetType()));
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
serialized = fsData.Null;
var result = fsResult.Success;
fsMetaProperty property;
if ((result += GetProperty(instance, out property)).Failed)
{
return result;
}
var actualInstance = property.Read(instance);
return Serializer.TrySerialize(property.StorageType, actualInstance, out serialized);
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
var result = fsResult.Success;
fsMetaProperty property;
if ((result += GetProperty(instance, out property)).Failed)
{
return result;
}
object actualInstance = null;
if ((result += Serializer.TryDeserialize(data, property.StorageType, ref actualInstance)).Failed)
{
return result;
}
property.Write(instance, actualInstance);
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return fsMetaType.Get(Serializer.Config, storageType).CreateInstance();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f85fe1ea3f9664fb9be7ce694de49076
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,48 @@
using System;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// Serializes and deserializes guids.
/// </summary>
public class fsGuidConverter : fsConverter
{
public override bool CanProcess(Type type)
{
return type == typeof(Guid);
}
public override bool RequestCycleSupport(Type storageType)
{
return false;
}
public override bool RequestInheritanceSupport(Type storageType)
{
return false;
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
var guid = (Guid)instance;
serialized = new fsData(guid.ToString());
return fsResult.Success;
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
if (data.IsString)
{
instance = new Guid(data.AsString);
return fsResult.Success;
}
return fsResult.Fail("fsGuidConverter encountered an unknown JSON data type");
}
public override object CreateInstance(fsData data, Type storageType)
{
return new Guid();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9836aacf159b449c6a57eb3c92fb6809
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,195 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// Provides serialization support for anything which extends from
/// `IEnumerable` and has an `Add` method.
/// </summary>
public class fsIEnumerableConverter : fsConverter
{
public override bool CanProcess(Type type)
{
if (typeof(IEnumerable).IsAssignableFrom(type) == false)
{
return false;
}
return GetAddMethod(type) != null;
}
public override object CreateInstance(fsData data, Type storageType)
{
return fsMetaType.Get(Serializer.Config, storageType).CreateInstance();
}
public override fsResult TrySerialize(object instance_, out fsData serialized, Type storageType)
{
var instance = (IEnumerable)instance_;
var result = fsResult.Success;
var elementType = GetElementType(storageType);
serialized = fsData.CreateList(HintSize(instance));
var serializedList = serialized.AsList;
foreach (var item in instance)
{
fsData itemData;
// note: We don't fail the entire deserialization even if the
// item failed
var itemResult = Serializer.TrySerialize(elementType, item, out itemData);
result.AddMessages(itemResult);
if (itemResult.Failed)
{
continue;
}
serializedList.Add(itemData);
}
// Stacks iterate from back to front, which means when we deserialize
// we will deserialize the items in the wrong order, so the stack
// will get reversed.
if (IsStack(instance.GetType()))
{
serializedList.Reverse();
}
return result;
}
private bool IsStack(Type type)
{
return type.Resolve().IsGenericType &&
type.Resolve().GetGenericTypeDefinition() == typeof(Stack<>);
}
public override fsResult TryDeserialize(fsData data, ref object instance_, Type storageType)
{
var instance = (IEnumerable)instance_;
var result = fsResult.Success;
if ((result += CheckType(data, fsDataType.Array)).Failed)
{
return result;
}
// LAZLO/LUDIQ: Changes to default behaviour.
// - Do not try to serialize into existing element; always clear and add
// (more reliable, compatible with custom indexers)
// - If the type is a list, add a default element on failure to prevent
// messing up the order.
// - Commented out that last change.
var elementStorageType = GetElementType(storageType);
var addMethod = GetAddMethod(storageType);
TryClear(storageType, instance);
var serializedList = data.AsList;
for (var i = 0; i < serializedList.Count; ++i)
{
var itemData = serializedList[i];
object itemInstance = null;
var itemResult = Serializer.TryDeserialize(itemData, elementStorageType, ref itemInstance);
result.AddMessages(itemResult);
if (itemResult.Succeeded)
{
addMethod.Invoke(instance, new[] { itemInstance });
}
// else
// {
// if (typeof(IList).IsAssignableFrom(storageType))
// {
// addMethod.Invoke(instance, new[] { elementStorageType.Default() });
// }
// else
// {
// continue;
// }
// }
}
return result;
}
private static int HintSize(IEnumerable collection)
{
if (collection is ICollection)
{
return ((ICollection)collection).Count;
}
return 0;
}
/// <summary>
/// Fetches the element type for objects inside of the collection.
/// </summary>
private static Type GetElementType(Type objectType)
{
if (objectType.HasElementType)
{
return objectType.GetElementType();
}
var enumerableList = fsReflectionUtility.GetInterface(objectType, typeof(IEnumerable<>));
if (enumerableList != null)
{
return enumerableList.GetGenericArguments()[0];
}
return typeof(object);
}
private static void TryClear(Type type, object instance)
{
var clear = type.GetFlattenedMethod("Clear");
if (clear != null)
{
clear.Invoke(instance, null);
}
}
private static int TryGetExistingSize(Type type, object instance)
{
var count = type.GetFlattenedProperty("Count");
if (count != null)
{
return (int)count.GetGetMethod().Invoke(instance, null);
}
return 0;
}
private static MethodInfo GetAddMethod(Type type)
{
// There is a really good chance the type will extend ICollection{},
// which will contain the add method we want. Just doing
// type.GetFlattenedMethod() may return the incorrect one -- for
// example, with dictionaries, it'll return Add(TKey, TValue), and we
// want Add(KeyValuePair<TKey, TValue>).
var collectionInterface = fsReflectionUtility.GetInterface(type, typeof(ICollection<>));
if (collectionInterface != null)
{
var add = collectionInterface.GetDeclaredMethod("Add");
if (add != null)
{
return add;
}
}
// Otherwise try and look up a general Add method.
return
type.GetFlattenedMethod("Add") ??
type.GetFlattenedMethod("Push") ??
type.GetFlattenedMethod("Enqueue");
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 83ff07ed5d5f746a18cff1d9fd010e93
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
public class fsKeyValuePairConverter : fsConverter
{
public override bool CanProcess(Type type)
{
return
type.Resolve().IsGenericType &&
type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>);
}
public override bool RequestCycleSupport(Type storageType)
{
return false;
}
public override bool RequestInheritanceSupport(Type storageType)
{
return false;
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
var result = fsResult.Success;
fsData keyData, valueData;
if ((result += CheckKey(data, "Key", out keyData)).Failed)
{
return result;
}
if ((result += CheckKey(data, "Value", out valueData)).Failed)
{
return result;
}
var genericArguments = storageType.GetGenericArguments();
Type keyType = genericArguments[0], valueType = genericArguments[1];
object keyObject = null, valueObject = null;
result.AddMessages(Serializer.TryDeserialize(keyData, keyType, ref keyObject));
result.AddMessages(Serializer.TryDeserialize(valueData, valueType, ref valueObject));
instance = Activator.CreateInstance(storageType, keyObject, valueObject);
return result;
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
var keyProperty = storageType.GetDeclaredProperty("Key");
var valueProperty = storageType.GetDeclaredProperty("Value");
var keyObject = keyProperty.GetValue(instance, null);
var valueObject = valueProperty.GetValue(instance, null);
var genericArguments = storageType.GetGenericArguments();
Type keyType = genericArguments[0], valueType = genericArguments[1];
var result = fsResult.Success;
fsData keyData, valueData;
result.AddMessages(Serializer.TrySerialize(keyType, keyObject, out keyData));
result.AddMessages(Serializer.TrySerialize(valueType, valueObject, out valueData));
serialized = fsData.CreateDictionary();
if (keyData != null)
{
serialized.AsDictionary["Key"] = keyData;
}
if (valueData != null)
{
serialized.AsDictionary["Value"] = valueData;
}
return result;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 37bee35b01d89446581ee06eb78ab74e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,36 @@
using System;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// The reflected converter will properly serialize nullable types. However,
/// we do it here instead as we can emit less serialization data.
/// </summary>
public class fsNullableConverter : fsConverter
{
public override bool CanProcess(Type type)
{
return
type.Resolve().IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
// null is automatically serialized
return Serializer.TrySerialize(Nullable.GetUnderlyingType(storageType), instance, out serialized);
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
// null is automatically deserialized
return Serializer.TryDeserialize(data, Nullable.GetUnderlyingType(storageType), ref instance);
}
public override object CreateInstance(fsData data, Type storageType)
{
return storageType;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d600c4c5c0dac41a885a14952da139bd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,173 @@
using System;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
public class fsPrimitiveConverter : fsConverter
{
public override bool CanProcess(Type type)
{
return
type.Resolve().IsPrimitive ||
type == typeof(string) ||
type == typeof(decimal);
}
public override bool RequestCycleSupport(Type storageType)
{
return false;
}
public override bool RequestInheritanceSupport(Type storageType)
{
return false;
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
var instanceType = instance.GetType();
if (Serializer.Config.Serialize64BitIntegerAsString && (instanceType == typeof(Int64) || instanceType == typeof(UInt64)))
{
serialized = new fsData((string)Convert.ChangeType(instance, typeof(string)));
return fsResult.Success;
}
if (UseBool(instanceType))
{
serialized = new fsData((bool)instance);
return fsResult.Success;
}
if (UseInt64(instanceType))
{
serialized = new fsData((Int64)Convert.ChangeType(instance, typeof(Int64)));
return fsResult.Success;
}
if (UseDouble(instanceType))
{
// Casting from float to double introduces floating point jitter,
// ie, 0.1 becomes 0.100000001490116. Casting to decimal as an
// intermediate step removes the jitter. Not sure why.
if (instance.GetType() == typeof(float) &&
// Decimal can't store
// float.MinValue/float.MaxValue/float.PositiveInfinity/float.NegativeInfinity/float.NaN
// - an exception gets thrown in that scenario.
(float)instance != float.MinValue &&
(float)instance != float.MaxValue &&
!float.IsInfinity((float)instance) &&
!float.IsNaN((float)instance)
)
{
serialized = new fsData((double)(decimal)(float)instance);
return fsResult.Success;
}
serialized = new fsData((double)Convert.ChangeType(instance, typeof(double)));
return fsResult.Success;
}
if (UseString(instanceType))
{
serialized = new fsData((string)Convert.ChangeType(instance, typeof(string)));
return fsResult.Success;
}
serialized = null;
return fsResult.Fail("Unhandled primitive type " + instance.GetType());
}
public override fsResult TryDeserialize(fsData storage, ref object instance, Type storageType)
{
var result = fsResult.Success;
if (UseBool(storageType))
{
if ((result += CheckType(storage, fsDataType.Boolean)).Succeeded)
{
instance = storage.AsBool;
}
return result;
}
if (UseDouble(storageType) || UseInt64(storageType))
{
if (storage.IsDouble)
{
instance = Convert.ChangeType(storage.AsDouble, storageType);
}
else if (storage.IsInt64)
{
instance = Convert.ChangeType(storage.AsInt64, storageType);
}
else if (Serializer.Config.Serialize64BitIntegerAsString && storage.IsString &&
(storageType == typeof(Int64) || storageType == typeof(UInt64)))
{
instance = Convert.ChangeType(storage.AsString, storageType);
}
else
{
return fsResult.Fail(GetType().Name + " expected number but got " + storage.Type + " in " + storage);
}
return fsResult.Success;
}
if (UseString(storageType))
{
if ((result += CheckType(storage, fsDataType.String)).Succeeded)
{
var str = storage.AsString;
if (storageType == typeof(char))
{
if (storageType == typeof(char))
{
if (str.Length == 1)
{
instance = str[0];
}
else
{
instance = default(char);
}
}
}
else
{
instance = str;
}
}
return result;
}
return fsResult.Fail(GetType().Name + ": Bad data; expected bool, number, string, but got " + storage);
}
private static bool UseBool(Type type)
{
return type == typeof(bool);
}
private static bool UseInt64(Type type)
{
return type == typeof(sbyte) || type == typeof(byte) ||
type == typeof(Int16) || type == typeof(UInt16) ||
type == typeof(Int32) || type == typeof(UInt32) ||
type == typeof(Int64) || type == typeof(UInt64);
}
private static bool UseDouble(Type type)
{
return type == typeof(float) ||
type == typeof(double) ||
type == typeof(decimal);
}
private static bool UseString(Type type)
{
return type == typeof(string) ||
type == typeof(char);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 558f1bd3630a14d2a8445d33219e5060
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,118 @@
using System;
using System.Collections;
using Unity.VisualScripting.FullSerializer.Internal;
#if !UNITY_EDITOR && UNITY_WSA
// For System.Reflection.TypeExtensions
using System.Reflection;
#endif
namespace Unity.VisualScripting.FullSerializer
{
public class fsReflectedConverter : fsConverter
{
public override bool CanProcess(Type type)
{
if (type.Resolve().IsArray ||
typeof(ICollection).IsAssignableFrom(type))
{
return false;
}
return true;
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
serialized = fsData.CreateDictionary();
var result = fsResult.Success;
var metaType = fsMetaType.Get(Serializer.Config, instance.GetType());
metaType.EmitAotData();
for (var i = 0; i < metaType.Properties.Length; ++i)
{
var property = metaType.Properties[i];
if (property.CanRead == false)
{
continue;
}
fsData serializedData;
var itemResult = Serializer.TrySerialize(property.StorageType, property.OverrideConverterType,
property.Read(instance), out serializedData);
result.AddMessages(itemResult);
if (itemResult.Failed)
{
continue;
}
serialized.AsDictionary[property.JsonName] = serializedData;
}
return result;
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
var result = fsResult.Success;
// Verify that we actually have an Object
if ((result += CheckType(data, fsDataType.Object)).Failed)
{
return result;
}
var metaType = fsMetaType.Get(Serializer.Config, storageType);
metaType.EmitAotData();
for (var i = 0; i < metaType.Properties.Length; ++i)
{
var property = metaType.Properties[i];
if (property.CanWrite == false)
{
continue;
}
fsData propertyData;
if (data.AsDictionary.TryGetValue(property.JsonName, out propertyData))
{
object deserializedValue = null;
// We have to read in the existing value, since we need to
// support partial deserialization. However, this is bad for
// perf.
// TODO: Find a way to avoid this call when we are not doing
// a partial deserialization Maybe through a new
// property, ie, Serializer.IsPartialSerialization,
// which just gets set when starting a new
// serialization? We cannot pipe the information
// through CreateInstance unfortunately.
if (property.CanRead)
{
deserializedValue = property.Read(instance);
}
var itemResult = Serializer.TryDeserialize(propertyData, property.StorageType,
property.OverrideConverterType, ref deserializedValue);
result.AddMessages(itemResult);
if (itemResult.Failed)
{
continue;
}
property.Write(instance, deserializedValue);
}
}
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
var metaType = fsMetaType.Get(Serializer.Config, storageType);
return metaType.CreateInstance();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aceaeecabc7804af78324f3a4ca624d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,58 @@
using System;
#if !UNITY_EDITOR && UNITY_WSA
// For System.Reflection.TypeExtensions
using System.Reflection;
#endif
namespace Unity.VisualScripting.FullSerializer
{
public class fsTypeConverter : fsConverter
{
public override bool CanProcess(Type type)
{
return typeof(Type).IsAssignableFrom(type);
}
public override bool RequestCycleSupport(Type type)
{
return false;
}
public override bool RequestInheritanceSupport(Type type)
{
return false;
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
var type = (Type)instance;
serialized = new fsData(RuntimeCodebase.SerializeType(type));
return fsResult.Success;
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
if (data.IsString == false)
{
return fsResult.Fail("Type converter requires a string");
}
if (RuntimeCodebase.TryDeserializeType(data.AsString, out var type))
{
instance = type;
}
else
{
return fsResult.Fail($"Unable to find type: '{data.AsString ?? "(null)"}'.");
}
return fsResult.Success;
}
public override object CreateInstance(fsData data, Type storageType)
{
return storageType;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1ffb0c77cc5134994ba0d23fcbdd4205
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,83 @@
using System;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// Serializes and deserializes WeakReferences.
/// </summary>
public class fsWeakReferenceConverter : fsConverter
{
public override bool CanProcess(Type type)
{
return type == typeof(WeakReference);
}
public override bool RequestCycleSupport(Type storageType)
{
return false;
}
public override bool RequestInheritanceSupport(Type storageType)
{
return false;
}
public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
var weakRef = (WeakReference)instance;
var result = fsResult.Success;
serialized = fsData.CreateDictionary();
if (weakRef.IsAlive)
{
fsData data;
if ((result += Serializer.TrySerialize(weakRef.Target, out data)).Failed)
{
return result;
}
serialized.AsDictionary["Target"] = data;
serialized.AsDictionary["TrackResurrection"] = new fsData(weakRef.TrackResurrection);
}
return result;
}
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
var result = fsResult.Success;
if ((result += CheckType(data, fsDataType.Object)).Failed)
{
return result;
}
if (data.AsDictionary.ContainsKey("Target"))
{
var targetData = data.AsDictionary["Target"];
object targetInstance = null;
if ((result += Serializer.TryDeserialize(targetData, typeof(object), ref targetInstance)).Failed)
{
return result;
}
var trackResurrection = false;
if (data.AsDictionary.ContainsKey("TrackResurrection") && data.AsDictionary["TrackResurrection"].IsBool)
{
trackResurrection = data.AsDictionary["TrackResurrection"].AsBool;
}
instance = new WeakReference(targetInstance, trackResurrection);
}
return result;
}
public override object CreateInstance(fsData data, Type storageType)
{
return new WeakReference(null);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 57352352fce8a4f57800fb25fb539745
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3ee33d080bf544382a0b3bb52e994713
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Unity.VisualScripting.FullSerializer.Internal
{
public class fsCyclicReferenceManager
{
private Dictionary<object, int> _objectIds = new Dictionary<object, int>(ObjectReferenceEqualityComparator.Instance);
private int _nextId;
private Dictionary<int, object> _marked = new Dictionary<int, object>();
private int _depth;
public void Enter()
{
_depth++;
}
public bool Exit()
{
_depth--;
if (_depth == 0)
{
_objectIds = new Dictionary<object, int>(ObjectReferenceEqualityComparator.Instance);
_nextId = 0;
_marked = new Dictionary<int, object>();
}
if (_depth < 0)
{
_depth = 0;
throw new InvalidOperationException("Internal Error - Mismatched Enter/Exit. Please report a bug at https://github.com/jacobdufault/fullserializer/issues with the serialization data.");
}
return _depth == 0;
}
public object GetReferenceObject(int id)
{
if (_marked.ContainsKey(id) == false)
{
throw new InvalidOperationException("Internal Deserialization Error - Object " +
"definition has not been encountered for object with id=" + id +
"; have you reordered or modified the serialized data? If this is an issue " +
"with an unmodified Full Serializer implementation and unmodified serialization " +
"data, please report an issue with an included test case.");
}
return _marked[id];
}
public void AddReferenceWithId(int id, object reference)
{
_marked[id] = reference;
}
public int GetReferenceId(object item)
{
int id;
if (_objectIds.TryGetValue(item, out id) == false)
{
id = _nextId++;
_objectIds[item] = id;
}
return id;
}
public bool IsReference(object item)
{
return _marked.ContainsKey(GetReferenceId(item));
}
public void MarkSerialized(object item)
{
var referenceId = GetReferenceId(item);
if (_marked.ContainsKey(referenceId))
{
throw new InvalidOperationException("Internal Error - " + item +
" has already been marked as serialized");
}
_marked[referenceId] = item;
}
// We use the default ReferenceEquals when comparing two objects because
// custom objects may override equals methods. These overriden equals may
// treat equals differently; we want to serialize/deserialize the object
// graph *identically* to how it currently exists.
private class ObjectReferenceEqualityComparator : IEqualityComparer<object>
{
bool IEqualityComparer<object>.Equals(object x, object y)
{
return ReferenceEquals(x, y);
}
int IEqualityComparer<object>.GetHashCode(object obj)
{
return RuntimeHelpers.GetHashCode(obj);
}
public static readonly IEqualityComparer<object> Instance = new ObjectReferenceEqualityComparator();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0304625fd852e4c1a88e3a6367245d13
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,45 @@
using System;
namespace Unity.VisualScripting.FullSerializer.Internal
{
/// <summary>
/// Simple option type. This is akin to nullable types.
/// </summary>
public struct fsOption<T>
{
private bool _hasValue;
private T _value;
public bool HasValue => _hasValue;
public bool IsEmpty => _hasValue == false;
public T Value
{
get
{
if (IsEmpty)
{
throw new InvalidOperationException("fsOption is empty");
}
return _value;
}
}
public fsOption(T value)
{
_hasValue = true;
_value = value;
}
public static fsOption<T> Empty;
}
public static class fsOption
{
public static fsOption<T> Just<T>(T value)
{
return new fsOption<T>(value);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b2d2628348c58407eb518c9b65d489cb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,507 @@
#if !UNITY_EDITOR && UNITY_METRO && !ENABLE_IL2CPP
#define USE_TYPEINFO
#if !UNITY_WINRT_10_0
#define USE_TYPEINFO_EXTENSIONS
#endif
#endif
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
#if USE_TYPEINFO
namespace System
{
public static class AssemblyExtensions
{
#if USE_TYPEINFO_EXTENSIONS
public static Type[] GetTypes(this Assembly assembly)
{
TypeInfo[] infos = assembly.DefinedTypes.ToArray();
Type[] types = new Type[infos.Length];
for (int i = 0; i < infos.Length; ++i)
{
types[i] = infos[i].AsType();
}
return types;
}
#endif
public static Type GetType(this Assembly assembly, string name, bool throwOnError)
{
var types = assembly.GetTypes();
for (int i = 0; i < types.Length; ++i)
{
if (types[i].Name == name)
{
return types[i];
}
}
if (throwOnError) throw new Exception("Type " + name + " was not found");
return null;
}
}
}
#endif
namespace Unity.VisualScripting.FullSerializer.Internal
{
/// <summary>
/// This wraps reflection types so that it is portable across different Unity
/// runtimes.
/// </summary>
public static class fsPortableReflection
{
public static Type[] EmptyTypes = { };
#region Attribute Queries
#if USE_TYPEINFO
public static TAttribute GetAttribute<TAttribute>(Type type)
where TAttribute : Attribute
{
return GetAttribute<TAttribute>(type.GetTypeInfo());
}
public static Attribute GetAttribute(Type type, Type attributeType)
{
return GetAttribute(type.GetTypeInfo(), attributeType, /*shouldCache:*/ false);
}
public static bool HasAttribute(Type type, Type attributeType)
{
return GetAttribute(type, attributeType) != null;
}
#endif
/// <summary>
/// Returns true if the given attribute is defined on the given element.
/// </summary>
public static bool HasAttribute<TAttribute>(MemberInfo element)
{
return HasAttribute(element, typeof(TAttribute));
}
/// <summary>
/// Returns true if the given attribute is defined on the given element.
/// </summary>
public static bool HasAttribute<TAttribute>(MemberInfo element, bool shouldCache)
{
return HasAttribute(element, typeof(TAttribute), shouldCache);
}
/// <summary>
/// Returns true if the given attribute is defined on the given element.
/// </summary>
public static bool HasAttribute(MemberInfo element, Type attributeType)
{
return HasAttribute(element, attributeType, true);
}
/// <summary>
/// Returns true if the given attribute is defined on the given element.
/// </summary>
public static bool HasAttribute(MemberInfo element, Type attributeType, bool shouldCache)
{
// LAZLO / LUDIQ FIX
// Inheritance on property overrides. MemberInfo.IsDefined ignores the inherited parameter.
// https://stackoverflow.com/questions/2520035
return Attribute.IsDefined(element, attributeType, true);
//return element.IsDefined(attributeType, true);
}
/// <summary>
/// Fetches the given attribute from the given MemberInfo. This method
/// applies caching and is allocation free (after caching has been
/// performed).
/// </summary>
/// <param name="element">
/// The MemberInfo the get the attribute from.
/// </param>
/// <param name="attributeType">The type of attribute to fetch.</param>
/// <returns>The attribute or null.</returns>
public static Attribute GetAttribute(MemberInfo element, Type attributeType, bool shouldCache)
{
var query = new AttributeQuery
{
MemberInfo = element,
AttributeType = attributeType
};
Attribute attribute;
if (_cachedAttributeQueries.TryGetValue(query, out attribute) == false)
{
// LAZLO / LUDIQ FIX
// Inheritance on property overrides. MemberInfo.IsDefined ignores the inherited parameter
//var attributes = element.GetCustomAttributes(attributeType, /*inherit:*/ true).ToArray();
var attributes = Attribute.GetCustomAttributes(element, attributeType, true).ToArray();
if (attributes.Length > 0)
{
attribute = (Attribute)attributes[0];
}
if (shouldCache)
{
_cachedAttributeQueries[query] = attribute;
}
}
return attribute;
}
/// <summary>
/// Fetches the given attribute from the given MemberInfo.
/// </summary>
/// <typeparam name="TAttribute">
/// The type of attribute to fetch.
/// </typeparam>
/// <param name="element">
/// The MemberInfo to get the attribute from.
/// </param>
/// <param name="shouldCache">
/// Should this computation be cached? If this is the only time it will
/// ever be done, don't bother caching.
/// </param>
/// <returns>The attribute or null.</returns>
public static TAttribute GetAttribute<TAttribute>(MemberInfo element, bool shouldCache)
where TAttribute : Attribute
{
return (TAttribute)GetAttribute(element, typeof(TAttribute), shouldCache);
}
public static TAttribute GetAttribute<TAttribute>(MemberInfo element)
where TAttribute : Attribute
{
return GetAttribute<TAttribute>(element, /*shouldCache:*/ true);
}
private struct AttributeQuery
{
public MemberInfo MemberInfo;
public Type AttributeType;
}
private static IDictionary<AttributeQuery, Attribute> _cachedAttributeQueries =
new Dictionary<AttributeQuery, Attribute>(new AttributeQueryComparator());
private class AttributeQueryComparator : IEqualityComparer<AttributeQuery>
{
public bool Equals(AttributeQuery x, AttributeQuery y)
{
return
x.MemberInfo == y.MemberInfo &&
x.AttributeType == y.AttributeType;
}
public int GetHashCode(AttributeQuery obj)
{
return
obj.MemberInfo.GetHashCode() +
(17 * obj.AttributeType.GetHashCode());
}
}
#endregion Attribute Queries
#if !USE_TYPEINFO
private static BindingFlags DeclaredFlags =
BindingFlags.NonPublic |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.DeclaredOnly;
#endif
public static PropertyInfo GetDeclaredProperty(this Type type, string propertyName)
{
var props = GetDeclaredProperties(type);
for (var i = 0; i < props.Length; ++i)
{
if (props[i].Name == propertyName)
{
return props[i];
}
}
return null;
}
public static MethodInfo GetDeclaredMethod(this Type type, string methodName)
{
var methods = GetDeclaredMethods(type);
for (var i = 0; i < methods.Length; ++i)
{
if (methods[i].Name == methodName)
{
return methods[i];
}
}
return null;
}
public static ConstructorInfo GetDeclaredConstructor(this Type type, Type[] parameters)
{
var ctors = GetDeclaredConstructors(type);
for (var i = 0; i < ctors.Length; ++i)
{
var ctor = ctors[i];
var ctorParams = ctor.GetParameters();
if (parameters.Length != ctorParams.Length)
{
continue;
}
for (var j = 0; j < ctorParams.Length; ++j)
{
// require an exact match
if (ctorParams[j].ParameterType != parameters[j])
{
continue;
}
}
return ctor;
}
return null;
}
public static ConstructorInfo[] GetDeclaredConstructors(this Type type)
{
#if USE_TYPEINFO
return type.GetTypeInfo().DeclaredConstructors.ToArray();
#else
return type.GetConstructors(DeclaredFlags & ~BindingFlags.Static); // LUDIQ: Exclude static constructors
#endif
}
public static MemberInfo[] GetFlattenedMember(this Type type, string memberName)
{
var result = new List<MemberInfo>();
while (type != null)
{
var members = GetDeclaredMembers(type);
for (var i = 0; i < members.Length; ++i)
{
if (members[i].Name == memberName)
{
result.Add(members[i]);
}
}
type = type.Resolve().BaseType;
}
return result.ToArray();
}
public static MethodInfo GetFlattenedMethod(this Type type, string methodName)
{
while (type != null)
{
var methods = GetDeclaredMethods(type);
for (var i = 0; i < methods.Length; ++i)
{
if (methods[i].Name == methodName)
{
return methods[i];
}
}
type = type.Resolve().BaseType;
}
return null;
}
public static IEnumerable<MethodInfo> GetFlattenedMethods(this Type type, string methodName)
{
while (type != null)
{
var methods = GetDeclaredMethods(type);
for (var i = 0; i < methods.Length; ++i)
{
if (methods[i].Name == methodName)
{
yield return methods[i];
}
}
type = type.Resolve().BaseType;
}
}
public static PropertyInfo GetFlattenedProperty(this Type type, string propertyName)
{
while (type != null)
{
var properties = GetDeclaredProperties(type);
for (var i = 0; i < properties.Length; ++i)
{
if (properties[i].Name == propertyName)
{
return properties[i];
}
}
type = type.Resolve().BaseType;
}
return null;
}
public static MemberInfo GetDeclaredMember(this Type type, string memberName)
{
var members = GetDeclaredMembers(type);
for (var i = 0; i < members.Length; ++i)
{
if (members[i].Name == memberName)
{
return members[i];
}
}
return null;
}
public static MethodInfo[] GetDeclaredMethods(this Type type)
{
#if USE_TYPEINFO
return type.GetTypeInfo().DeclaredMethods.ToArray();
#else
return type.GetMethods(DeclaredFlags);
#endif
}
public static PropertyInfo[] GetDeclaredProperties(this Type type)
{
#if USE_TYPEINFO
return type.GetTypeInfo().DeclaredProperties.ToArray();
#else
return type.GetProperties(DeclaredFlags);
#endif
}
public static FieldInfo[] GetDeclaredFields(this Type type)
{
#if USE_TYPEINFO
return type.GetTypeInfo().DeclaredFields.ToArray();
#else
return type.GetFields(DeclaredFlags);
#endif
}
public static MemberInfo[] GetDeclaredMembers(this Type type)
{
#if USE_TYPEINFO
return type.GetTypeInfo().DeclaredMembers.ToArray();
#else
return type.GetMembers(DeclaredFlags);
#endif
}
public static MemberInfo AsMemberInfo(Type type)
{
#if USE_TYPEINFO
return type.GetTypeInfo();
#else
return type;
#endif
}
public static bool IsType(MemberInfo member)
{
#if USE_TYPEINFO
return member is TypeInfo;
#else
return member is Type;
#endif
}
public static Type AsType(MemberInfo member)
{
#if USE_TYPEINFO
return ((TypeInfo)member).AsType();
#else
return (Type)member;
#endif
}
#if USE_TYPEINFO
public static TypeInfo Resolve(this Type type)
{
return type.GetTypeInfo();
}
#else
public static Type Resolve(this Type type)
{
return type;
}
#endif
#region Extensions
#if USE_TYPEINFO_EXTENSIONS
public static bool IsAssignableFrom(this Type parent, Type child)
{
return parent.GetTypeInfo().IsAssignableFrom(child.GetTypeInfo());
}
public static Type GetElementType(this Type type)
{
return type.GetTypeInfo().GetElementType();
}
public static MethodInfo GetSetMethod(this PropertyInfo member, bool nonPublic = false)
{
// only public requested but the set method is not public
if (nonPublic == false && member.SetMethod != null && member.SetMethod.IsPublic == false) return null;
return member.SetMethod;
}
public static MethodInfo GetGetMethod(this PropertyInfo member, bool nonPublic = false)
{
// only public requested but the set method is not public
if (nonPublic == false && member.GetMethod != null && member.GetMethod.IsPublic == false) return null;
return member.GetMethod;
}
public static MethodInfo GetBaseDefinition(this MethodInfo method)
{
return method.GetRuntimeBaseDefinition();
}
public static Type[] GetInterfaces(this Type type)
{
return type.GetTypeInfo().ImplementedInterfaces.ToArray();
}
public static Type[] GetGenericArguments(this Type type)
{
return type.GetTypeInfo().GenericTypeArguments.ToArray();
}
#endif
#endregion Extensions
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e8457d68030d4970ae014b8a8aa5e28
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
#if !UNITY_EDITOR && UNITY_WSA
// For System.Reflection.TypeExtensions
using System.Reflection;
#endif
namespace Unity.VisualScripting.FullSerializer.Internal
{
public static class fsTypeExtensions
{
/// <summary>
/// Returns a pretty name for the type in the style of one that you'd see
/// in C# without the namespace.
/// </summary>
public static string CSharpName(this Type type)
{
return CSharpName(type, /*includeNamespace:*/ false);
}
public static string CSharpName(this Type type, bool includeNamespace, bool ensureSafeDeclarationName)
{
var name = CSharpName(type, includeNamespace);
if (ensureSafeDeclarationName)
{
name = name.Replace('>', '_').Replace('<', '_').Replace('.', '_');
}
return name;
}
/// <summary>
/// Returns a pretty name for the type in the style of one that you'd see
/// in C#.
/// </summary>
/// <parparam name="includeNamespace">
/// Should the name include namespaces?
/// </parparam>
public static string CSharpName(this Type type, bool includeNamespace)
{
// we special case some of the common type names
if (type == typeof(void))
{
return "void";
}
if (type == typeof(int))
{
return "int";
}
if (type == typeof(float))
{
return "float";
}
if (type == typeof(bool))
{
return "bool";
}
if (type == typeof(double))
{
return "double";
}
if (type == typeof(string))
{
return "string";
}
// Generic parameter, ie, T in Okay<T> We special-case this logic
// otherwise we will recurse on the T
if (type.IsGenericParameter)
{
return type.ToString();
}
var name = "";
var genericArguments = (IEnumerable<Type>)type.GetGenericArguments();
if (type.IsNested)
{
name += type.DeclaringType.CSharpName() + ".";
// The declaring type generic parameters are considered part of
// the nested types generic parameters so we need to remove them,
// otherwise it will get included again.
//
// Say we have type `class Parent<T> { class Child {} }` If we
// did not do the removal, then we would output
// Parent<T>.Child<T>, but we really want to output
// Parent<T>.Child
if (type.DeclaringType.GetGenericArguments().Length > 0)
{
genericArguments = genericArguments.Skip(type.DeclaringType.GetGenericArguments().Length);
}
}
if (genericArguments.Any() == false)
{
name += type.Name;
}
else
{
var genericsTic = type.Name.IndexOf('`');
if (genericsTic > 0)
{
name += type.Name.Substring(0, genericsTic);
}
name += "<" + String.Join(",", genericArguments.Select(t => CSharpName(t, includeNamespace)).ToArray()) + ">";
}
if (includeNamespace && type.Namespace != null)
{
name = type.Namespace + "." + name;
}
return name;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8e88fda4ffd5d4c97818a2f71560bd9c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,157 @@
using System;
using System.Collections.Generic;
namespace Unity.VisualScripting.FullSerializer.Internal
{
public static class fsVersionManager
{
private static readonly Dictionary<Type, fsOption<fsVersionedType>> _cache = new Dictionary<Type, fsOption<fsVersionedType>>();
public static fsResult GetVersionImportPath(string currentVersion, fsVersionedType targetVersion, out List<fsVersionedType> path)
{
path = new List<fsVersionedType>();
if (GetVersionImportPathRecursive(path, currentVersion, targetVersion) == false)
{
return fsResult.Fail("There is no migration path from \"" + currentVersion + "\" to \"" + targetVersion.VersionString + "\"");
}
path.Add(targetVersion);
return fsResult.Success;
}
private static bool GetVersionImportPathRecursive(List<fsVersionedType> path, string currentVersion, fsVersionedType current)
{
for (var i = 0; i < current.Ancestors.Length; ++i)
{
var ancestor = current.Ancestors[i];
if (ancestor.VersionString == currentVersion ||
GetVersionImportPathRecursive(path, currentVersion, ancestor))
{
path.Add(ancestor);
return true;
}
}
return false;
}
public static fsOption<fsVersionedType> GetVersionedType(Type type)
{
fsOption<fsVersionedType> optionalVersionedType;
if (_cache.TryGetValue(type, out optionalVersionedType) == false)
{
var attr = fsPortableReflection.GetAttribute<fsObjectAttribute>(type);
if (attr != null)
{
if (string.IsNullOrEmpty(attr.VersionString) == false || attr.PreviousModels != null)
{
// Version string must be provided
if (attr.PreviousModels != null && string.IsNullOrEmpty(attr.VersionString))
{
throw new Exception("fsObject attribute on " + type + " contains a PreviousModels specifier - it must also include a VersionString modifier");
}
// Map the ancestor types into versioned types
var ancestors = new fsVersionedType[attr.PreviousModels != null ? attr.PreviousModels.Length : 0];
for (var i = 0; i < ancestors.Length; ++i)
{
var ancestorType = GetVersionedType(attr.PreviousModels[i]);
if (ancestorType.IsEmpty)
{
throw new Exception("Unable to create versioned type for ancestor " + ancestorType + "; please add an [fsObject(VersionString=\"...\")] attribute");
}
ancestors[i] = ancestorType.Value;
}
// construct the actual versioned type instance
var versionedType = new fsVersionedType
{
Ancestors = ancestors,
VersionString = attr.VersionString,
ModelType = type
};
// finally, verify that the versioned type passes some
// sanity checks
VerifyUniqueVersionStrings(versionedType);
VerifyConstructors(versionedType);
optionalVersionedType = fsOption.Just(versionedType);
}
}
_cache[type] = optionalVersionedType;
}
return optionalVersionedType;
}
/// <summary>
/// Verifies that the given type has constructors to migrate from all
/// ancestor types.
/// </summary>
private static void VerifyConstructors(fsVersionedType type)
{
var publicConstructors = type.ModelType.GetDeclaredConstructors();
for (var i = 0; i < type.Ancestors.Length; ++i)
{
var requiredConstructorType = type.Ancestors[i].ModelType;
var found = false;
for (var j = 0; j < publicConstructors.Length; ++j)
{
var parameters = publicConstructors[j].GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == requiredConstructorType)
{
found = true;
break;
}
}
if (found == false)
{
throw new fsMissingVersionConstructorException(type.ModelType, requiredConstructorType);
}
}
}
/// <summary>
/// Verifies that the given version graph contains only unique versions.
/// </summary>
private static void VerifyUniqueVersionStrings(fsVersionedType type)
{
// simple tree traversal
var found = new Dictionary<string, Type>();
var remaining = new Queue<fsVersionedType>();
remaining.Enqueue(type);
while (remaining.Count > 0)
{
var item = remaining.Dequeue();
// Verify we do not already have the version string. Take into
// account that we're not just comparing the same model twice,
// since we can have a valid import graph that has the same model
// multiple times.
if (found.ContainsKey(item.VersionString) && found[item.VersionString] != item.ModelType)
{
throw new fsDuplicateVersionNameException(found[item.VersionString], item.ModelType, item.VersionString);
}
found[item.VersionString] = item.ModelType;
// scan the ancestors as well
foreach (var ancestor in item.Ancestors)
{
remaining.Enqueue(ancestor);
}
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b20bca1887a4a470897d494be7929520
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,57 @@
using System;
namespace Unity.VisualScripting.FullSerializer.Internal
{
public struct fsVersionedType
{
/// <summary>
/// The direct ancestors that this type can import.
/// </summary>
public fsVersionedType[] Ancestors;
/// <summary>
/// The identifying string that is unique among all ancestors.
/// </summary>
public string VersionString;
/// <summary>
/// The modeling type that this versioned type maps back to.
/// </summary>
public Type ModelType;
/// <summary>
/// Migrate from an instance of an ancestor.
/// </summary>
public object Migrate(object ancestorInstance)
{
return Activator.CreateInstance(ModelType, ancestorInstance);
}
public override string ToString()
{
return "fsVersionedType [ModelType=" + ModelType + ", VersionString=" + VersionString + ", Ancestors.Length=" + Ancestors.Length + "]";
}
public static bool operator ==(fsVersionedType a, fsVersionedType b)
{
return a.ModelType == b.ModelType;
}
public static bool operator !=(fsVersionedType a, fsVersionedType b)
{
return a.ModelType != b.ModelType;
}
public override bool Equals(object obj)
{
return
obj is fsVersionedType &&
ModelType == ((fsVersionedType)obj).ModelType;
}
public override int GetHashCode()
{
return ModelType.GetHashCode();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 201c5a374fe1842a591c42128390be5c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9ddd8c837d1c542b5aaf490022c44132
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,168 @@
using System;
using System.Reflection;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// A property or field on a MetaType. This unifies the FieldInfo and
/// PropertyInfo classes.
/// </summary>
public class fsMetaProperty
{
internal fsMetaProperty(fsConfig config, FieldInfo field)
{
_memberInfo = field;
StorageType = field.FieldType;
MemberName = field.Name;
IsPublic = field.IsPublic;
IsReadOnly = field.IsInitOnly;
CanRead = true;
CanWrite = true;
CommonInitialize(config);
}
internal fsMetaProperty(fsConfig config, PropertyInfo property)
{
_memberInfo = property;
StorageType = property.PropertyType;
MemberName = property.Name;
IsPublic = property.GetGetMethod() != null && property.GetGetMethod().IsPublic && property.GetSetMethod() != null && property.GetSetMethod().IsPublic;
IsReadOnly = false;
CanRead = property.CanRead;
CanWrite = property.CanWrite;
CommonInitialize(config);
}
/// <summary>
/// Internal handle to the reflected member.
/// </summary>
internal MemberInfo _memberInfo;
/// <summary>
/// The type of value that is stored inside of the property. For example,
/// for an int field, StorageType will be typeof(int).
/// </summary>
public Type StorageType { get; private set; }
/// <summary>
/// A custom fsBaseConverter instance to use for this field/property, if
/// requested. This will be null if the default converter selection
/// algorithm should be used. This is specified using the [fsObject]
/// annotation with the Converter field.
/// </summary>
public Type OverrideConverterType { get; private set; }
/// <summary>
/// Can this property be read?
/// </summary>
public bool CanRead { get; private set; }
/// <summary>
/// Can this property be written to?
/// </summary>
public bool CanWrite { get; private set; }
/// <summary>
/// The serialized name of the property, as it should appear in JSON.
/// </summary>
public string JsonName { get; private set; }
/// <summary>
/// The name of the actual member.
/// </summary>
public string MemberName { get; private set; }
/// <summary>
/// Is this member public?
/// </summary>
public bool IsPublic { get; private set; }
/// <summary>
/// Is this type readonly? We can modify readonly properties using
/// reflection, but not using generated C#.
/// </summary>
public bool IsReadOnly { get; private set; }
private void CommonInitialize(fsConfig config)
{
var attr = fsPortableReflection.GetAttribute<fsPropertyAttribute>(_memberInfo);
if (attr != null)
{
JsonName = attr.Name;
OverrideConverterType = attr.Converter;
}
if (string.IsNullOrEmpty(JsonName))
{
JsonName = config.GetJsonNameFromMemberName(MemberName, _memberInfo);
}
}
/// <summary>
/// Writes a value to the property that this MetaProperty represents,
/// using given object instance as the context.
/// </summary>
public void Write(object context, object value)
{
var field = _memberInfo as FieldInfo;
var property = _memberInfo as PropertyInfo;
if (field != null)
{
if (PlatformUtility.supportsJit)
{
field.SetValueOptimized(context, value);
}
else
{
field.SetValue(context, value);
}
}
else if (property != null)
{
if (PlatformUtility.supportsJit)
{
if (property.CanWrite)
{
property.SetValueOptimized(context, value);
}
}
else
{
var setMethod = property.GetSetMethod(/*nonPublic:*/ true);
if (setMethod != null)
{
setMethod.Invoke(context, new[] { value });
}
}
}
}
/// <summary>
/// Reads a value from the property that this MetaProperty represents,
/// using the given object instance as the context.
/// </summary>
public object Read(object context)
{
if (_memberInfo is PropertyInfo)
{
#if LUDIQ_OPTIMIZE
return ((PropertyInfo)_memberInfo).GetValueOptimized(context);
#else
return ((PropertyInfo)_memberInfo).GetValue(context, null); // Attempt fix-1588
#endif
}
else
{
#if LUDIQ_OPTIMIZE
return ((FieldInfo)_memberInfo).GetValueOptimized(context);
#else
return ((FieldInfo)_memberInfo).GetValue(context);
#endif
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 726bd1b4a2da44073b58af642cb2cd67
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,414 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// MetaType contains metadata about a type. This is used by the reflection
/// serializer.
/// </summary>
public class fsMetaType
{
private fsMetaType(fsConfig config, Type reflectedType)
{
ReflectedType = reflectedType;
var properties = new List<fsMetaProperty>();
CollectProperties(config, properties, reflectedType);
Properties = properties.ToArray();
}
public Type ReflectedType;
private bool _hasEmittedAotData;
private bool? _hasDefaultConstructorCache;
private bool _isDefaultConstructorPublic;
public fsMetaProperty[] Properties { get; private set; }
/// <summary>
/// Returns true if the type represented by this metadata contains a
/// default constructor.
/// </summary>
public bool HasDefaultConstructor
{
get
{
if (_hasDefaultConstructorCache.HasValue == false)
{
// arrays are considered to have a default constructor
if (ReflectedType.Resolve().IsArray)
{
_hasDefaultConstructorCache = true;
_isDefaultConstructorPublic = true;
}
// value types (ie, structs) always have a default
// constructor
else if (ReflectedType.Resolve().IsValueType)
{
_hasDefaultConstructorCache = true;
_isDefaultConstructorPublic = true;
}
else
{
// consider private constructors as well
var ctor = ReflectedType.GetDeclaredConstructor(fsPortableReflection.EmptyTypes);
_hasDefaultConstructorCache = ctor != null;
if (ctor != null)
{
_isDefaultConstructorPublic = ctor.IsPublic;
}
}
}
return _hasDefaultConstructorCache.Value;
}
}
/// <summary>
/// Attempt to emit an AOT compiled direct converter for this type.
/// </summary>
/// <returns>True if AOT data was emitted, false otherwise.</returns>
public bool EmitAotData()
{
if (_hasEmittedAotData == false)
{
_hasEmittedAotData = true;
// NOTE: Even if the type has derived types, we can still
// generate a direct converter for it. Direct converters are not
// used for inherited types, so the reflected converter or
// something similar will be used for the derived type instead of
// our AOT compiled one.
for (var i = 0; i < Properties.Length; ++i)
{
// Cannot AOT compile since we need to public member access.
if (Properties[i].IsPublic == false)
{
return false;
}
// Cannot AOT compile since readonly members can only be
// modified using reflection.
if (Properties[i].IsReadOnly)
{
return false;
}
}
// Cannot AOT compile since we need a default ctor.
if (HasDefaultConstructor == false)
{
return false;
}
fsAotCompilationManager.AddAotCompilation(ReflectedType, Properties, _isDefaultConstructorPublic);
return true;
}
return false;
}
/// <summary>
/// Creates a new instance of the type that this metadata points back to.
/// If this type has a default constructor, then Activator.CreateInstance
/// will be used to construct the type (or Array.CreateInstance if it an
/// array). Otherwise, an uninitialized object created via
/// FormatterServices.GetSafeUninitializedObject is used to construct the
/// instance.
/// </summary>
public object CreateInstance()
{
if (ReflectedType.Resolve().IsInterface || ReflectedType.Resolve().IsAbstract)
{
throw new Exception("Cannot create an instance of an interface or abstract type for " + ReflectedType);
}
#if !NO_UNITY
// Unity requires special construction logic for types that derive
// from ScriptableObject.
if (typeof(UnityEngine.ScriptableObject).IsAssignableFrom(ReflectedType))
{
return UnityEngine.ScriptableObject.CreateInstance(ReflectedType);
}
#endif
// Strings don't have default constructors but also fail when run
// through FormatterSerivces.GetSafeUninitializedObject
if (typeof(string) == ReflectedType)
{
return string.Empty;
}
if (HasDefaultConstructor == false)
{
#if !UNITY_EDITOR && (UNITY_WEBPLAYER || UNITY_WP8 || UNITY_METRO)
throw new InvalidOperationException("The selected Unity platform requires " +
ReflectedType.FullName + " to have a default constructor. Please add one.");
#else
return System.Runtime.Serialization.FormatterServices.GetSafeUninitializedObject(ReflectedType);
#endif
}
if (ReflectedType.Resolve().IsArray)
{
// we have to start with a size zero array otherwise it will have
// invalid data inside of it
return Array.CreateInstance(ReflectedType.GetElementType(), 0);
}
try
{
#if (!UNITY_EDITOR && (UNITY_METRO))
// In WinRT/WinStore builds, Activator.CreateInstance(..., true)
// is broken
return Activator.CreateInstance(ReflectedType);
#else
return Activator.CreateInstance(ReflectedType, /*nonPublic:*/ true);
#endif
}
#if (!UNITY_EDITOR && (UNITY_METRO)) == false
catch (MissingMethodException e)
{
throw new InvalidOperationException("Unable to create instance of " + ReflectedType + "; there is no default constructor", e);
}
#endif
catch (TargetInvocationException e)
{
throw new InvalidOperationException("Constructor of " + ReflectedType + " threw an exception when creating an instance", e);
}
catch (MemberAccessException e)
{
throw new InvalidOperationException("Unable to access constructor of " + ReflectedType, e);
}
}
private static Dictionary<fsConfig, Dictionary<Type, fsMetaType>> _configMetaTypes =
new Dictionary<fsConfig, Dictionary<Type, fsMetaType>>();
public static fsMetaType Get(fsConfig config, Type type)
{
Dictionary<Type, fsMetaType> metaTypes;
lock (typeof(fsMetaType))
{
if (_configMetaTypes.TryGetValue(config, out metaTypes) == false)
{
metaTypes = _configMetaTypes[config] = new Dictionary<Type, fsMetaType>();
}
}
fsMetaType metaType;
if (metaTypes.TryGetValue(type, out metaType) == false)
{
metaType = new fsMetaType(config, type);
metaTypes[type] = metaType;
}
return metaType;
}
/// <summary>
/// Clears out the cached type results. Useful if some prior assumptions
/// become invalid, ie, the default member serialization mode.
/// </summary>
public static void ClearCache()
{
lock (typeof(fsMetaType))
{
_configMetaTypes = new Dictionary<fsConfig, Dictionary<Type, fsMetaType>>();
}
}
private static void CollectProperties(fsConfig config, List<fsMetaProperty> properties, Type reflectedType)
{
// do we require a [SerializeField] or [fsProperty] attribute?
var requireOptIn = config.DefaultMemberSerialization == fsMemberSerialization.OptIn;
var requireOptOut = config.DefaultMemberSerialization == fsMemberSerialization.OptOut;
var attr = fsPortableReflection.GetAttribute<fsObjectAttribute>(reflectedType);
if (attr != null)
{
requireOptIn = attr.MemberSerialization == fsMemberSerialization.OptIn;
requireOptOut = attr.MemberSerialization == fsMemberSerialization.OptOut;
}
var members = reflectedType.GetDeclaredMembers();
foreach (var member in members)
{
// We don't serialize members annotated with any of the ignore
// serialize attributes
if (config.IgnoreSerializeAttributes.Any(t => fsPortableReflection.HasAttribute(member, t)))
{
continue;
}
var property = member as PropertyInfo;
var field = member as FieldInfo;
// Early out if it's neither a field or a property, since we
// don't serialize anything else.
if (property == null && field == null)
{
continue;
}
// Skip properties if we don't want them, to avoid the cost of
// checking attributes.
if (property != null && !config.EnablePropertySerialization)
{
continue;
}
// If an opt-in annotation is required, then skip the property if
// it doesn't have one of the serialize attributes
if (requireOptIn &&
!config.SerializeAttributes.Any(t => fsPortableReflection.HasAttribute(member, t)))
{
continue;
}
// If an opt-out annotation is required, then skip the property
// *only if* it has one of the not serialize attributes
if (requireOptOut &&
config.IgnoreSerializeAttributes.Any(t => fsPortableReflection.HasAttribute(member, t)))
{
continue;
}
if (property != null)
{
if (CanSerializeProperty(config, property, members, requireOptOut))
{
properties.Add(new fsMetaProperty(config, property));
}
}
else if (field != null)
{
if (CanSerializeField(config, field, requireOptOut))
{
properties.Add(new fsMetaProperty(config, field));
}
}
}
if (reflectedType.Resolve().BaseType != null)
{
CollectProperties(config, properties, reflectedType.Resolve().BaseType);
}
}
private static bool IsAutoProperty(PropertyInfo property, MemberInfo[] members)
{
return
property.CanWrite && property.CanRead &&
fsPortableReflection.HasAttribute(
property.GetGetMethod(), typeof(CompilerGeneratedAttribute), /*shouldCache:*/ false);
}
/// <summary>
/// Returns if the given property should be serialized.
/// </summary>
/// <param name="annotationFreeValue">
/// Should a property without any annotations be serialized?
/// </param>
private static bool CanSerializeProperty(fsConfig config, PropertyInfo property, MemberInfo[] members, bool annotationFreeValue)
{
// We don't serialize delegates
if (typeof(Delegate).IsAssignableFrom(property.PropertyType))
{
return false;
}
var publicGetMethod = property.GetGetMethod(/*nonPublic:*/ false);
var publicSetMethod = property.GetSetMethod(/*nonPublic:*/ false);
// We do not bother to serialize static fields.
if ((publicGetMethod != null && publicGetMethod.IsStatic) ||
(publicSetMethod != null && publicSetMethod.IsStatic))
{
return false;
}
// Never serialize indexers. I can't think of a sane way to
// serialize/deserialize them, and they're normally wrappers around
// other fields anyway...
if (property.GetIndexParameters().Length > 0)
{
return false;
}
// If a property is annotated with one of the serializable
// attributes, then it should it should definitely be serialized.
//
// NOTE: We place this override check *after* the static check,
// because we *never* allow statics to be serialized.
if (config.SerializeAttributes.Any(t => fsPortableReflection.HasAttribute(property, t)))
{
return true;
}
// If the property cannot be both read and written to, we are not
// going to serialize it regardless of the default serialization mode
if (property.CanRead == false || property.CanWrite == false)
{
return false;
}
// Depending on the configuration options, check whether the property
// is automatic and if it has a public setter to determine whether it
// should be serialized
if ((publicGetMethod != null && (config.SerializeNonPublicSetProperties || publicSetMethod != null)) &&
(config.SerializeNonAutoProperties || IsAutoProperty(property, members)))
{
return true;
}
// Otherwise, we don't bother with serialization
return annotationFreeValue;
}
private static bool CanSerializeField(fsConfig config, FieldInfo field, bool annotationFreeValue)
{
// We don't serialize delegates
if (typeof(Delegate).IsAssignableFrom(field.FieldType))
{
return false;
}
// We don't serialize compiler generated fields.
// LAZLO / LUDIQ FIX: Attributes inheritance
if (Attribute.IsDefined(field, typeof(CompilerGeneratedAttribute), false))
{
return false;
}
// We don't serialize static fields
if (field.IsStatic)
{
return false;
}
// We want to serialize any fields annotated with one of the
// serialize attributes.
//
// NOTE: This occurs *after* the static check, because we *never*
// want to serialize static fields.
if (config.SerializeAttributes.Any(t => fsPortableReflection.HasAttribute(field, t)))
{
return true;
}
// We use !IsPublic because that also checks for internal, protected,
// and private.
if (!annotationFreeValue && !field.IsPublic)
{
return false;
}
return true;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8cacd6b711f9c44b2bcaeee005d77210
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,61 @@
using System;
using Unity.VisualScripting.FullSerializer.Internal;
#if !UNITY_EDITOR && UNITY_WSA
// For System.Reflection.TypeExtensions
using System.Reflection;
#endif
namespace Unity.VisualScripting.FullSerializer
{
public static class fsReflectionUtility
{
/// <summary>
/// Searches for a particular implementation of the given interface type
/// inside of the type. This is particularly useful if the interface type
/// is an open type, ie, typeof(IFace{}), because this method will then
/// return IFace{} but with appropriate type parameters inserted.
/// </summary>
/// <param name="type">The base type to search for interface</param>
/// <param name="interfaceType">
/// The interface type to search for. Can be an open generic type.
/// </param>
/// <returns>
/// The actual interface type that the type contains, or null if there is
/// no implementation of the given interfaceType on type.
/// </returns>
public static Type GetInterface(Type type, Type interfaceType)
{
if (interfaceType.Resolve().IsGenericType &&
interfaceType.Resolve().IsGenericTypeDefinition == false)
{
throw new ArgumentException("GetInterface requires that if the interface " +
"type is generic, then it must be the generic type definition, not a " +
"specific generic type instantiation");
}
;
while (type != null)
{
foreach (var iface in type.GetInterfaces())
{
if (iface.Resolve().IsGenericType)
{
if (interfaceType == iface.GetGenericTypeDefinition())
{
return iface;
}
}
else if (interfaceType == iface)
{
return iface;
}
}
type = type.Resolve().BaseType;
}
return null;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 51067c71ac63e4194be5651f0c1a32ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// Caches type name to type lookups. Type lookups occur in all loaded
/// assemblies.
/// </summary>
public static class fsTypeCache
{
// Moved / converted to RuntimeCodebase
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 75dc9dc2af22844e2a7d47d23b127f49
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using System.Text;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// The AOT compilation manager
/// </summary>
public class fsAotCompilationManager
{
private static Dictionary<Type, string> _computedAotCompilations = new Dictionary<Type, string>();
private static List<AotCompilation> _uncomputedAotCompilations = new List<AotCompilation>();
/// <summary>
/// Ahead of time compilations that are available. The type maps to the
/// object type the generated converter will serialize/deserialize, and
/// the string is the text content for a converter that will do the
/// serialization.
/// <para />
/// The generated serializer is completely independent and you don't need
/// to do anything. Simply add the file to your project and it'll get
/// used instead of the reflection based one.
/// </summary>
public static Dictionary<Type, string> AvailableAotCompilations
{
get
{
for (var i = 0; i < _uncomputedAotCompilations.Count; ++i)
{
var item = _uncomputedAotCompilations[i];
_computedAotCompilations[item.Type] = GenerateDirectConverterForTypeInCSharp(item.Type, item.Members, item.IsConstructorPublic);
}
_uncomputedAotCompilations.Clear();
return _computedAotCompilations;
}
}
/// <summary>
/// This is a helper method that makes it simple to run an AOT
/// compilation on the given type.
/// </summary>
/// <param name="config">
/// The configuration to use when running AOT compilation.
/// </param>
/// <param name="type">
/// The type to perform the AOT compilation on.
/// </param>
/// <param name="aotCompiledClassInCSharp">
/// The AOT class. Add this C# code to your project.
/// </param>
/// <returns>True if AOT compilation was successful.</returns>
public static bool TryToPerformAotCompilation(fsConfig config, Type type, out string aotCompiledClassInCSharp)
{
if (fsMetaType.Get(config, type).EmitAotData())
{
aotCompiledClassInCSharp = AvailableAotCompilations[type];
return true;
}
aotCompiledClassInCSharp = default(string);
return false;
}
/// <summary>
/// Adds a new AOT compilation unit.
/// </summary>
/// <param name="type">The type of object we are AOT compiling.</param>
/// <param name="members">
/// The members on the object which will be serialized/deserialized.
/// </param>
public static void AddAotCompilation(Type type, fsMetaProperty[] members, bool isConstructorPublic)
{
_uncomputedAotCompilations.Add(new AotCompilation
{
Type = type,
Members = members,
IsConstructorPublic = isConstructorPublic
});
}
private static string GetConverterString(fsMetaProperty member)
{
if (member.OverrideConverterType == null)
{
return "null";
}
return $"typeof({fsTypeExtensions.CSharpName( /*includeNamespace:*/member.OverrideConverterType, true)})";
}
/// <summary>
/// AOT compiles the object (in C#).
/// </summary>
private static string GenerateDirectConverterForTypeInCSharp(Type type, fsMetaProperty[] members, bool isConstructorPublic)
{
var sb = new StringBuilder();
var typeName = fsTypeExtensions.CSharpName( /*includeNamespace:*/
type, true);
var typeNameSafeDecl = type.CSharpName(true, true);
sb.AppendLine("using System;");
sb.AppendLine("using System.Collections.Generic;");
sb.AppendLine();
sb.AppendLine("namespace Unity.VisualScripting.Dependencies.FullSerializer {");
sb.AppendLine(" partial class fsConverterRegistrar {");
sb.AppendLine(" public static Speedup." + typeNameSafeDecl + "_DirectConverter " + "Register_" + typeNameSafeDecl + ";");
sb.AppendLine(" }");
sb.AppendLine("}");
sb.AppendLine();
sb.AppendLine("namespace Unity.VisualScripting.Dependencies.FullSerializer.Speedup {");
sb.AppendLine(" public class " + typeNameSafeDecl + "_DirectConverter : fsDirectConverter<" + typeName + "> {");
sb.AppendLine(" protected override fsResult DoSerialize(" + typeName + " model, Dictionary<string, fsData> serialized) {");
sb.AppendLine(" var result = fsResult.Success;");
sb.AppendLine();
foreach (var member in members)
{
sb.AppendLine(" result += SerializeMember(serialized, " + GetConverterString(member) + ", \"" + member.JsonName + "\", model." + member.MemberName + ");");
}
sb.AppendLine();
sb.AppendLine(" return result;");
sb.AppendLine(" }");
sb.AppendLine();
sb.AppendLine(" protected override fsResult DoDeserialize(Dictionary<string, fsData> data, ref " + typeName + " model) {");
sb.AppendLine(" var result = fsResult.Success;");
sb.AppendLine();
for (var i = 0; i < members.Length; ++i)
{
var member = members[i];
sb.AppendLine(" var t" + i + " = model." + member.MemberName + ";");
sb.AppendLine(" result += DeserializeMember(data, " + GetConverterString(member) + ", \"" + member.JsonName + "\", out t" + i + ");");
sb.AppendLine(" model." + member.MemberName + " = t" + i + ";");
sb.AppendLine();
}
sb.AppendLine(" return result;");
sb.AppendLine(" }");
sb.AppendLine();
sb.AppendLine(" public override object CreateInstance(fsData data, Type storageType) {");
if (isConstructorPublic)
{
sb.AppendLine(" return new " + typeName + "();");
}
else
{
sb.AppendLine(" return Activator.CreateInstance(typeof(" + typeName + "), /*nonPublic:*/true);");
}
sb.AppendLine(" }");
sb.AppendLine(" }");
sb.AppendLine("}");
return sb.ToString();
}
private struct AotCompilation
{
public Type Type;
public fsMetaProperty[] Members;
public bool IsConstructorPublic;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f658832818572457f80abe66f86cc055
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,161 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// The serialization converter allows for customization of the serialization
/// process.
/// </summary>
/// <remarks>
/// You do not want to derive from this class - there is no way to actually
/// use it within the serializer.. Instead, derive from either fsConverter or
/// fsDirectConverter
/// </remarks>
public abstract class fsBaseConverter
{
/// <summary>
/// The serializer that was owns this converter.
/// </summary>
public fsSerializer Serializer;
/// <summary>
/// Construct an object instance that will be passed to TryDeserialize.
/// This should **not** deserialize the object.
/// </summary>
/// <param name="data">The data the object was serialized with.</param>
/// <param name="storageType">
/// The field/property type that is storing the instance.
/// </param>
/// <returns>An object instance</returns>
public virtual object CreateInstance(fsData data, Type storageType)
{
if (RequestCycleSupport(storageType))
{
throw new InvalidOperationException("Please override CreateInstance for " +
GetType() + "; the object graph for " + storageType +
" can contain potentially contain cycles, so separated instance creation " +
"is needed");
}
return storageType;
}
/// <summary>
/// If true, then the serializer will support cyclic references with the
/// given converted type.
/// </summary>
/// <param name="storageType">
/// The field/property type that is currently storing the object that is
/// being serialized.
/// </param>
public virtual bool RequestCycleSupport(Type storageType)
{
if (storageType == typeof(string))
{
return false;
}
return storageType.Resolve().IsClass || storageType.Resolve().IsInterface;
}
/// <summary>
/// If true, then the serializer will include inheritance data for the
/// given converter.
/// </summary>
/// <param name="storageType">
/// The field/property type that is currently storing the object that is
/// being serialized.
/// </param>
public virtual bool RequestInheritanceSupport(Type storageType)
{
return storageType.Resolve().IsSealed == false;
}
/// <summary>
/// Serialize the actual object into the given data storage.
/// </summary>
/// <param name="instance">
/// The object instance to serialize. This will never be null.
/// </param>
/// <param name="serialized">The serialized state.</param>
/// <param name="storageType">
/// The field/property type that is storing this instance.
/// </param>
/// <returns>If serialization was successful.</returns>
public abstract fsResult TrySerialize(object instance, out fsData serialized, Type storageType);
/// <summary>
/// Deserialize data into the object instance.
/// </summary>
/// <param name="data">Serialization data to deserialize from.</param>
/// <param name="instance">
/// The object instance to deserialize into.
/// </param>
/// <param name="storageType">
/// The field/property type that is storing the instance.
/// </param>
/// <returns>
/// True if serialization was successful, false otherwise.
/// </returns>
public abstract fsResult TryDeserialize(fsData data, ref object instance, Type storageType);
protected fsResult FailExpectedType(fsData data, params fsDataType[] types)
{
return fsResult.Fail(GetType().Name + " expected one of " +
string.Join(", ", types.Select(t => t.ToString()).ToArray()) +
" but got " + data.Type + " in " + data);
}
protected fsResult CheckType(fsData data, fsDataType type)
{
if (data.Type != type)
{
return fsResult.Fail(GetType().Name + " expected " + type + " but got " + data.Type + " in " + data);
}
return fsResult.Success;
}
protected fsResult CheckKey(fsData data, string key, out fsData subitem)
{
return CheckKey(data.AsDictionary, key, out subitem);
}
protected fsResult CheckKey(Dictionary<string, fsData> data, string key, out fsData subitem)
{
if (data.TryGetValue(key, out subitem) == false)
{
return fsResult.Fail(GetType().Name + " requires a <" + key + "> key in the data " + data);
}
return fsResult.Success;
}
protected fsResult SerializeMember<T>(Dictionary<string, fsData> data, Type overrideConverterType, string name, T value)
{
fsData memberData;
var result = Serializer.TrySerialize(typeof(T), overrideConverterType, value, out memberData);
if (result.Succeeded)
{
data[name] = memberData;
}
return result;
}
protected fsResult DeserializeMember<T>(Dictionary<string, fsData> data, Type overrideConverterType, string name, out T value)
{
fsData memberData;
if (data.TryGetValue(name, out memberData) == false)
{
value = default(T);
return fsResult.Fail("Unable to find member \"" + name + "\"");
}
object storage = null;
var result = Serializer.TryDeserialize(memberData, typeof(T), overrideConverterType, ref storage);
value = (T)storage;
return result;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c7e2ff8b37f14fb29e741eea37c4af1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,115 @@
using System;
using System.Reflection;
namespace Unity.VisualScripting.FullSerializer
{
// Global configuration options.
public static class fsGlobalConfig
{
/// <summary>
/// Should deserialization be case sensitive? If this is false and the
/// JSON has multiple members with the same keys only separated by case,
/// then this results in undefined behavior.
/// </summary>
public static bool IsCaseSensitive = true;
/// <summary>
/// If exceptions are allowed internally, then additional date formats
/// can be deserialized. Note that the Full Serializer public API will
/// *not* throw exceptions with this enabled; errors will still be
/// returned in a fsResult instance.
/// </summary>
public static bool AllowInternalExceptions = true;
/// <summary>
/// This string will be used to prefix fields used internally by
/// FullSerializer.
/// </summary>
public static string InternalFieldPrefix = "$";
}
/// <summary>
/// Enables some top-level customization of Full Serializer.
/// </summary>
public class fsConfig
{
/// <summary>
/// The attributes that will force a field or property to be serialized.
/// </summary>
public Type[] SerializeAttributes =
{
#if !NO_UNITY
typeof(UnityEngine.SerializeField),
#endif
typeof(fsPropertyAttribute),
typeof(SerializeAttribute),
typeof(SerializeAsAttribute)
};
/// <summary>
/// The attributes that will force a field or property to *not* be
/// serialized.
/// </summary>
public Type[] IgnoreSerializeAttributes =
{
typeof(NonSerializedAttribute),
typeof(fsIgnoreAttribute),
typeof(DoNotSerializeAttribute)
};
/// <summary>
/// The default member serialization.
/// </summary>
public fsMemberSerialization DefaultMemberSerialization = fsMemberSerialization.Default;
/// <summary>
/// Convert a C# field/property name into the key used for the JSON
/// object. For example, you could force all JSON names to lowercase
/// with:
/// fsConfig.GetJsonNameFromMemberName = (name, info) =&gt;
/// name.ToLower();
/// This will only be used when the name is not explicitly specified with
/// fsProperty.
/// </summary>
public Func<string, MemberInfo, string> GetJsonNameFromMemberName = (name, info) => name;
/// <summary>
/// If false, then *all* property serialization support will be disabled
/// - even properties explicitly annotated with fsProperty or any other
/// opt-in annotation.
/// Setting this to false means that SerializeNonAutoProperties and
/// SerializeNonPublicSetProperties will be completely ignored.
/// </summary>
public bool EnablePropertySerialization = true;
/// <summary>
/// Should the default serialization behaviour include non-auto
/// properties?
/// </summary>
public bool SerializeNonAutoProperties = false;
/// <summary>
/// Should the default serialization behaviour include properties with
/// non-public setters?
/// </summary>
public bool SerializeNonPublicSetProperties = true;
/// <summary>
/// If not null, this string format will be used for DateTime instead of
/// the default one.
/// </summary>
public string CustomDateTimeFormatString = null;
/// <summary>
/// Int64 and UInt64 will be serialized and deserialized as string for
/// compatibility
/// </summary>
public bool Serialize64BitIntegerAsString = false;
/// <summary>
/// Enums are serialized using their names by default. Setting this to
/// true will serialize them as integers instead.
/// </summary>
public bool SerializeEnumsAsInteger = false;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98d16b6826cab47639c1c29e2a9ed97d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// fsContext stores global metadata that can be used to customize how
/// fsConverters operate during serialization.
/// </summary>
public sealed class fsContext
{
/// <summary>
/// All of the context objects.
/// </summary>
private readonly Dictionary<Type, object> _contextObjects = new Dictionary<Type, object>();
/// <summary>
/// Removes all context objects from the context.
/// </summary>
public void Reset()
{
_contextObjects.Clear();
}
/// <summary>
/// Sets the context object for the given type with the given value.
/// </summary>
public void Set<T>(T obj)
{
_contextObjects[typeof(T)] = obj;
}
/// <summary>
/// Returns true if there is a context object for the given type.
/// </summary>
public bool Has<T>()
{
return _contextObjects.ContainsKey(typeof(T));
}
/// <summary>
/// Fetches the context object for the given type.
/// </summary>
public T Get<T>()
{
object val;
if (_contextObjects.TryGetValue(typeof(T), out val))
{
return (T)val;
}
throw new InvalidOperationException("There is no context object of type " + typeof(T));
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2056e0c2ed99946f2aa0b59a7d523406
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,20 @@
using System;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// The serialization converter allows for customization of the serialization
/// process.
/// </summary>
public abstract class fsConverter : fsBaseConverter
{
/// <summary>
/// Can this converter serialize and deserialize the given object type?
/// </summary>
/// <param name="type">The given object type.</param>
/// <returns>
/// True if the converter can serialize it, false otherwise.
/// </returns>
public abstract bool CanProcess(Type type);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 14260676d94004f02b41b5c7844458fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using Unity.VisualScripting.FullSerializer.Internal;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// This class allows arbitrary code to easily register global converters. To
/// add a converter, simply declare a new field called "Register_*" that
/// stores the type of converter you would like to add. Alternatively, you
/// can do the same with a method called "Register_*"; just add the converter
/// type to the `Converters` list.
/// </summary>
public partial class fsConverterRegistrar
{
static fsConverterRegistrar()
{
Converters = new List<Type>();
foreach (var field in typeof(fsConverterRegistrar).GetDeclaredFields())
{
if (field.Name.StartsWith("Register_"))
{
Converters.Add(field.FieldType);
}
}
foreach (var method in typeof(fsConverterRegistrar).GetDeclaredMethods())
{
if (method.Name.StartsWith("Register_"))
{
method.Invoke(null, null);
}
}
}
public static List<Type> Converters;
//public static AnimationCurve_DirectConverter Register_AnimationCurve_DirectConverter;
// Example field registration:
// Example method registration:
//public static void Register_AnimationCurve_DirectConverter() {
// Converters.Add(typeof(AnimationCurve_DirectConverter));
//}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cbda48de6424242dcbc9f142e5a80c40
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,425 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// The actual type that a JsonData instance can store.
/// </summary>
public enum fsDataType
{
Array,
Object,
Double,
Int64,
Boolean,
String,
Null
}
/// <summary>
/// A union type that stores a serialized value. The stored type can be one
/// of six different
/// types: null, boolean, double, Int64, string, Dictionary, or List.
/// </summary>
public sealed class fsData
{
/// <summary>
/// The raw value that this serialized data stores. It can be one of six
/// different types; a boolean, a double, Int64, a string, a Dictionary,
/// or a List.
/// </summary>
private object _value;
#region ToString Implementation
public override string ToString()
{
return fsJsonPrinter.CompressedJson(this);
}
#endregion ToString Implementation
#region Constructors
/// <summary>
/// Creates a fsData instance that holds null.
/// </summary>
public fsData()
{
_value = null;
}
/// <summary>
/// Creates a fsData instance that holds a boolean.
/// </summary>
public fsData(bool boolean)
{
_value = boolean;
}
/// <summary>
/// Creates a fsData instance that holds a double.
/// </summary>
public fsData(double f)
{
_value = f;
}
/// <summary>
/// Creates a new fsData instance that holds an integer.
/// </summary>
public fsData(Int64 i)
{
_value = i;
}
/// <summary>
/// Creates a fsData instance that holds a string.
/// </summary>
public fsData(string str)
{
_value = str;
}
/// <summary>
/// Creates a fsData instance that holds a dictionary of values.
/// </summary>
public fsData(Dictionary<string, fsData> dict)
{
_value = dict;
}
/// <summary>
/// Creates a fsData instance that holds a list of values.
/// </summary>
public fsData(List<fsData> list)
{
_value = list;
}
/// <summary>
/// Helper method to create a fsData instance that holds a dictionary.
/// </summary>
public static fsData CreateDictionary()
{
return new fsData(new Dictionary<string, fsData>(
fsGlobalConfig.IsCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase));
}
/// <summary>
/// Helper method to create a fsData instance that holds a list.
/// </summary>
public static fsData CreateList()
{
return new fsData(new List<fsData>());
}
/// <summary>
/// Helper method to create a fsData instance that holds a list with the
/// initial capacity.
/// </summary>
public static fsData CreateList(int capacity)
{
return new fsData(new List<fsData>(capacity));
}
public readonly static fsData True = new fsData(true);
public readonly static fsData False = new fsData(false);
public readonly static fsData Null = new fsData();
#endregion Constructors
#region Internal Helper Methods
/// <summary>
/// Transforms the internal fsData instance into a dictionary.
/// </summary>
internal void BecomeDictionary()
{
_value = new Dictionary<string, fsData>();
}
/// <summary>
/// Returns a shallow clone of this data instance.
/// </summary>
internal fsData Clone()
{
var clone = new fsData();
clone._value = _value;
return clone;
}
#endregion Internal Helper Methods
#region Casting Predicates
public fsDataType Type
{
get
{
if (_value == null)
{
return fsDataType.Null;
}
if (_value is double)
{
return fsDataType.Double;
}
if (_value is Int64)
{
return fsDataType.Int64;
}
if (_value is bool)
{
return fsDataType.Boolean;
}
if (_value is string)
{
return fsDataType.String;
}
if (_value is Dictionary<string, fsData>)
{
return fsDataType.Object;
}
if (_value is List<fsData>)
{
return fsDataType.Array;
}
throw new InvalidOperationException("unknown JSON data type");
}
}
/// <summary>
/// Returns true if this fsData instance maps back to null.
/// </summary>
public bool IsNull => _value == null;
/// <summary>
/// Returns true if this fsData instance maps back to a double.
/// </summary>
public bool IsDouble => _value is double;
/// <summary>
/// Returns true if this fsData instance maps back to an Int64.
/// </summary>
public bool IsInt64 => _value is Int64;
/// <summary>
/// Returns true if this fsData instance maps back to a boolean.
/// </summary>
public bool IsBool => _value is bool;
/// <summary>
/// Returns true if this fsData instance maps back to a string.
/// </summary>
public bool IsString => _value is string;
/// <summary>
/// Returns true if this fsData instance maps back to a Dictionary.
/// </summary>
public bool IsDictionary => _value is Dictionary<string, fsData>;
/// <summary>
/// Returns true if this fsData instance maps back to a List.
/// </summary>
public bool IsList => _value is List<fsData>;
#endregion Casting Predicates
#region Casts
/// <summary>
/// Casts this fsData to a double. Throws an exception if it is not a
/// double.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public double AsDouble => Cast<double>();
/// <summary>
/// Casts this fsData to an Int64. Throws an exception if it is not an
/// Int64.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Int64 AsInt64 => Cast<Int64>();
/// <summary>
/// Casts this fsData to a boolean. Throws an exception if it is not a
/// boolean.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public bool AsBool => Cast<bool>();
/// <summary>
/// Casts this fsData to a string. Throws an exception if it is not a
/// string.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public string AsString => Cast<string>();
/// <summary>
/// Casts this fsData to a Dictionary. Throws an exception if it is not a
/// Dictionary.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public Dictionary<string, fsData> AsDictionary => Cast<Dictionary<string, fsData>>();
/// <summary>
/// Casts this fsData to a List. Throws an exception if it is not a List.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public List<fsData> AsList => Cast<List<fsData>>();
/// <summary>
/// Internal helper method to cast the underlying storage to the given
/// type or throw a pretty printed exception on failure.
/// </summary>
private T Cast<T>()
{
if (_value is T)
{
return (T)_value;
}
throw new InvalidCastException("Unable to cast <" + this + "> (with type = " +
_value.GetType() + ") to type " + typeof(T));
}
#endregion Casts
#region Equality Comparisons
/// <summary>
/// Determines whether the specified object is equal to the current
/// object.
/// </summary>
public override bool Equals(object obj)
{
return Equals(obj as fsData);
}
/// <summary>
/// Determines whether the specified object is equal to the current
/// object.
/// </summary>
public bool Equals(fsData other)
{
if (other == null || Type != other.Type)
{
return false;
}
switch (Type)
{
case fsDataType.Null:
return true;
case fsDataType.Double:
return AsDouble == other.AsDouble || Math.Abs(AsDouble - other.AsDouble) < double.Epsilon;
case fsDataType.Int64:
return AsInt64 == other.AsInt64;
case fsDataType.Boolean:
return AsBool == other.AsBool;
case fsDataType.String:
return AsString == other.AsString;
case fsDataType.Array:
var thisList = AsList;
var otherList = other.AsList;
if (thisList.Count != otherList.Count)
{
return false;
}
for (var i = 0; i < thisList.Count; ++i)
{
if (thisList[i].Equals(otherList[i]) == false)
{
return false;
}
}
return true;
case fsDataType.Object:
var thisDict = AsDictionary;
var otherDict = other.AsDictionary;
if (thisDict.Count != otherDict.Count)
{
return false;
}
foreach (var key in thisDict.Keys)
{
if (otherDict.ContainsKey(key) == false)
{
return false;
}
if (thisDict[key].Equals(otherDict[key]) == false)
{
return false;
}
}
return true;
}
throw new Exception("Unknown data type");
}
/// <summary>
/// Returns true iff a == b.
/// </summary>
public static bool operator ==(fsData a, fsData b)
{
// If both are null, or both are same instance, return true.
if (ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
if (a.IsDouble && b.IsDouble)
{
return Math.Abs(a.AsDouble - b.AsDouble) < double.Epsilon;
}
return a.Equals(b);
}
/// <summary>
/// Returns true iff a != b.
/// </summary>
public static bool operator !=(fsData a, fsData b)
{
return !(a == b);
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms
/// and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
return _value.GetHashCode();
}
#endregion Equality Comparisons
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3520c694a43b048559591ea21c37a8d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// The direct converter is similar to a regular converter, except that it
/// targets specifically only one type. This means that it can be used
/// without performance impact when discovering converters. It is strongly
/// recommended that you derive from fsDirectConverter{TModel}.
/// </summary>
/// <remarks>
/// Due to the way that direct converters operate, inheritance is *not*
/// supported. Direct converters will only be used with the exact ModelType
/// object.
/// </remarks>
public abstract class fsDirectConverter : fsBaseConverter
{
public abstract Type ModelType { get; }
}
public abstract class fsDirectConverter<TModel> : fsDirectConverter
{
public override Type ModelType => typeof(TModel);
public sealed override fsResult TrySerialize(object instance, out fsData serialized, Type storageType)
{
var serializedDictionary = new Dictionary<string, fsData>();
var result = DoSerialize((TModel)instance, serializedDictionary);
serialized = new fsData(serializedDictionary);
return result;
}
public sealed override fsResult TryDeserialize(fsData data, ref object instance, Type storageType)
{
var result = fsResult.Success;
if ((result += CheckType(data, fsDataType.Object)).Failed)
{
return result;
}
var obj = (TModel)instance;
result += DoDeserialize(data.AsDictionary, ref obj);
instance = obj;
return result;
}
protected abstract fsResult DoSerialize(TModel model, Dictionary<string, fsData> serialized);
protected abstract fsResult DoDeserialize(Dictionary<string, fsData> data, ref TModel model);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a458c80bcb97443e9e611c09e5ca71a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
// note: This file contains exceptions used by FullSerializer. Exceptions are
// never used at runtime in FullSerializer; they are only used when
// validating annotations and code-based models.
using System;
namespace Unity.VisualScripting.FullSerializer
{
public sealed class fsMissingVersionConstructorException : Exception
{
public fsMissingVersionConstructorException(Type versionedType, Type constructorType) :
base(versionedType + " is missing a constructor for previous model type " + constructorType)
{ }
}
public sealed class fsDuplicateVersionNameException : Exception
{
public fsDuplicateVersionNameException(Type typeA, Type typeB, string version) :
base(typeA + " and " + typeB + " have the same version string (" + version + "); please change one of them.")
{ }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 521bba425c159452e902b0b73f80e68c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,131 @@
using System;
using UnityEngine;
using UnityObject = UnityEngine.Object;
namespace Unity.VisualScripting.FullSerializer
{
#if !UNITY_EDITOR && UNITY_WSA
// For System.Reflection.TypeExtensions
using System.Reflection;
#endif
/// <summary>
/// Extend this interface on your type to receive notifications about
/// serialization/deserialization events. If you don't have access to the
/// type itself, then you can write an fsObjectProcessor instead.
/// </summary>
public interface fsISerializationCallbacks
{
/// <summary>
/// Called before serialization.
/// </summary>
void OnBeforeSerialize(Type storageType);
/// <summary>
/// Called after serialization.
/// </summary>
/// <param name="storageType">
/// The field/property type that is storing the instance.
/// </param>
/// <param name="data">The data that was serialized.</param>
void OnAfterSerialize(Type storageType, ref fsData data);
/// <summary>
/// Called before deserialization.
/// </summary>
/// <param name="storageType">
/// The field/property type that is storing the instance.
/// </param>
/// <param name="data">
/// The data that will be used for deserialization.
/// </param>
void OnBeforeDeserialize(Type storageType, ref fsData data);
/// <summary>
/// Called after deserialization.
/// </summary>
/// <param name="storageType">
/// The field/property type that is storing the instance.
/// </param>
/// <param name="instance">The type of the instance.</param>
void OnAfterDeserialize(Type storageType);
}
public class fsSerializationCallbackProcessor : fsObjectProcessor
{
public override bool CanProcess(Type type)
{
return typeof(fsISerializationCallbacks).IsAssignableFrom(type);
}
public override void OnBeforeSerialize(Type storageType, object instance)
{
// Don't call the callback on null instances.
if (instance == null)
{
return;
}
((fsISerializationCallbacks)instance).OnBeforeSerialize(storageType);
}
public override void OnAfterSerialize(Type storageType, object instance, ref fsData data)
{
// Don't call the callback on null instances.
if (instance == null)
{
return;
}
((fsISerializationCallbacks)instance).OnAfterSerialize(storageType, ref data);
}
public override void OnBeforeDeserializeAfterInstanceCreation(Type storageType, object instance, ref fsData data)
{
if (instance is fsISerializationCallbacks == false)
{
throw new InvalidCastException("Please ensure the converter for " + storageType + " actually returns an instance of it, not an instance of " + instance.GetType());
}
((fsISerializationCallbacks)instance).OnBeforeDeserialize(storageType, ref data);
}
public override void OnAfterDeserialize(Type storageType, object instance)
{
// Don't call the callback on null instances.
if (instance == null)
{
return;
}
((fsISerializationCallbacks)instance).OnAfterDeserialize(storageType);
}
}
#if !NO_UNITY
public class fsSerializationCallbackReceiverProcessor : fsObjectProcessor
{
public override bool CanProcess(Type type)
{
return typeof(ISerializationCallbackReceiver).IsAssignableFrom(type);
}
public override void OnBeforeSerialize(Type storageType, object instance)
{
// Don't call the callback on null instances.
if (instance == null || instance is UnityObject)
{
return;
}
((ISerializationCallbackReceiver)instance).OnBeforeSerialize();
}
public override void OnAfterDeserialize(Type storageType, object instance)
{
// Don't call the callback on null instances.
if (instance == null || instance is UnityObject)
{
return;
}
((ISerializationCallbackReceiver)instance).OnAfterDeserialize();
}
}
#endif
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a9d2948c439334d35b3b0155feda81aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,11 @@
using System;
namespace Unity.VisualScripting.FullSerializer
{
/// <summary>
/// The given property or field annotated with [JsonIgnore] will not be
/// serialized.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class fsIgnoreAttribute : Attribute { }
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec8a76215406a466c86f4003b82f6811
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,628 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Unity.VisualScripting.FullSerializer
{
// TODO: properly propagate warnings/etc for fsResult states
/// <summary>
/// A simple recursive descent parser for JSON.
/// </summary>
public class fsJsonParser
{
private fsJsonParser(string input)
{
_input = input;
_start = 0;
}
private readonly StringBuilder _cachedStringBuilder = new StringBuilder(256);
private int _start;
private string _input;
private fsResult MakeFailure(string message)
{
var start = Math.Max(0, _start - 20);
var length = Math.Min(50, _input.Length - start);
var error = "Error while parsing: " + message + "; context = <" +
_input.Substring(start, length) + ">";
return fsResult.Fail(error);
}
private bool TryMoveNext()
{
if (_start < _input.Length)
{
++_start;
return true;
}
return false;
}
private bool HasValue()
{
return HasValue(0);
}
private bool HasValue(int offset)
{
return (_start + offset) >= 0 && (_start + offset) < _input.Length;
}
private char Character()
{
return Character(0);
}
private char Character(int offset)
{
return _input[_start + offset];
}
/// <summary>
/// Skips input such that Character() will return a non-whitespace
/// character
/// </summary>
private void SkipSpace()
{
while (HasValue())
{
var c = Character();
// whitespace; fine to skip
if (char.IsWhiteSpace(c))
{
TryMoveNext();
continue;
}
// comment?
if (HasValue(1) && Character(0) == '/')
{
if (Character(1) == '/')
{
// skip the rest of the line
while (HasValue() && Environment.NewLine.Contains("" + Character()) == false)
{
TryMoveNext();
}
continue;
}
else if (Character(1) == '*')
{
// skip to comment close
TryMoveNext();
TryMoveNext();
while (HasValue(1))
{
if (Character(0) == '*' && Character(1) == '/')
{
TryMoveNext();
TryMoveNext();
TryMoveNext();
break;
}
else
{
TryMoveNext();
}
}
}
// let other checks to check fail
continue;
}
break;
}
}
private fsResult TryParseExact(string content)
{
for (var i = 0; i < content.Length; ++i)
{
if (Character() != content[i])
{
return MakeFailure("Expected " + content[i]);
}
if (TryMoveNext() == false)
{
return MakeFailure("Unexpected end of content when parsing " + content);
}
}
return fsResult.Success;
}
private fsResult TryParseTrue(out fsData data)
{
var fail = TryParseExact("true");
if (fail.Succeeded)
{
data = new fsData(true);
return fsResult.Success;
}
data = null;
return fail;
}
private fsResult TryParseFalse(out fsData data)
{
var fail = TryParseExact("false");
if (fail.Succeeded)
{
data = new fsData(false);
return fsResult.Success;
}
data = null;
return fail;
}
private fsResult TryParseNull(out fsData data)
{
var fail = TryParseExact("null");
if (fail.Succeeded)
{
data = new fsData();
return fsResult.Success;
}
data = null;
return fail;
}
private bool IsSeparator(char c)
{
return char.IsWhiteSpace(c) || c == ',' || c == '}' || c == ']';
}
/// <summary>
/// Parses numbers that follow the regular expression [-+](\d+|\d*\.\d*)
/// </summary>
private fsResult TryParseNumber(out fsData data)
{
var start = _start;
// read until we get to a separator
while (
TryMoveNext() &&
(HasValue() && IsSeparator(Character()) == false)) { }
// try to parse the value
var numberString = _input.Substring(start, _start - start);
// double -- includes a .
if (numberString.Contains(".") || numberString.Contains("e") || numberString.Contains("E") ||
numberString == "Infinity" || numberString == "-Infinity" || numberString == "NaN")
{
double doubleValue;
if (double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue) == false)
{
data = null;
return MakeFailure("Bad double format with " + numberString);
}
data = new fsData(doubleValue);
return fsResult.Success;
}
else
{
Int64 intValue;
if (Int64.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out intValue) == false)
{
data = null;
return MakeFailure("Bad Int64 format with " + numberString);
}
data = new fsData(intValue);
return fsResult.Success;
}
}
/// <summary>
/// Parses a string
/// </summary>
private fsResult TryParseString(out string str)
{
_cachedStringBuilder.Length = 0;
// skip the first "
if (Character() != '"' || TryMoveNext() == false)
{
str = string.Empty;
return MakeFailure("Expected initial \" when parsing a string");
}
// read until the next "
while (HasValue() && Character() != '\"')
{
var c = Character();
// escape if necessary
if (c == '\\')
{
char unescaped;
var fail = TryUnescapeChar(out unescaped);
if (fail.Failed)
{
str = string.Empty;
return fail;
}
_cachedStringBuilder.Append(unescaped);
}
// no escaping necessary
else
{
_cachedStringBuilder.Append(c);
// get the next character
if (TryMoveNext() == false)
{
str = string.Empty;
return MakeFailure("Unexpected end of input when reading a string");
}
}
}
// skip the first "
if (HasValue() == false || Character() != '"' || TryMoveNext() == false)
{
str = string.Empty;
return MakeFailure("No closing \" when parsing a string");
}
str = _cachedStringBuilder.ToString();
return fsResult.Success;
}
/// <summary>
/// Parses an array
/// </summary>
private fsResult TryParseArray(out fsData arr)
{
if (Character() != '[')
{
arr = null;
return MakeFailure("Expected initial [ when parsing an array");
}
// skip '['
if (TryMoveNext() == false)
{
arr = null;
return MakeFailure("Unexpected end of input when parsing an array");
}
SkipSpace();
var result = new List<fsData>();
while (HasValue() && Character() != ']')
{
// parse the element
fsData element;
var fail = RunParse(out element);
if (fail.Failed)
{
arr = null;
return fail;
}
result.Add(element);
// parse the comma
SkipSpace();
if (HasValue() && Character() == ',')
{
if (TryMoveNext() == false)
{
break;
}
SkipSpace();
}
}
// skip the final ]
if (HasValue() == false || Character() != ']' || TryMoveNext() == false)
{
arr = null;
return MakeFailure("No closing ] for array");
}
arr = new fsData(result);
return fsResult.Success;
}
private fsResult TryParseObject(out fsData obj)
{
if (Character() != '{')
{
obj = null;
return MakeFailure("Expected initial { when parsing an object");
}
// skip '{'
if (TryMoveNext() == false)
{
obj = null;
return MakeFailure("Unexpected end of input when parsing an object");
}
SkipSpace();
var result = new Dictionary<string, fsData>(
fsGlobalConfig.IsCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase);
while (HasValue() && Character() != '}')
{
fsResult failure;
// parse the key
SkipSpace();
string key;
failure = TryParseString(out key);
if (failure.Failed)
{
obj = null;
return failure;
}
SkipSpace();
// parse the ':' after the key
if (HasValue() == false || Character() != ':' || TryMoveNext() == false)
{
obj = null;
return MakeFailure("Expected : after key \"" + key + "\"");
}
SkipSpace();
// parse the value
fsData value;
failure = RunParse(out value);
if (failure.Failed)
{
obj = null;
return failure;
}
result.Add(key, value);
// parse the comma
SkipSpace();
if (HasValue() && Character() == ',')
{
if (TryMoveNext() == false)
{
break;
}
SkipSpace();
}
}
// skip the final }
if (HasValue() == false || Character() != '}' || TryMoveNext() == false)
{
obj = null;
return MakeFailure("No closing } for object");
}
obj = new fsData(result);
return fsResult.Success;
}
private fsResult RunParse(out fsData data)
{
SkipSpace();
if (HasValue() == false)
{
data = default(fsData);
return MakeFailure("Unexpected end of input");
}
switch (Character())
{
case 'I': // Infinity
case 'N': // NaN
case '.':
case '+':
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return TryParseNumber(out data);
case '"':
{
string str;
var fail = TryParseString(out str);
if (fail.Failed)
{
data = null;
return fail;
}
data = new fsData(str);
return fsResult.Success;
}
case '[':
return TryParseArray(out data);
case '{':
return TryParseObject(out data);
case 't':
return TryParseTrue(out data);
case 'f':
return TryParseFalse(out data);
case 'n':
return TryParseNull(out data);
default:
data = null;
return MakeFailure("unable to parse; invalid token \"" + Character() + "\"");
}
}
/// <summary>
/// Parses the specified input. Returns a failure state if parsing
/// failed.
/// </summary>
/// <param name="input">The input to parse.</param>
/// <param name="data">
/// The parsed data. This is undefined if parsing fails.
/// </param>
/// <returns>The parsed input.</returns>
public static fsResult Parse(string input, out fsData data)
{
if (string.IsNullOrEmpty(input))
{
data = default(fsData);
return fsResult.Fail("No input");
}
var context = new fsJsonParser(input);
return context.RunParse(out data);
}
/// <summary>
/// Helper method for Parse that does not allow the error information to
/// be recovered.
/// </summary>
public static fsData Parse(string input)
{
fsData data;
Parse(input, out data).AssertSuccess();
return data;
}
#region Escaping
private bool IsHex(char c)
{
return ((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F'));
}
private uint ParseSingleChar(char c1, uint multipliyer)
{
uint p1 = 0;
if (c1 >= '0' && c1 <= '9')
{
p1 = (uint)(c1 - '0') * multipliyer;
}
else if (c1 >= 'A' && c1 <= 'F')
{
p1 = (uint)((c1 - 'A') + 10) * multipliyer;
}
else if (c1 >= 'a' && c1 <= 'f')
{
p1 = (uint)((c1 - 'a') + 10) * multipliyer;
}
return p1;
}
private uint ParseUnicode(char c1, char c2, char c3, char c4)
{
var p1 = ParseSingleChar(c1, 0x1000);
var p2 = ParseSingleChar(c2, 0x100);
var p3 = ParseSingleChar(c3, 0x10);
var p4 = ParseSingleChar(c4, 0x1);
return p1 + p2 + p3 + p4;
}
private fsResult TryUnescapeChar(out char escaped)
{
// skip leading backslash '\'
TryMoveNext();
if (HasValue() == false)
{
escaped = ' ';
return MakeFailure("Unexpected end of input after \\");
}
switch (Character())
{
case '\\':
TryMoveNext();
escaped = '\\';
return fsResult.Success;
case '/':
TryMoveNext();
escaped = '/';
return fsResult.Success;
case '"':
TryMoveNext();
escaped = '\"';
return fsResult.Success;
case 'a':
TryMoveNext();
escaped = '\a';
return fsResult.Success;
case 'b':
TryMoveNext();
escaped = '\b';
return fsResult.Success;
case 'f':
TryMoveNext();
escaped = '\f';
return fsResult.Success;
case 'n':
TryMoveNext();
escaped = '\n';
return fsResult.Success;
case 'r':
TryMoveNext();
escaped = '\r';
return fsResult.Success;
case 't':
TryMoveNext();
escaped = '\t';
return fsResult.Success;
case '0':
TryMoveNext();
escaped = '\0';
return fsResult.Success;
case 'u':
TryMoveNext();
if (IsHex(Character(0))
&& IsHex(Character(1))
&& IsHex(Character(2))
&& IsHex(Character(3)))
{
var codePoint = ParseUnicode(Character(0), Character(1), Character(2), Character(3));
TryMoveNext();
TryMoveNext();
TryMoveNext();
TryMoveNext();
escaped = (char)codePoint;
return fsResult.Success;
}
// invalid escape sequence
escaped = (char)0;
return MakeFailure(
$"invalid escape sequence '\\u{Character(0)}{Character(1)}{Character(2)}{Character(3)}'\n");
default:
escaped = (char)0;
return MakeFailure($"Invalid escape sequence \\{Character()}");
}
}
#endregion Escaping
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b0c8cf2ada4fd4eb6b1a8960abf537f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show more