Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,192 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class CSharpNameUtility
|
||||
{
|
||||
private static readonly Dictionary<Type, string> primitives = new Dictionary<Type, string>
|
||||
{
|
||||
{ typeof(byte), "byte" },
|
||||
{ typeof(sbyte), "sbyte" },
|
||||
{ typeof(short), "short" },
|
||||
{ typeof(ushort), "ushort" },
|
||||
{ typeof(int), "int" },
|
||||
{ typeof(uint), "uint" },
|
||||
{ typeof(long), "long" },
|
||||
{ typeof(ulong), "ulong" },
|
||||
{ typeof(float), "float" },
|
||||
{ typeof(double), "double" },
|
||||
{ typeof(decimal), "decimal" },
|
||||
{ typeof(string), "string" },
|
||||
{ typeof(char), "char" },
|
||||
{ typeof(bool), "bool" },
|
||||
{ typeof(void), "void" },
|
||||
{ typeof(object), "object" },
|
||||
};
|
||||
|
||||
public static readonly Dictionary<string, string> operators = new Dictionary<string, string>
|
||||
{
|
||||
{ "op_Addition", "+" },
|
||||
{ "op_Subtraction", "-" },
|
||||
{ "op_Multiply", "*" },
|
||||
{ "op_Division", "/" },
|
||||
{ "op_Modulus", "%" },
|
||||
{ "op_ExclusiveOr", "^" },
|
||||
{ "op_BitwiseAnd", "&" },
|
||||
{ "op_BitwiseOr", "|" },
|
||||
{ "op_LogicalAnd", "&&" },
|
||||
{ "op_LogicalOr", "||" },
|
||||
{ "op_Assign", "=" },
|
||||
{ "op_LeftShift", "<<" },
|
||||
{ "op_RightShift", ">>" },
|
||||
{ "op_Equality", "==" },
|
||||
{ "op_GreaterThan", ">" },
|
||||
{ "op_LessThan", "<" },
|
||||
{ "op_Inequality", "!=" },
|
||||
{ "op_GreaterThanOrEqual", ">=" },
|
||||
{ "op_LessThanOrEqual", "<=" },
|
||||
{ "op_MultiplicationAssignment", "*=" },
|
||||
{ "op_SubtractionAssignment", "-=" },
|
||||
{ "op_ExclusiveOrAssignment", "^=" },
|
||||
{ "op_LeftShiftAssignment", "<<=" },
|
||||
{ "op_ModulusAssignment", "%=" },
|
||||
{ "op_AdditionAssignment", "+=" },
|
||||
{ "op_BitwiseAndAssignment", "&=" },
|
||||
{ "op_BitwiseOrAssignment", "|=" },
|
||||
{ "op_Comma", "," },
|
||||
{ "op_DivisionAssignment", "/=" },
|
||||
{ "op_Decrement", "--" },
|
||||
{ "op_Increment", "++" },
|
||||
{ "op_UnaryNegation", "-" },
|
||||
{ "op_UnaryPlus", "+" },
|
||||
{ "op_OnesComplement", "~" },
|
||||
};
|
||||
|
||||
private static readonly HashSet<char> illegalTypeFileNameCharacters = new HashSet<char>()
|
||||
{
|
||||
'<',
|
||||
'>',
|
||||
'?',
|
||||
' ',
|
||||
',',
|
||||
':',
|
||||
};
|
||||
|
||||
public static string CSharpName(this MemberInfo member, ActionDirection direction)
|
||||
{
|
||||
if (member is MethodInfo && ((MethodInfo)member).IsOperator())
|
||||
{
|
||||
return operators[member.Name] + " operator";
|
||||
}
|
||||
|
||||
if (member is ConstructorInfo)
|
||||
{
|
||||
return "new " + member.DeclaringType.CSharpName();
|
||||
}
|
||||
|
||||
if ((member is FieldInfo || member is PropertyInfo) && direction != ActionDirection.Any)
|
||||
{
|
||||
return $"{member.Name} ({direction.ToString().ToLower()})";
|
||||
}
|
||||
|
||||
return member.Name;
|
||||
}
|
||||
|
||||
public static string CSharpName(this Type type, bool includeGenericParameters = true)
|
||||
{
|
||||
return type.CSharpName(TypeQualifier.Name, includeGenericParameters);
|
||||
}
|
||||
|
||||
public static string CSharpFullName(this Type type, bool includeGenericParameters = true)
|
||||
{
|
||||
return type.CSharpName(TypeQualifier.Namespace, includeGenericParameters);
|
||||
}
|
||||
|
||||
public static string CSharpUniqueName(this Type type, bool includeGenericParameters = true)
|
||||
{
|
||||
return type.CSharpName(TypeQualifier.GlobalNamespace, includeGenericParameters);
|
||||
}
|
||||
|
||||
public static string CSharpFileName(this Type type, bool includeNamespace, bool includeGenericParameters = false)
|
||||
{
|
||||
var fileName = type.CSharpName(includeNamespace ? TypeQualifier.Namespace : TypeQualifier.Name, includeGenericParameters);
|
||||
|
||||
if (!includeGenericParameters && type.IsGenericType && fileName.Contains('<'))
|
||||
{
|
||||
fileName = fileName.Substring(0, fileName.IndexOf('<'));
|
||||
}
|
||||
|
||||
fileName = fileName.ReplaceMultiple(illegalTypeFileNameCharacters, '_')
|
||||
.Trim('_')
|
||||
.RemoveConsecutiveCharacters('_');
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private static string CSharpName(this Type type, TypeQualifier qualifier, bool includeGenericParameters = true)
|
||||
{
|
||||
if (primitives.ContainsKey(type))
|
||||
{
|
||||
return primitives[type];
|
||||
}
|
||||
else if (type.IsGenericParameter)
|
||||
{
|
||||
return includeGenericParameters ? type.Name : "";
|
||||
}
|
||||
else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
var nonNullable = Nullable.GetUnderlyingType(type);
|
||||
|
||||
var underlyingName = nonNullable.CSharpName(qualifier, includeGenericParameters);
|
||||
|
||||
return underlyingName + "?";
|
||||
}
|
||||
else
|
||||
{
|
||||
var name = type.Name;
|
||||
|
||||
if (type.IsGenericType && name.Contains('`'))
|
||||
{
|
||||
name = name.Substring(0, name.IndexOf('`'));
|
||||
}
|
||||
|
||||
var genericArguments = (IEnumerable<Type>)type.GetGenericArguments();
|
||||
|
||||
if (type.IsNested)
|
||||
{
|
||||
name = type.DeclaringType.CSharpName(qualifier, includeGenericParameters) + "." + name;
|
||||
|
||||
if (type.DeclaringType.IsGenericType)
|
||||
{
|
||||
genericArguments.Skip(type.DeclaringType.GetGenericArguments().Length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!type.IsNested)
|
||||
{
|
||||
if ((qualifier == TypeQualifier.Namespace || qualifier == TypeQualifier.GlobalNamespace) && type.Namespace != null)
|
||||
{
|
||||
name = type.Namespace + "." + name;
|
||||
}
|
||||
|
||||
if (qualifier == TypeQualifier.GlobalNamespace)
|
||||
{
|
||||
name = "global::" + name;
|
||||
}
|
||||
}
|
||||
|
||||
if (genericArguments.Any())
|
||||
{
|
||||
name += "<";
|
||||
name += string.Join(includeGenericParameters ? ", " : ",", genericArguments.Select(t => t.CSharpName(qualifier, includeGenericParameters)).ToArray());
|
||||
name += ">";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 09c9e2e5152e0495f86ddb8484d7e1bc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,250 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class ComponentHolderProtocol
|
||||
{
|
||||
public static bool IsComponentHolderType(Type type)
|
||||
{
|
||||
Ensure.That(nameof(type)).IsNotNull(type);
|
||||
|
||||
return typeof(GameObject).IsAssignableFrom(type) || typeof(Component).IsAssignableFrom(type);
|
||||
}
|
||||
|
||||
public static bool IsComponentHolder(this UnityObject uo)
|
||||
{
|
||||
return uo is GameObject || uo is Component;
|
||||
}
|
||||
|
||||
public static GameObject GameObject(this UnityObject uo)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return (GameObject)uo;
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).gameObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static T AddComponent<T>(this UnityObject uo) where T : Component
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).AddComponent<T>();
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).gameObject.AddComponent<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static T GetOrAddComponent<T>(this UnityObject uo) where T : Component
|
||||
{
|
||||
return uo.GetComponent<T>() ?? uo.AddComponent<T>();
|
||||
}
|
||||
|
||||
public static T GetComponent<T>(this UnityObject uo)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponent<T>();
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponent<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static T GetComponentInChildren<T>(this UnityObject uo)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponentInChildren<T>();
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponentInChildren<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static T GetComponentInParent<T>(this UnityObject uo)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponentInParent<T>();
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponentInParent<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static T[] GetComponents<T>(this UnityObject uo)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponents<T>();
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponents<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static T[] GetComponentsInChildren<T>(this UnityObject uo)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponentsInChildren<T>();
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponentsInChildren<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static T[] GetComponentsInParent<T>(this UnityObject uo)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponentsInParent<T>();
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponentsInParent<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static Component GetComponent(this UnityObject uo, Type type)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponent(type);
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponent(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static Component GetComponentInChildren(this UnityObject uo, Type type)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponentInChildren(type);
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponentInChildren(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static Component GetComponentInParent(this UnityObject uo, Type type)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponentInParent(type);
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponentInParent(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static Component[] GetComponents(this UnityObject uo, Type type)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponents(type);
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponents(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static Component[] GetComponentsInChildren(this UnityObject uo, Type type)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponentsInChildren(type);
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponentsInChildren(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static Component[] GetComponentsInParent(this UnityObject uo, Type type)
|
||||
{
|
||||
if (uo is GameObject)
|
||||
{
|
||||
return ((GameObject)uo).GetComponentsInParent(type);
|
||||
}
|
||||
else if (uo is Component)
|
||||
{
|
||||
return ((Component)uo).GetComponentsInParent(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e5031b55827d74367b8d19a739ae45e3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,24 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Singleton(Name = "Coroutine Runner", Automatic = true, Persistent = true)]
|
||||
[AddComponentMenu("")]
|
||||
[DisableAnnotation]
|
||||
[IncludeInSettings(false)]
|
||||
public sealed class CoroutineRunner : MonoBehaviour, ISingleton
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
Singleton<CoroutineRunner>.Awake(this);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
Singleton<CoroutineRunner>.OnDestroy(this);
|
||||
}
|
||||
|
||||
public static CoroutineRunner instance => Singleton<CoroutineRunner>.instance;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 28cb3597f76b74b39b40b102825752e0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
// For some reason, Enumerable.Empty<T>() seems to allocate 240b in Unity,
|
||||
// even though Mono source seems to use a shared 0-length array instance.
|
||||
// Maybe it's an old version's bug?
|
||||
public static class Empty<T>
|
||||
{
|
||||
public static readonly T[] array = new T[0];
|
||||
public static readonly List<T> list = new List<T>(0);
|
||||
public static readonly HashSet<T> hashSet = new HashSet<T>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cefc61f3b485d4f83b7932574b4b3130
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class EnumUtility
|
||||
{
|
||||
public static bool HasFlag(this Enum value, Enum flag)
|
||||
{
|
||||
var lValue = Convert.ToInt64(value);
|
||||
var lFlag = Convert.ToInt64(flag);
|
||||
return (lValue & lFlag) == lFlag;
|
||||
}
|
||||
|
||||
public static Dictionary<string, Enum> ValuesByNames(Type enumType, bool obsolete = false)
|
||||
{
|
||||
Ensure.That(nameof(enumType)).IsNotNull(enumType);
|
||||
|
||||
IEnumerable<FieldInfo> fields = enumType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (!obsolete)
|
||||
{
|
||||
fields = fields.Where(f => !f.IsDefined(typeof(ObsoleteAttribute), false));
|
||||
}
|
||||
|
||||
return fields.ToDictionary(f => f.Name, f => (Enum)f.GetValue(null));
|
||||
}
|
||||
|
||||
public static Dictionary<string, T> ValuesByNames<T>(bool obsolete = false)
|
||||
{
|
||||
IEnumerable<FieldInfo> fields = typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
|
||||
|
||||
if (!obsolete)
|
||||
{
|
||||
fields = fields.Where(f => !f.IsDefined(typeof(ObsoleteAttribute), false));
|
||||
}
|
||||
|
||||
return fields.ToDictionary(f => f.Name, f => (T)f.GetValue(null));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3314c51d5eca847faa3dca214bbb52cf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class ExceptionUtility
|
||||
{
|
||||
public static Exception Relevant(this Exception ex)
|
||||
{
|
||||
if (ex is TargetInvocationException)
|
||||
{
|
||||
return ex.InnerException;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7f804b6c44a294916b0052bae34a42b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,83 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class HashUtility
|
||||
{
|
||||
public static int GetHashCode<T>(T a)
|
||||
{
|
||||
return a?.GetHashCode() ?? 0;
|
||||
}
|
||||
|
||||
public static int GetHashCode<T1, T2>(T1 a, T2 b)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = 17;
|
||||
|
||||
hash = hash * 23 + (a?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (b?.GetHashCode() ?? 0);
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetHashCode<T1, T2, T3>(T1 a, T2 b, T3 c)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = 17;
|
||||
|
||||
hash = hash * 23 + (a?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (b?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (c?.GetHashCode() ?? 0);
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetHashCode<T1, T2, T3, T4>(T1 a, T2 b, T3 c, T4 d)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = 17;
|
||||
|
||||
hash = hash * 23 + (a?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (b?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (c?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (d?.GetHashCode() ?? 0);
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetHashCode<T1, T2, T3, T4, T5>(T1 a, T2 b, T3 c, T4 d, T5 e)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = 17;
|
||||
|
||||
hash = hash * 23 + (a?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (b?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (c?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (d?.GetHashCode() ?? 0);
|
||||
hash = hash * 23 + (e?.GetHashCode() ?? 0);
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetHashCodeAlloc(params object[] values)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hash = 17;
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
hash = hash * 23 + (value?.GetHashCode() ?? 0);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 38c7f6215a1b2469a877eed0cd55cf3d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IGettable
|
||||
{
|
||||
object GetValue();
|
||||
}
|
||||
|
||||
public static class XGettable
|
||||
{
|
||||
public static object GetValue(this IGettable gettable, Type type)
|
||||
{
|
||||
return ConversionUtility.Convert(gettable.GetValue(), type);
|
||||
}
|
||||
|
||||
public static T GetValue<T>(this IGettable gettable)
|
||||
{
|
||||
return (T)gettable.GetValue(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d9a0487fa0dbe4c4db50cd8d1bb03247
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IIdentifiable
|
||||
{
|
||||
Guid guid { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b0efdfbd6ee674288a50819c81f48320
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,7 @@
|
|||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IInitializable
|
||||
{
|
||||
void Initialize();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9d1ec6799af714a1aad300d02d85d3a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,239 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class LinqUtility
|
||||
{
|
||||
public static IEnumerable<T> Concat<T>(params IEnumerable[] enumerables)
|
||||
{
|
||||
foreach (var enumerable in enumerables.NotNull())
|
||||
{
|
||||
foreach (var item in enumerable.OfType<T>())
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> property)
|
||||
{
|
||||
return items.GroupBy(property).Select(x => x.First());
|
||||
}
|
||||
|
||||
public static IEnumerable<T> NotNull<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
return enumerable.Where(i => i != null);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Yield<T>(this T t)
|
||||
{
|
||||
yield return t;
|
||||
}
|
||||
|
||||
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
return new HashSet<T>(enumerable);
|
||||
}
|
||||
|
||||
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
collection.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRange(this IList list, IEnumerable items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
list.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// NETUP: Replace with IReadOnlyCollection, IReadOnlyList
|
||||
|
||||
public static ICollection<T> AsReadOnlyCollection<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
if (enumerable is ICollection<T>)
|
||||
{
|
||||
return (ICollection<T>)enumerable;
|
||||
}
|
||||
else
|
||||
{
|
||||
return enumerable.ToList().AsReadOnly();
|
||||
}
|
||||
}
|
||||
|
||||
public static IList<T> AsReadOnlyList<T>(this IEnumerable<T> enumerable)
|
||||
{
|
||||
if (enumerable is IList<T>)
|
||||
{
|
||||
return (IList<T>)enumerable;
|
||||
}
|
||||
else
|
||||
{
|
||||
return enumerable.ToList().AsReadOnly();
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Flatten<T>
|
||||
(
|
||||
this IEnumerable<T> source,
|
||||
Func<T, IEnumerable<T>> childrenSelector
|
||||
)
|
||||
{
|
||||
var flattenedList = source;
|
||||
|
||||
foreach (var element in source)
|
||||
{
|
||||
flattenedList = flattenedList.Concat(childrenSelector(element).Flatten(childrenSelector));
|
||||
}
|
||||
|
||||
return flattenedList;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> IntersectAll<T>(this IEnumerable<IEnumerable<T>> groups)
|
||||
{
|
||||
HashSet<T> hashSet = null;
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
if (hashSet == null)
|
||||
{
|
||||
hashSet = new HashSet<T>(group);
|
||||
}
|
||||
else
|
||||
{
|
||||
hashSet.IntersectWith(group);
|
||||
}
|
||||
}
|
||||
|
||||
return hashSet == null ? Enumerable.Empty<T>() : hashSet.AsEnumerable();
|
||||
}
|
||||
|
||||
public static IEnumerable<T> OrderByDependencies<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getDependencies, bool throwOnCycle = true)
|
||||
{
|
||||
var sorted = new List<T>();
|
||||
var visited = HashSetPool<T>.New();
|
||||
|
||||
foreach (var item in source)
|
||||
{
|
||||
OrderByDependenciesVisit(item, visited, sorted, getDependencies, throwOnCycle);
|
||||
}
|
||||
|
||||
HashSetPool<T>.Free(visited);
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
private static void OrderByDependenciesVisit<T>(T item, HashSet<T> visited, List<T> sorted, Func<T, IEnumerable<T>> getDependencies, bool throwOnCycle)
|
||||
{
|
||||
if (!visited.Contains(item))
|
||||
{
|
||||
visited.Add(item);
|
||||
|
||||
foreach (var dependency in getDependencies(item))
|
||||
{
|
||||
OrderByDependenciesVisit(dependency, visited, sorted, getDependencies, throwOnCycle);
|
||||
}
|
||||
|
||||
sorted.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (throwOnCycle && !sorted.Contains(item))
|
||||
{
|
||||
throw new InvalidOperationException("Cyclic dependency.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> OrderByDependers<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getDependers, bool throwOnCycle = true)
|
||||
{
|
||||
// TODO: Optimize, or use another algorithm (Kahn's?)
|
||||
|
||||
// Convert dependers to dependencies
|
||||
var dependencies = new Dictionary<T, HashSet<T>>();
|
||||
|
||||
foreach (var dependency in source)
|
||||
{
|
||||
foreach (var depender in getDependers(dependency))
|
||||
{
|
||||
if (!dependencies.ContainsKey(depender))
|
||||
{
|
||||
dependencies.Add(depender, new HashSet<T>());
|
||||
}
|
||||
|
||||
dependencies[depender].Add(dependency);
|
||||
}
|
||||
}
|
||||
|
||||
return source.OrderByDependencies(depender =>
|
||||
{
|
||||
if (dependencies.ContainsKey(depender))
|
||||
{
|
||||
return dependencies[depender];
|
||||
}
|
||||
else
|
||||
{
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
}, throwOnCycle);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Catch<T>(this IEnumerable<T> source, Action<Exception> @catch)
|
||||
{
|
||||
Ensure.That(nameof(source)).IsNotNull(source);
|
||||
|
||||
using (var enumerator = source.GetEnumerator())
|
||||
{
|
||||
bool success;
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
success = enumerator.MoveNext();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@catch?.Invoke(ex);
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
yield return enumerator.Current;
|
||||
}
|
||||
}
|
||||
while (success);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Catch<T>(this IEnumerable<T> source, ICollection<Exception> exceptions)
|
||||
{
|
||||
Ensure.That(nameof(exceptions)).IsNotNull(exceptions);
|
||||
|
||||
return source.Catch(exceptions.Add);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> CatchAsLogError<T>(this IEnumerable<T> source, string message)
|
||||
{
|
||||
return source.Catch((ex) => Debug.LogError(message + "\n" + ex.ToString()));
|
||||
}
|
||||
|
||||
public static IEnumerable<T> CatchAsLogWarning<T>(this IEnumerable<T> source, string message)
|
||||
{
|
||||
return source.Catch((ex) => Debug.LogWarning(message + "\n" + ex.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 16c818a2cfc334b38b238142c08478ce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public class OverrideStack<T>
|
||||
{
|
||||
public OverrideStack(T defaultValue)
|
||||
{
|
||||
_value = defaultValue;
|
||||
getValue = () => _value;
|
||||
setValue = (value) => _value = value;
|
||||
}
|
||||
|
||||
public OverrideStack(Func<T> getValue, Action<T> setValue)
|
||||
{
|
||||
Ensure.That(nameof(getValue)).IsNotNull(getValue);
|
||||
Ensure.That(nameof(setValue)).IsNotNull(setValue);
|
||||
|
||||
this.getValue = getValue;
|
||||
this.setValue = setValue;
|
||||
}
|
||||
|
||||
public OverrideStack(Func<T> getValue, Action<T> setValue, Action clearValue) : this(getValue, setValue)
|
||||
{
|
||||
Ensure.That(nameof(clearValue)).IsNotNull(clearValue);
|
||||
|
||||
this.clearValue = clearValue;
|
||||
}
|
||||
|
||||
private readonly Func<T> getValue;
|
||||
|
||||
private readonly Action<T> setValue;
|
||||
|
||||
private readonly Action clearValue;
|
||||
|
||||
private T _value;
|
||||
|
||||
private readonly Stack<T> previous = new Stack<T>();
|
||||
|
||||
public T value
|
||||
{
|
||||
get
|
||||
{
|
||||
return getValue();
|
||||
}
|
||||
internal set
|
||||
{
|
||||
setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
public OverrideLayer<T> Override(T item)
|
||||
{
|
||||
return new OverrideLayer<T>(this, item);
|
||||
}
|
||||
|
||||
public void BeginOverride(T item)
|
||||
{
|
||||
previous.Push(value);
|
||||
value = item;
|
||||
}
|
||||
|
||||
public void EndOverride()
|
||||
{
|
||||
if (previous.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
value = previous.Pop();
|
||||
|
||||
if (previous.Count == 0)
|
||||
{
|
||||
clearValue?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator T(OverrideStack<T> stack)
|
||||
{
|
||||
Ensure.That(nameof(stack)).IsNotNull(stack);
|
||||
|
||||
return stack.value;
|
||||
}
|
||||
}
|
||||
|
||||
public struct OverrideLayer<T> : IDisposable
|
||||
{
|
||||
public OverrideStack<T> stack { get; }
|
||||
|
||||
internal OverrideLayer(OverrideStack<T> stack, T item)
|
||||
{
|
||||
Ensure.That(nameof(stack)).IsNotNull(stack);
|
||||
|
||||
this.stack = stack;
|
||||
|
||||
stack.BeginOverride(item);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
stack.EndOverride();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 648b9d6f371f74db398aa1e83ea0f383
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,181 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public class Recursion<T> : IPoolable, IDisposable
|
||||
{
|
||||
protected Recursion()
|
||||
{
|
||||
traversedOrder = new Stack<T>();
|
||||
traversedCount = new Dictionary<T, int>();
|
||||
}
|
||||
|
||||
private readonly Stack<T> traversedOrder;
|
||||
|
||||
private readonly Dictionary<T, int> traversedCount;
|
||||
|
||||
private bool disposed;
|
||||
|
||||
protected int maxDepth;
|
||||
|
||||
public void Enter(T o)
|
||||
{
|
||||
if (!TryEnter(o))
|
||||
{
|
||||
throw new StackOverflowException($"Max recursion depth of {maxDepth} has been exceeded. Consider increasing '{nameof(Recursion)}.{nameof(Recursion.defaultMaxDepth)}'.");
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryEnter(T o)
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(ToString());
|
||||
}
|
||||
|
||||
// Disable null check because it boxes o
|
||||
// Ensure.That(nameof(o)).IsNotNull(o);
|
||||
|
||||
if (traversedCount.TryGetValue(o, out var depth))
|
||||
{
|
||||
if (depth < maxDepth)
|
||||
{
|
||||
traversedOrder.Push(o);
|
||||
traversedCount[o]++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
traversedOrder.Push(o);
|
||||
traversedCount.Add(o, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Exit(T o)
|
||||
{
|
||||
if (traversedOrder.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Trying to exit an empty recursion stack.");
|
||||
}
|
||||
|
||||
var current = traversedOrder.Peek();
|
||||
|
||||
if (!EqualityComparer<T>.Default.Equals(o, current))
|
||||
{
|
||||
throw new InvalidOperationException($"Exiting recursion stack in a non-consecutive order:\nProvided: {o} / Expected: {current}");
|
||||
}
|
||||
|
||||
traversedOrder.Pop();
|
||||
|
||||
var newDepth = traversedCount[current]--;
|
||||
|
||||
if (newDepth == 0)
|
||||
{
|
||||
traversedCount.Remove(current);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(ToString());
|
||||
}
|
||||
|
||||
Free();
|
||||
}
|
||||
|
||||
protected virtual void Free()
|
||||
{
|
||||
GenericPool<Recursion<T>>.Free(this);
|
||||
}
|
||||
|
||||
void IPoolable.New()
|
||||
{
|
||||
disposed = false;
|
||||
}
|
||||
|
||||
void IPoolable.Free()
|
||||
{
|
||||
disposed = true;
|
||||
traversedCount.Clear();
|
||||
traversedOrder.Clear();
|
||||
}
|
||||
|
||||
public static Recursion<T> New()
|
||||
{
|
||||
return New(Recursion.defaultMaxDepth);
|
||||
}
|
||||
|
||||
public static Recursion<T> New(int maxDepth)
|
||||
{
|
||||
if (!Recursion.safeMode)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (maxDepth < 1)
|
||||
{
|
||||
throw new ArgumentException("Max recursion depth must be at least one.", nameof(maxDepth));
|
||||
}
|
||||
|
||||
var recursion = GenericPool<Recursion<T>>.New(() => new Recursion<T>());
|
||||
|
||||
recursion.maxDepth = maxDepth;
|
||||
|
||||
return recursion;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Recursion : Recursion<object>
|
||||
{
|
||||
private Recursion() : base() { }
|
||||
|
||||
public static int defaultMaxDepth { get; set; } = 100;
|
||||
|
||||
public static bool safeMode { get; set; }
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void OnRuntimeMethodLoad()
|
||||
{
|
||||
safeMode = Application.isEditor || Debug.isDebugBuild;
|
||||
}
|
||||
|
||||
protected override void Free()
|
||||
{
|
||||
GenericPool<Recursion>.Free(this);
|
||||
}
|
||||
|
||||
public new static Recursion New()
|
||||
{
|
||||
return New(defaultMaxDepth);
|
||||
}
|
||||
|
||||
public new static Recursion New(int maxDepth)
|
||||
{
|
||||
if (!safeMode)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (maxDepth < 1)
|
||||
{
|
||||
throw new ArgumentException("Max recursion depth must be at least one.", nameof(maxDepth));
|
||||
}
|
||||
|
||||
var recursion = GenericPool<Recursion>.New(() => new Recursion());
|
||||
|
||||
recursion.maxDepth = maxDepth;
|
||||
|
||||
return recursion;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d466a08d759134cb394b892eeaeabb85
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class ReferenceCollector
|
||||
{
|
||||
public static event Action onSceneUnloaded;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void Initialize()
|
||||
{
|
||||
SceneManager.sceneUnloaded += scene => onSceneUnloaded?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6641aaf2964f14d2ca96abe794c52929
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,51 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
// Implementation From Roslyn:
|
||||
// http://source.roslyn.io/#microsoft.codeanalysis/InternalUtilities/ReferenceEqualityComparer.cs
|
||||
public class ReferenceEqualityComparer : IEqualityComparer<object>
|
||||
{
|
||||
private ReferenceEqualityComparer() { }
|
||||
|
||||
bool IEqualityComparer<object>.Equals(object a, object b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
int IEqualityComparer<object>.GetHashCode(object a)
|
||||
{
|
||||
return GetHashCode(a);
|
||||
}
|
||||
|
||||
public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer();
|
||||
|
||||
public static int GetHashCode(object a)
|
||||
{
|
||||
return RuntimeHelpers.GetHashCode(a);
|
||||
}
|
||||
}
|
||||
|
||||
public class ReferenceEqualityComparer<T> : IEqualityComparer<T>
|
||||
{
|
||||
private ReferenceEqualityComparer() { }
|
||||
|
||||
bool IEqualityComparer<T>.Equals(T a, T b)
|
||||
{
|
||||
return ReferenceEquals(a, b);
|
||||
}
|
||||
|
||||
int IEqualityComparer<T>.GetHashCode(T a)
|
||||
{
|
||||
return GetHashCode(a);
|
||||
}
|
||||
|
||||
public static readonly ReferenceEqualityComparer<T> Instance = new ReferenceEqualityComparer<T>();
|
||||
|
||||
public static int GetHashCode(T a)
|
||||
{
|
||||
return RuntimeHelpers.GetHashCode(a);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 473eee99af81e4e85b5a2048b267f9f0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,449 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class StringUtility
|
||||
{
|
||||
public static bool IsNullOrWhiteSpace(string s)
|
||||
{
|
||||
return s == null || s.Trim() == string.Empty;
|
||||
}
|
||||
|
||||
public static string FallbackEmpty(string s, string fallback)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
s = fallback;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static string FallbackWhitespace(string s, string fallback)
|
||||
{
|
||||
if (IsNullOrWhiteSpace(s))
|
||||
{
|
||||
s = fallback;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public static void AppendLineFormat(this StringBuilder sb, string format, params object[] args)
|
||||
{
|
||||
sb.AppendFormat(format, args);
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
public static string ToSeparatedString(this IEnumerable enumerable, string separator)
|
||||
{
|
||||
return string.Join(separator, enumerable.Cast<object>().Select(o => o?.ToString() ?? "(null)").ToArray());
|
||||
}
|
||||
|
||||
public static string ToCommaSeparatedString(this IEnumerable enumerable)
|
||||
{
|
||||
return ToSeparatedString(enumerable, ", ");
|
||||
}
|
||||
|
||||
public static string ToLineSeparatedString(this IEnumerable enumerable)
|
||||
{
|
||||
return ToSeparatedString(enumerable, Environment.NewLine);
|
||||
}
|
||||
|
||||
public static bool ContainsInsensitive(this string haystack, string needle)
|
||||
{
|
||||
return haystack.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
public static IEnumerable<int> AllIndexesOf(this string haystack, string needle)
|
||||
{
|
||||
if (string.IsNullOrEmpty(needle))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
for (var index = 0; ; index += needle.Length)
|
||||
{
|
||||
index = haystack.IndexOf(needle, index, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
yield return index;
|
||||
}
|
||||
}
|
||||
|
||||
public static string Filter(this string s, bool letters = true, bool numbers = true, bool whitespace = true, bool symbols = true, bool punctuation = true)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (var c in s)
|
||||
{
|
||||
if ((!letters && char.IsLetter(c)) ||
|
||||
(!numbers && char.IsNumber(c)) ||
|
||||
(!whitespace && char.IsWhiteSpace(c)) ||
|
||||
(!symbols && char.IsSymbol(c)) ||
|
||||
(!punctuation && char.IsPunctuation(c)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sb.Append(c);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string FilterReplace(this string s, char replacement, bool merge, bool letters = true, bool numbers = true, bool whitespace = true, bool symbols = true, bool punctuation = true)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
var wasFiltered = false;
|
||||
|
||||
foreach (var c in s)
|
||||
{
|
||||
if ((!letters && char.IsLetter(c)) ||
|
||||
(!numbers && char.IsNumber(c)) ||
|
||||
(!whitespace && char.IsWhiteSpace(c)) ||
|
||||
(!symbols && char.IsSymbol(c)) ||
|
||||
(!punctuation && char.IsPunctuation(c)))
|
||||
{
|
||||
if (!merge || !wasFiltered)
|
||||
{
|
||||
sb.Append(replacement);
|
||||
}
|
||||
|
||||
wasFiltered = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(c);
|
||||
|
||||
wasFiltered = false;
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string Prettify(this string s)
|
||||
{
|
||||
return s.FirstCharacterToUpper().SplitWords(' ');
|
||||
}
|
||||
|
||||
public static bool IsWordDelimiter(char c)
|
||||
{
|
||||
return char.IsWhiteSpace(c) || char.IsSymbol(c) || char.IsPunctuation(c);
|
||||
}
|
||||
|
||||
public static bool IsWordBeginning(char? previous, char current, char? next)
|
||||
{
|
||||
var isFirst = previous == null;
|
||||
var isLast = next == null;
|
||||
|
||||
var isLetter = char.IsLetter(current);
|
||||
var wasLetter = previous != null && char.IsLetter(previous.Value);
|
||||
|
||||
var isNumber = char.IsNumber(current);
|
||||
var wasNumber = previous != null && char.IsNumber(previous.Value);
|
||||
|
||||
var isUpper = char.IsUpper(current);
|
||||
var wasUpper = previous != null && char.IsUpper(previous.Value);
|
||||
|
||||
var isDelimiter = IsWordDelimiter(current);
|
||||
var wasDelimiter = previous != null && IsWordDelimiter(previous.Value);
|
||||
|
||||
var willBeLower = next != null && char.IsLower(next.Value);
|
||||
|
||||
return
|
||||
(!isDelimiter && isFirst) ||
|
||||
(!isDelimiter && wasDelimiter) ||
|
||||
(isLetter && wasLetter && isUpper && !wasUpper) || // camelCase => camel_Case
|
||||
(isLetter && wasLetter && isUpper && wasUpper && !isLast && willBeLower) || // => ABBRWord => ABBR_Word
|
||||
(isNumber && wasLetter) || // Vector3 => Vector_3
|
||||
(isLetter && wasNumber && isUpper && willBeLower); // Word1Word => Word_1_Word, Word1word => Word_1word
|
||||
}
|
||||
|
||||
public static bool IsWordBeginning(string s, int index)
|
||||
{
|
||||
Ensure.That(nameof(index)).IsGte(index, 0);
|
||||
Ensure.That(nameof(index)).IsLt(index, s.Length);
|
||||
|
||||
var previous = index > 0 ? s[index - 1] : (char?)null;
|
||||
var current = s[index];
|
||||
var next = index < s.Length - 1 ? s[index + 1] : (char?)null;
|
||||
|
||||
return IsWordBeginning(previous, current, next);
|
||||
}
|
||||
|
||||
public static string SplitWords(this string s, char separator)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for (var i = 0; i < s.Length; i++)
|
||||
{
|
||||
var c = s[i];
|
||||
|
||||
if (i > 0 && IsWordBeginning(s, i))
|
||||
{
|
||||
sb.Append(separator);
|
||||
}
|
||||
|
||||
sb.Append(c);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string RemoveConsecutiveCharacters(this string s, char c)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
var previous = '\0';
|
||||
|
||||
foreach (var current in s)
|
||||
{
|
||||
if (current != c || current != previous)
|
||||
{
|
||||
sb.Append(current);
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string ReplaceMultiple(this string s, HashSet<char> haystacks, char replacement)
|
||||
{
|
||||
Ensure.That(nameof(haystacks)).IsNotNull(haystacks);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
foreach (var current in s)
|
||||
{
|
||||
if (haystacks.Contains(current))
|
||||
{
|
||||
sb.Append(replacement);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(current);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string Truncate(this string value, int maxLength, string suffix = "...")
|
||||
{
|
||||
return value.Length <= maxLength ? value : value.Substring(0, maxLength) + suffix;
|
||||
}
|
||||
|
||||
public static string TrimEnd(this string source, string value)
|
||||
{
|
||||
if (!source.EndsWith(value))
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
return source.Remove(source.LastIndexOf(value));
|
||||
}
|
||||
|
||||
public static string TrimStart(this string source, string value)
|
||||
{
|
||||
if (!source.StartsWith(value))
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
return source.Substring(value.Length);
|
||||
}
|
||||
|
||||
public static string FirstCharacterToLower(this string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s) || char.IsLower(s, 0))
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
return char.ToLowerInvariant(s[0]) + s.Substring(1);
|
||||
}
|
||||
|
||||
public static string FirstCharacterToUpper(this string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s) || char.IsUpper(s, 0))
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
return char.ToUpperInvariant(s[0]) + s.Substring(1);
|
||||
}
|
||||
|
||||
public static string PartBefore(this string s, char c)
|
||||
{
|
||||
Ensure.That(nameof(s)).IsNotNull(s);
|
||||
|
||||
var index = s.IndexOf(c);
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
return s.Substring(0, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static string PartAfter(this string s, char c)
|
||||
{
|
||||
Ensure.That(nameof(s)).IsNotNull(s);
|
||||
|
||||
var index = s.IndexOf(c);
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
return s.Substring(index + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static void PartsAround(this string s, char c, out string before, out string after)
|
||||
{
|
||||
Ensure.That(nameof(s)).IsNotNull(s);
|
||||
|
||||
var index = s.IndexOf(c);
|
||||
|
||||
if (index > 0)
|
||||
{
|
||||
before = s.Substring(0, index);
|
||||
after = s.Substring(index + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
before = s;
|
||||
after = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Faster equivalents for chars
|
||||
|
||||
public static bool EndsWith(this string s, char c)
|
||||
{
|
||||
Ensure.That(nameof(s)).IsNotNull(s);
|
||||
|
||||
return s[s.Length - 1] == c;
|
||||
}
|
||||
|
||||
public static bool StartsWith(this string s, char c)
|
||||
{
|
||||
Ensure.That(nameof(s)).IsNotNull(s);
|
||||
|
||||
return s[0] == c;
|
||||
}
|
||||
|
||||
public static bool Contains(this string s, char c)
|
||||
{
|
||||
Ensure.That(nameof(s)).IsNotNull(s);
|
||||
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
{
|
||||
if (s[i] == c)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string NullIfEmpty(this string s)
|
||||
{
|
||||
if (s == string.Empty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToBinaryString(this int value)
|
||||
{
|
||||
return Convert.ToString(value, 2).PadLeft(8, '0');
|
||||
}
|
||||
|
||||
public static string ToBinaryString(this long value)
|
||||
{
|
||||
return Convert.ToString(value, 2).PadLeft(16, '0');
|
||||
}
|
||||
|
||||
public static string ToBinaryString(this Enum value)
|
||||
{
|
||||
return Convert.ToString(Convert.ToInt64(value), 2).PadLeft(16, '0');
|
||||
}
|
||||
|
||||
public static int CountIndices(this string s, char c)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
foreach (var _c in s)
|
||||
{
|
||||
if (c == _c)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public static bool IsGuid(string value)
|
||||
{
|
||||
return guidRegex.IsMatch(value);
|
||||
}
|
||||
|
||||
private static readonly Regex guidRegex = new Regex(@"[a-fA-F0-9]{8}(\-[a-fA-F0-9]{4}){3}\-[a-fA-F0-9]{12}");
|
||||
|
||||
public static string PathEllipsis(string s, int maxLength)
|
||||
{
|
||||
var ellipsis = "...";
|
||||
|
||||
if (s.Length < maxLength)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
var fileName = Path.GetFileName(s);
|
||||
var directory = Path.GetDirectoryName(s);
|
||||
|
||||
var maxDirectoryLength = maxLength - fileName.Length - ellipsis.Length;
|
||||
|
||||
if (maxDirectoryLength > 0)
|
||||
{
|
||||
return directory.Substring(0, maxDirectoryLength) + ellipsis + Path.DirectorySeparatorChar + fileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ellipsis + Path.DirectorySeparatorChar + fileName;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToHexString(this byte[] bytes)
|
||||
{
|
||||
return BitConverter.ToString(bytes).Replace("-", "");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 61ab10f4687d1455da6d4845e21f5401
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,159 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class UnityObjectUtility
|
||||
{
|
||||
public static bool IsDestroyed(this UnityObject target)
|
||||
{
|
||||
// Checks whether a Unity object is not actually a null reference,
|
||||
// but a rather destroyed native instance.
|
||||
|
||||
return !ReferenceEquals(target, null) && target == null;
|
||||
}
|
||||
|
||||
public static bool IsUnityNull(this object obj)
|
||||
{
|
||||
// Checks whether an object is null or Unity pseudo-null
|
||||
// without having to cast to UnityEngine.Object manually
|
||||
|
||||
return obj == null || ((obj is UnityObject) && ((UnityObject)obj) == null);
|
||||
}
|
||||
|
||||
public static string ToSafeString(this UnityObject uo)
|
||||
{
|
||||
if (ReferenceEquals(uo, null))
|
||||
{
|
||||
return "(null)";
|
||||
}
|
||||
|
||||
if (!UnityThread.allowsAPI)
|
||||
{
|
||||
return uo.GetType().Name;
|
||||
}
|
||||
|
||||
if (uo == null)
|
||||
{
|
||||
return "(Destroyed)";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return uo.name;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"({ex.GetType().Name} in ToString: {ex.Message})";
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToSafeString(this object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return "(null)";
|
||||
}
|
||||
|
||||
if (obj is UnityObject uo)
|
||||
{
|
||||
return uo.ToSafeString();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return obj.ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"({ex.GetType().Name} in ToString: {ex.Message})";
|
||||
}
|
||||
}
|
||||
|
||||
public static T AsUnityNull<T>(this T obj) where T : UnityObject
|
||||
{
|
||||
// Converts a Unity pseudo-null to a real null, allowing for coalesce operators.
|
||||
// e.g.: destroyedObject.AsUnityNull() ?? otherObject
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static bool TrulyEqual(UnityObject a, UnityObject b)
|
||||
{
|
||||
// This method is required when checking two references
|
||||
// against one another, where one of them might have been destroyed.
|
||||
// It is not required when checking against null.
|
||||
|
||||
// This is because Unity does not compare alive state
|
||||
// in the CompareBaseObjects method unless one of the two
|
||||
// operators is actually the null literal.
|
||||
|
||||
// From the source:
|
||||
/*
|
||||
bool lhsIsNull = (object) lhs == null;
|
||||
bool rhsIsNull = (object) rhs == null;
|
||||
if (rhsIsNull && lhsIsNull)
|
||||
return true;
|
||||
if (rhsIsNull)
|
||||
return !Object.IsNativeObjectAlive(lhs);
|
||||
if (lhsIsNull)
|
||||
return !Object.IsNativeObjectAlive(rhs);
|
||||
return lhs.m_InstanceID == rhs.m_InstanceID;
|
||||
*/
|
||||
|
||||
// As we can see, Object.IsNativeObjectAlive is not compared
|
||||
// across the two objects unless one of the operands is actually null.
|
||||
// But it can happen, for example when exiting play mode.
|
||||
// If we stored a static reference to a scene object that was destroyed,
|
||||
// the reference won't get cleared because assembly reloads don't happen
|
||||
// when exiting playmode. But the instance ID of the object will stay
|
||||
// the same, because it only gets reserialized. So if we compare our
|
||||
// stale reference that was destroyed to a new reference to the object,
|
||||
// it will return true, even though one reference is alive and the other isn't.
|
||||
|
||||
if (a != b)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((a == null) != (b == null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> NotUnityNull<T>(this IEnumerable<T> enumerable) where T : UnityObject
|
||||
{
|
||||
return enumerable.Where(i => i != null);
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FindObjectsOfTypeIncludingInactive<T>()
|
||||
{
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
var scene = SceneManager.GetSceneAt(i);
|
||||
|
||||
if (scene.isLoaded)
|
||||
{
|
||||
foreach (var rootGameObject in scene.GetRootGameObjects())
|
||||
{
|
||||
foreach (var result in rootGameObject.GetComponentsInChildren<T>(true))
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 85f4b970ba57b4bdd9b801cec11a183c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,16 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class XColor
|
||||
{
|
||||
public static string ToHexString(this Color color)
|
||||
{
|
||||
return
|
||||
((byte)(color.r * 255)).ToString("X2") +
|
||||
((byte)(color.g * 255)).ToString("X2") +
|
||||
((byte)(color.b * 255)).ToString("X2") +
|
||||
((byte)(color.a * 255)).ToString("X2");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc7b71435e995493f8881e16f854d1cf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue