添加插件
This commit is contained in:
110
Assets/Obvious/Soap/Core/Runtime/Utilities/SoapRuntimeUtils.cs
Normal file
110
Assets/Obvious/Soap/Core/Runtime/Utilities/SoapRuntimeUtils.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Obvious.Soap.Attributes;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Obvious.Soap
|
||||
{
|
||||
public static class SoapRuntimeUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of a ScriptableVariableBase subclass with the given name.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the ScriptableVariableBase subclass to create.</typeparam>
|
||||
/// <param name="name">The name of the new ScriptableVariableBase instance.</param>
|
||||
/// <returns>The newly created ScriptableVariableBase instance.</returns>
|
||||
public static T CreateRuntimeInstance<T>(string name = "") where T : ScriptableVariableBase
|
||||
{
|
||||
var runtimeVariable = CreateInstance<T>(name);
|
||||
runtimeVariable.ResetType = ResetType.None;
|
||||
return runtimeVariable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of a ScriptableObject subclass with the given name.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static T CreateInstance<T>(string name = "") where T : ScriptableObject
|
||||
{
|
||||
var instance = ScriptableObject.CreateInstance<T>();
|
||||
instance.name = string.IsNullOrEmpty(name) ? typeof(T).Name : name;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of a ScriptableEvent subclass with the given name.
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static T CreateRuntimeEventInstance<T>(string name = "") where T : ScriptableEventBase
|
||||
{
|
||||
return CreateInstance<T>(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a deep copy of the template
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the subclass to create.</typeparam>
|
||||
/// <param name="template">Template to copy.</param>
|
||||
/// <returns>The newly created or copied instance.</returns>
|
||||
public static T CreateCopy<T>(T template) where T : ScriptableObject
|
||||
{
|
||||
// Create a deep copy of the template
|
||||
T copy = Object.Instantiate(template);
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<(Type, string), List<FieldInfo>> _cachedInjectableFields =
|
||||
new Dictionary<(Type, string), List<FieldInfo>>();
|
||||
|
||||
public static void InjectInChildren<TVariable>(GameObject gameObject,
|
||||
TVariable runtimeVariable, string id, bool debugLogEnabled)
|
||||
where TVariable : ScriptableObject
|
||||
{
|
||||
var components = gameObject.GetComponentsInChildren<MonoBehaviour>();
|
||||
foreach (var component in components)
|
||||
{
|
||||
if (component == null)
|
||||
continue;
|
||||
|
||||
var type = component.GetType();
|
||||
var cacheKey = (type, variableName: id);
|
||||
if (!_cachedInjectableFields.TryGetValue(cacheKey, out var fields))
|
||||
{
|
||||
fields = new List<FieldInfo>();
|
||||
foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic |
|
||||
BindingFlags.Public))
|
||||
{
|
||||
if (Attribute.IsDefined(field, typeof(RuntimeInjectableAttribute)) &&
|
||||
field.FieldType == typeof(TVariable))
|
||||
{
|
||||
// Check if the field has the correct variable name
|
||||
var attribute = field.GetCustomAttribute<RuntimeInjectableAttribute>();
|
||||
if (attribute.Id != id || string.IsNullOrEmpty(attribute.Id))
|
||||
continue;
|
||||
|
||||
fields.Add(field);
|
||||
}
|
||||
}
|
||||
|
||||
_cachedInjectableFields[cacheKey] = fields;
|
||||
}
|
||||
|
||||
foreach (var field in fields)
|
||||
{
|
||||
field.SetValue(component, runtimeVariable);
|
||||
if (debugLogEnabled)
|
||||
{
|
||||
Debug.Log(
|
||||
$"<color=#f75369>[Injected]</color> {runtimeVariable.name} into {component.GetType().Name}.{field.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca4d627fedfbb3946bb2553a6169a16a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
207
Assets/Obvious/Soap/Core/Runtime/Utilities/SoapUtils.cs
Normal file
207
Assets/Obvious/Soap/Core/Runtime/Utilities/SoapUtils.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Obvious.Soap
|
||||
{
|
||||
//TODO: Rename to SoapTypeUtils when doing major Update
|
||||
public static class SoapUtils
|
||||
{
|
||||
private static readonly Dictionary<string, string> intrinsicToSystemTypeMap = new Dictionary<string, string>
|
||||
{
|
||||
{ "byte", "System.Byte" },
|
||||
{ "sbyte", "System.SByte" },
|
||||
{ "char", "System.Char" },
|
||||
{ "decimal", "System.Decimal" }, //not serializable by unity [DO NOT USE]. Use float or double instead.
|
||||
{ "double", "System.Double" },
|
||||
{ "uint", "System.UInt32" },
|
||||
{ "nint", "System.IntPtr" },
|
||||
{ "nuint", "System.UIntPtr" },
|
||||
{ "long", "System.Int64" },
|
||||
{ "ulong", "System.UInt64" },
|
||||
{ "short", "System.Int16" },
|
||||
{ "ushort", "System.UInt16" },
|
||||
{ "int", "System.Int32" },
|
||||
{ "float", "System.Single" },
|
||||
{ "string", "System.String" },
|
||||
{ "object", "System.Object" },
|
||||
{ "bool", "System.Boolean" }
|
||||
};
|
||||
|
||||
private static readonly HashSet<Type> unityTypes = new HashSet<Type>()
|
||||
{
|
||||
typeof(string), typeof(Vector4), typeof(Vector3), typeof(Vector2), typeof(Rect),
|
||||
typeof(Quaternion), typeof(Color), typeof(Color32), typeof(LayerMask), typeof(Bounds),
|
||||
typeof(Matrix4x4), typeof(AnimationCurve), typeof(Gradient), typeof(RectOffset),
|
||||
typeof(bool[]), typeof(byte[]), typeof(sbyte[]), typeof(char[]),
|
||||
typeof(double[]), typeof(float[]), typeof(int[]), typeof(uint[]), typeof(long[]),
|
||||
typeof(ulong[]), typeof(short[]), typeof(ushort[]), typeof(string[]),
|
||||
typeof(Vector4[]), typeof(Vector3[]), typeof(Vector2[]), typeof(Rect[]),
|
||||
typeof(Quaternion[]), typeof(Color[]), typeof(Color32[]), typeof(LayerMask[]), typeof(Bounds[]),
|
||||
typeof(Matrix4x4[]), typeof(AnimationCurve[]), typeof(Gradient[]), typeof(RectOffset[]),
|
||||
typeof(List<bool>), typeof(List<byte>), typeof(List<sbyte>), typeof(List<char>),
|
||||
typeof(List<double>), typeof(List<float>), typeof(List<int>), typeof(List<uint>), typeof(List<long>),
|
||||
typeof(List<ulong>), typeof(List<short>), typeof(List<ushort>), typeof(List<string>),
|
||||
typeof(List<Vector4>), typeof(List<Vector3>), typeof(List<Vector2>), typeof(List<Rect>),
|
||||
typeof(List<Quaternion>), typeof(List<Color>), typeof(List<Color32>), typeof(List<LayerMask>),
|
||||
typeof(List<Bounds>),
|
||||
typeof(List<Matrix4x4>), typeof(List<AnimationCurve>), typeof(List<Gradient>), typeof(List<RectOffset>),
|
||||
typeof(Vector3Int), typeof(Vector2Int), typeof(RectInt), typeof(BoundsInt),
|
||||
typeof(Vector3Int[]), typeof(Vector2Int[]), typeof(RectInt[]), typeof(BoundsInt[]),
|
||||
typeof(List<Vector3Int>), typeof(List<Vector2Int>), typeof(List<RectInt>), typeof(List<BoundsInt>),
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> unityTypesAsString = new HashSet<string>()
|
||||
{
|
||||
"string", "Vector4", "Vector3", "Vector2", "Rect",
|
||||
"Quaternion", "Color", "Color32", "LayerMask", "Bounds",
|
||||
"Matrix4x4", "AnimationCurve", "Gradient", "RectOffset",
|
||||
"GameObject", "Transform", "Material", "Texture", "Sprite",
|
||||
"AudioClip", "Mesh", "Shader", "Font", "TextAsset",
|
||||
"Rigidbody", "Rigidbody2D", "Camera", "Light", "AudioSource",
|
||||
"Vector2Int", "Vector3Int", "Collider", "Collider2D", "BoundsInt",
|
||||
"RectInt", "MeshRenderer", "SpriteRenderer", "BoxCollider",
|
||||
"BoxCollider2D", "CircleCollider2D", "PolygonCollider2D", "CapsuleCollider",
|
||||
"CapsuleCollider2D", "MeshCollider", "MeshCollider2D", "SphereCollider",
|
||||
"SphereCollider2D", "TerrainCollider", "WheelCollider", "WheelCollider2D",
|
||||
"CharacterController", "CharacterJoint", "ConfigurableJoint", "FixedJoint",
|
||||
"HingeJoint", "SpringJoint", "SliderJoint", "TargetJoint2D",
|
||||
"AnimationCurve", "AnimationClip", "Animator", "AnimatorController",
|
||||
};
|
||||
|
||||
|
||||
public static bool IsIntrinsicType(string typeName)
|
||||
{
|
||||
if (intrinsicToSystemTypeMap.TryGetValue(typeName.ToLower(), out var qualifiedName))
|
||||
typeName = qualifiedName;
|
||||
|
||||
Type type = Type.GetType(typeName);
|
||||
if (type?.Namespace != null && type.Namespace.StartsWith("System"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string GetIntrinsicType(string systemType)
|
||||
{
|
||||
return intrinsicToSystemTypeMap.FirstOrDefault(x =>
|
||||
x.Value == $"System.{systemType}").Key ?? systemType;
|
||||
}
|
||||
|
||||
public static bool IsUnityType(Type type) => unityTypes.Contains(type);
|
||||
public static bool IsUnityType(string type) => unityTypesAsString.Contains(type);
|
||||
|
||||
internal static bool CanBeCreated(string typeName)
|
||||
{
|
||||
if (IsIntrinsicType(typeName) || IsUnityType(typeName))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsSerializable(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
return false;
|
||||
|
||||
if (typeof(UnityEngine.Object).IsAssignableFrom(type) || type.IsEnum)
|
||||
return true;
|
||||
|
||||
if (type.IsArray)
|
||||
{
|
||||
//dont support multi-dimensional arrays
|
||||
if (type.GetArrayRank() != 1)
|
||||
return false;
|
||||
return IsSerializable(type.GetElementType());
|
||||
}
|
||||
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
var genericDefinition = type.GetGenericTypeDefinition();
|
||||
if (genericDefinition == typeof(Nullable<>)
|
||||
|| genericDefinition == typeof(List<>))
|
||||
{
|
||||
return IsSerializable(type.GetGenericArguments()[0]);
|
||||
}
|
||||
|
||||
// Generic types are allowed on 2020.1 and later
|
||||
#if !UNITY_2020_1_OR_NEWER
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
return Attribute.IsDefined(type, typeof(SerializableAttribute), false);
|
||||
}
|
||||
|
||||
// public static bool IsSerializableLazy(Type type)
|
||||
// {
|
||||
// var isSerializable = false;
|
||||
// isSerializable |= type.IsSerializable;
|
||||
// isSerializable |= type.Namespace == "UnityEngine";
|
||||
// isSerializable |= type.IsSubclassOf(typeof(MonoBehaviour));
|
||||
// return isSerializable;
|
||||
// }
|
||||
|
||||
internal static Type GetTypeByName(string name)
|
||||
{
|
||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
foreach (Type type in assembly.GetTypes())
|
||||
{
|
||||
if (string.Equals(type.Name, name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool IsCollection(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
|
||||
if (type.IsArray)
|
||||
return true;
|
||||
|
||||
if (type.IsGenericType && type.GetInterfaces().Any(i =>
|
||||
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
|
||||
return true;
|
||||
|
||||
// Check if it's a non-generic collection
|
||||
if (typeof(IEnumerable).IsAssignableFrom(type))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool InheritsFromOpenGeneric(Type type, Type openGenericBase)
|
||||
{
|
||||
if (type == null || openGenericBase == null) return false;
|
||||
|
||||
// walk class hierarchy
|
||||
for (var t = type; t != null && t != typeof(object); t = t.BaseType)
|
||||
{
|
||||
var candidate = t.IsGenericType ? t.GetGenericTypeDefinition() : t;
|
||||
if (candidate == openGenericBase)
|
||||
return true;
|
||||
}
|
||||
|
||||
// optionally check interfaces as well (useful if your base is an interface)
|
||||
if (openGenericBase.IsInterface)
|
||||
{
|
||||
foreach (var itf in type.GetInterfaces())
|
||||
{
|
||||
var candidate = itf.IsGenericType ? itf.GetGenericTypeDefinition() : itf;
|
||||
if (candidate == openGenericBase)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Obvious/Soap/Core/Runtime/Utilities/SoapUtils.cs.meta
Normal file
11
Assets/Obvious/Soap/Core/Runtime/Utilities/SoapUtils.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf7a2d5b4db6ed14fb41e4f1d73d62a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user