2021-04-27 21:22:48 +10:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
using System.Text;
|
2021-04-28 20:47:48 +10:00
|
|
|
|
using UnityEngine;
|
2021-04-27 21:22:48 +10:00
|
|
|
|
using UnityExplorer.UI.Inspectors.CacheObject.Views;
|
|
|
|
|
using UnityExplorer.UI.Utility;
|
|
|
|
|
|
|
|
|
|
namespace UnityExplorer.UI.Inspectors.CacheObject
|
|
|
|
|
{
|
2021-04-28 20:47:48 +10:00
|
|
|
|
// TODO some of this can be reused for CacheEnumerated / CacheKVP as well, just doing members for now.
|
|
|
|
|
// Will put shared stuff in CacheObjectBase.
|
|
|
|
|
|
2021-04-27 21:22:48 +10:00
|
|
|
|
public abstract class CacheMember : CacheObjectBase
|
|
|
|
|
{
|
|
|
|
|
public ReflectionInspector ParentInspector { get; internal set; }
|
|
|
|
|
|
|
|
|
|
public Type DeclaringType { get; private set; }
|
|
|
|
|
public string NameForFiltering { get; private set; }
|
|
|
|
|
|
|
|
|
|
public object Value { get; protected set; }
|
|
|
|
|
public Type FallbackType { get; private set; }
|
|
|
|
|
|
2021-04-28 20:47:48 +10:00
|
|
|
|
public abstract bool ShouldAutoEvaluate { get; }
|
|
|
|
|
public bool HasArguments => Arguments?.Length > 0;
|
|
|
|
|
public ParameterInfo[] Arguments { get; protected set; }
|
2021-04-27 21:22:48 +10:00
|
|
|
|
public bool Evaluating { get; protected set; }
|
|
|
|
|
public bool CanWrite { get; protected set; }
|
|
|
|
|
public bool HadException { get; protected set; }
|
|
|
|
|
public Exception LastException { get; protected set; }
|
|
|
|
|
|
|
|
|
|
public string MemberLabelText { get; private set; }
|
|
|
|
|
public string TypeLabelText { get; protected set; }
|
|
|
|
|
public string ValueLabelText { get; protected set; }
|
|
|
|
|
|
2021-04-28 20:47:48 +10:00
|
|
|
|
public enum ValueState
|
|
|
|
|
{
|
|
|
|
|
NotEvaluated, Exception, NullValue,
|
|
|
|
|
Boolean, Number, String, Enum,
|
|
|
|
|
Collection, ValueStruct, Unsupported
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected ValueState State = ValueState.NotEvaluated;
|
|
|
|
|
|
|
|
|
|
private const string NOT_YET_EVAL = "<color=grey>Not yet evaluated</color>";
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initialize the CacheMember when an Inspector is opened and caches the member
|
|
|
|
|
/// </summary>
|
2021-04-27 21:22:48 +10:00
|
|
|
|
public virtual void Initialize(ReflectionInspector inspector, Type declaringType, MemberInfo member, Type returnType)
|
|
|
|
|
{
|
|
|
|
|
this.DeclaringType = declaringType;
|
|
|
|
|
this.ParentInspector = inspector;
|
|
|
|
|
this.FallbackType = returnType;
|
|
|
|
|
this.MemberLabelText = SignatureHighlighter.ParseFullSyntax(declaringType, false, member);
|
|
|
|
|
this.NameForFiltering = $"{declaringType.Name}.{member.Name}";
|
2021-04-28 20:47:48 +10:00
|
|
|
|
this.TypeLabelText = SignatureHighlighter.HighlightTypeName(FallbackType, false);
|
|
|
|
|
this.ValueLabelText = GetValueLabel();
|
2021-04-27 21:22:48 +10:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-28 20:47:48 +10:00
|
|
|
|
public virtual void OnDestroyed()
|
2021-04-27 21:22:48 +10:00
|
|
|
|
{
|
2021-04-28 20:47:48 +10:00
|
|
|
|
// TODO release IValue / Evaluate back to pool, etc
|
|
|
|
|
}
|
2021-04-27 21:22:48 +10:00
|
|
|
|
|
2021-04-28 20:47:48 +10:00
|
|
|
|
protected abstract void TryEvaluate();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Evaluate when first shown (if ShouldAutoEvaluate), or else when Evaluate button is clicked.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Evaluate()
|
|
|
|
|
{
|
|
|
|
|
TryEvaluate();
|
|
|
|
|
|
|
|
|
|
ProcessOnEvaluate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Process the CacheMember state when the value has been evaluated (or re-evaluated)
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected virtual void ProcessOnEvaluate()
|
|
|
|
|
{
|
|
|
|
|
var prevState = State;
|
2021-04-27 21:22:48 +10:00
|
|
|
|
|
|
|
|
|
if (HadException)
|
2021-04-28 20:47:48 +10:00
|
|
|
|
State = ValueState.Exception;
|
|
|
|
|
else if (Value.IsNullOrDestroyed())
|
|
|
|
|
State = ValueState.NullValue;
|
|
|
|
|
else
|
2021-04-27 21:22:48 +10:00
|
|
|
|
{
|
2021-04-28 20:47:48 +10:00
|
|
|
|
var type = Value.GetActualType();
|
|
|
|
|
|
|
|
|
|
if (type == typeof(bool))
|
|
|
|
|
State = ValueState.Boolean;
|
|
|
|
|
else if (type.IsPrimitive || type == typeof(decimal))
|
|
|
|
|
State = ValueState.Number;
|
|
|
|
|
else if (type == typeof(string))
|
|
|
|
|
State = ValueState.String;
|
|
|
|
|
else if (type.IsEnum)
|
|
|
|
|
State = ValueState.Enum;
|
|
|
|
|
else if (type.IsEnumerable() || type.IsDictionary())
|
|
|
|
|
State = ValueState.Collection;
|
|
|
|
|
// todo Color and ValueStruct
|
|
|
|
|
else
|
|
|
|
|
State = ValueState.Unsupported;
|
2021-04-27 21:22:48 +10:00
|
|
|
|
}
|
2021-04-28 20:47:48 +10:00
|
|
|
|
|
|
|
|
|
// Set label text
|
|
|
|
|
ValueLabelText = GetValueLabel();
|
|
|
|
|
|
|
|
|
|
if (State != prevState)
|
2021-04-27 21:22:48 +10:00
|
|
|
|
{
|
2021-04-28 20:47:48 +10:00
|
|
|
|
// TODO handle if subcontent / evaluate shown, check type change, etc
|
2021-04-27 21:22:48 +10:00
|
|
|
|
}
|
2021-04-28 20:47:48 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string GetValueLabel()
|
|
|
|
|
{
|
|
|
|
|
switch (State)
|
2021-04-27 21:22:48 +10:00
|
|
|
|
{
|
2021-04-28 20:47:48 +10:00
|
|
|
|
case ValueState.NotEvaluated:
|
|
|
|
|
return $"<i>{NOT_YET_EVAL} ({SignatureHighlighter.HighlightTypeName(FallbackType, true)})</i>";
|
|
|
|
|
case ValueState.Exception:
|
|
|
|
|
return $"<i><color=red>{ReflectionUtility.ReflectionExToString(LastException)}</color></i>";
|
|
|
|
|
case ValueState.Boolean:
|
|
|
|
|
case ValueState.Number:
|
|
|
|
|
return null;
|
|
|
|
|
case ValueState.String:
|
|
|
|
|
string s = Value as string;
|
|
|
|
|
if (s.Length > 200)
|
|
|
|
|
s = $"{s.Substring(0, 200)}...";
|
|
|
|
|
return $"\"{s}\"";
|
|
|
|
|
case ValueState.NullValue:
|
|
|
|
|
return $"<i>{ToStringUtility.ToStringWithType(Value, FallbackType, true)}</i>";
|
|
|
|
|
case ValueState.Enum:
|
|
|
|
|
case ValueState.Collection:
|
|
|
|
|
case ValueState.ValueStruct:
|
|
|
|
|
case ValueState.Unsupported:
|
|
|
|
|
default:
|
|
|
|
|
return ToStringUtility.ToStringWithType(Value, FallbackType, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-27 21:22:48 +10:00
|
|
|
|
|
2021-04-28 20:47:48 +10:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set the cell view for an enabled cell based on this CacheMember model.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void SetCell(CacheMemberCell cell)
|
|
|
|
|
{
|
|
|
|
|
cell.MemberLabel.text = MemberLabelText;
|
|
|
|
|
cell.ValueLabel.gameObject.SetActive(true);
|
|
|
|
|
|
|
|
|
|
cell.EvaluateHolder.SetActive(!ShouldAutoEvaluate);
|
|
|
|
|
if (!ShouldAutoEvaluate)
|
|
|
|
|
{
|
|
|
|
|
cell.EvaluateButton.Button.gameObject.SetActive(true);
|
|
|
|
|
if (HasArguments)
|
|
|
|
|
cell.EvaluateButton.ButtonText.text = $"Evaluate ({Arguments.Length})";
|
2021-04-27 21:22:48 +10:00
|
|
|
|
else
|
2021-04-28 20:47:48 +10:00
|
|
|
|
cell.EvaluateButton.ButtonText.text = "Evaluate";
|
2021-04-27 21:22:48 +10:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-28 20:47:48 +10:00
|
|
|
|
if (State == ValueState.NotEvaluated && !ShouldAutoEvaluate)
|
|
|
|
|
{
|
|
|
|
|
// todo evaluate buttons etc
|
|
|
|
|
SetCellState(cell, true, true, Color.white, false, false, false, false, false, false);
|
2021-04-27 21:22:48 +10:00
|
|
|
|
|
2021-04-28 20:47:48 +10:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (State == ValueState.NotEvaluated)
|
|
|
|
|
Evaluate();
|
|
|
|
|
|
|
|
|
|
switch (State)
|
|
|
|
|
{
|
|
|
|
|
case ValueState.Exception:
|
|
|
|
|
case ValueState.NullValue:
|
|
|
|
|
SetCellState(cell, true, true, Color.white, false, false, false, false, false, false);
|
|
|
|
|
break;
|
|
|
|
|
case ValueState.Boolean:
|
|
|
|
|
SetCellState(cell, false, false, default, true, toggleActive: true, false, CanWrite, false, false);
|
|
|
|
|
break;
|
|
|
|
|
case ValueState.Number:
|
|
|
|
|
SetCellState(cell, false, true, Color.white, true, false, inputActive: true, CanWrite, false, false);
|
|
|
|
|
break;
|
|
|
|
|
case ValueState.String:
|
|
|
|
|
SetCellState(cell, true, false, SignatureHighlighter.StringOrange, false, false, false, false, false, true);
|
|
|
|
|
break;
|
|
|
|
|
case ValueState.Enum:
|
|
|
|
|
SetCellState(cell, true, true, Color.white, false, false, false, false, false, true);
|
|
|
|
|
break;
|
|
|
|
|
case ValueState.Collection:
|
|
|
|
|
case ValueState.ValueStruct:
|
|
|
|
|
SetCellState(cell, true, true, Color.white, false, false, false, false, true, true);
|
|
|
|
|
break;
|
|
|
|
|
case ValueState.Unsupported:
|
|
|
|
|
SetCellState(cell, true, true, Color.white, false, false, false, false, true, false);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SetCellState(CacheMemberCell cell, bool valueActive, bool valueRichText, Color valueColor,
|
|
|
|
|
bool typeLabelActive, bool toggleActive, bool inputActive, bool applyActive, bool inspectActive, bool subContentActive)
|
2021-04-27 21:22:48 +10:00
|
|
|
|
{
|
2021-04-28 20:47:48 +10:00
|
|
|
|
//cell.ValueLabel.gameObject.SetActive(valueActive);
|
|
|
|
|
if (valueActive)
|
|
|
|
|
{
|
|
|
|
|
cell.ValueLabel.text = ValueLabelText;
|
|
|
|
|
cell.ValueLabel.supportRichText = valueRichText;
|
|
|
|
|
cell.ValueLabel.color = valueColor;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
cell.ValueLabel.text = "";
|
|
|
|
|
|
|
|
|
|
cell.TypeLabel.gameObject.SetActive(typeLabelActive);
|
|
|
|
|
if (typeLabelActive)
|
|
|
|
|
cell.TypeLabel.text = TypeLabelText;
|
2021-04-27 21:22:48 +10:00
|
|
|
|
|
2021-04-28 20:47:48 +10:00
|
|
|
|
cell.Toggle.gameObject.SetActive(toggleActive);
|
|
|
|
|
if (toggleActive)
|
2021-04-27 21:22:48 +10:00
|
|
|
|
{
|
2021-04-28 20:47:48 +10:00
|
|
|
|
cell.Toggle.isOn = (bool)Value;
|
|
|
|
|
cell.ToggleText.text = Value.ToString();
|
2021-04-27 21:22:48 +10:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-28 20:47:48 +10:00
|
|
|
|
cell.InputField.gameObject.SetActive(inputActive);
|
|
|
|
|
if (inputActive)
|
|
|
|
|
cell.InputField.text = Value.ToString();
|
|
|
|
|
|
|
|
|
|
cell.ApplyButton.Button.gameObject.SetActive(applyActive);
|
|
|
|
|
cell.InspectButton.Button.gameObject.SetActive(inspectActive);
|
|
|
|
|
cell.SubContentButton.Button.gameObject.SetActive(subContentActive);
|
|
|
|
|
|
|
|
|
|
cell.UpdateButton.Button.gameObject.SetActive(ShouldAutoEvaluate);
|
2021-04-27 21:22:48 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region Cache Member Util
|
|
|
|
|
|
|
|
|
|
public static bool CanProcessArgs(ParameterInfo[] parameters)
|
|
|
|
|
{
|
|
|
|
|
foreach (var param in parameters)
|
|
|
|
|
{
|
|
|
|
|
var pType = param.ParameterType;
|
|
|
|
|
|
|
|
|
|
if (pType.IsByRef && pType.HasElementType)
|
|
|
|
|
pType = pType.GetElementType();
|
|
|
|
|
|
|
|
|
|
if (pType != null && (pType.IsPrimitive || pType == typeof(string)))
|
|
|
|
|
continue;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static List<CacheMember> GetCacheMembers(object inspectorTarget, Type _type, ReflectionInspector _inspector)
|
|
|
|
|
{
|
|
|
|
|
var list = new List<CacheMember>();
|
|
|
|
|
var cachedSigs = new HashSet<string>();
|
|
|
|
|
|
|
|
|
|
var types = ReflectionUtility.GetAllBaseTypes(_type);
|
|
|
|
|
|
|
|
|
|
var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;
|
|
|
|
|
if (!_inspector.StaticOnly)
|
|
|
|
|
flags |= BindingFlags.Instance;
|
|
|
|
|
|
|
|
|
|
var infos = new List<MemberInfo>();
|
|
|
|
|
|
|
|
|
|
foreach (var declaringType in types)
|
|
|
|
|
{
|
|
|
|
|
var target = inspectorTarget;
|
|
|
|
|
if (!_inspector.StaticOnly)
|
|
|
|
|
target = target.TryCast(declaringType);
|
|
|
|
|
|
|
|
|
|
infos.Clear();
|
|
|
|
|
infos.AddRange(declaringType.GetProperties(flags));
|
|
|
|
|
infos.AddRange(declaringType.GetFields(flags));
|
2021-04-28 20:47:48 +10:00
|
|
|
|
infos.AddRange(declaringType.GetMethods(flags));
|
2021-04-27 21:22:48 +10:00
|
|
|
|
|
|
|
|
|
foreach (var member in infos)
|
|
|
|
|
{
|
|
|
|
|
if (member.DeclaringType != declaringType)
|
|
|
|
|
continue;
|
|
|
|
|
TryCacheMember(member, list, cachedSigs, declaringType, _inspector);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var typeList = types.ToList();
|
|
|
|
|
|
|
|
|
|
var sorted = new List<CacheMember>();
|
|
|
|
|
sorted.AddRange(list.Where(it => it is CacheProperty)
|
|
|
|
|
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
|
|
|
|
|
.ThenBy(it => it.NameForFiltering));
|
|
|
|
|
sorted.AddRange(list.Where(it => it is CacheField)
|
|
|
|
|
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
|
|
|
|
|
.ThenBy(it => it.NameForFiltering));
|
|
|
|
|
sorted.AddRange(list.Where(it => it is CacheMethod)
|
|
|
|
|
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
|
|
|
|
|
.ThenBy(it => it.NameForFiltering));
|
|
|
|
|
|
|
|
|
|
return sorted;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void TryCacheMember(MemberInfo member, List<CacheMember> list, HashSet<string> cachedSigs,
|
|
|
|
|
Type declaringType, ReflectionInspector _inspector, bool ignoreMethodBlacklist = false)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var sig = GetSig(member);
|
|
|
|
|
|
|
|
|
|
if (IsBlacklisted(sig))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
//ExplorerCore.Log($"Trying to cache member {sig}...");
|
|
|
|
|
//ExplorerCore.Log(member.DeclaringType.FullName + "." + member.Name);
|
|
|
|
|
|
|
|
|
|
CacheMember cached;
|
|
|
|
|
Type returnType;
|
|
|
|
|
switch (member.MemberType)
|
|
|
|
|
{
|
|
|
|
|
case MemberTypes.Method:
|
|
|
|
|
{
|
|
|
|
|
var mi = member as MethodInfo;
|
|
|
|
|
if (!ignoreMethodBlacklist && IsBlacklisted(mi))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var args = mi.GetParameters();
|
|
|
|
|
if (!CanProcessArgs(args))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
sig += AppendArgsToSig(args);
|
|
|
|
|
if (cachedSigs.Contains(sig))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cached = new CacheMethod() { MethodInfo = mi };
|
|
|
|
|
returnType = mi.ReturnType;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case MemberTypes.Property:
|
|
|
|
|
{
|
|
|
|
|
var pi = member as PropertyInfo;
|
|
|
|
|
|
|
|
|
|
var args = pi.GetIndexParameters();
|
|
|
|
|
if (!CanProcessArgs(args))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!pi.CanRead && pi.CanWrite)
|
|
|
|
|
{
|
|
|
|
|
// write-only property, cache the set method instead.
|
|
|
|
|
var setMethod = pi.GetSetMethod(true);
|
|
|
|
|
if (setMethod != null)
|
|
|
|
|
TryCacheMember(setMethod, list, cachedSigs, declaringType, _inspector, true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sig += AppendArgsToSig(args);
|
|
|
|
|
if (cachedSigs.Contains(sig))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cached = new CacheProperty() { PropertyInfo = pi };
|
|
|
|
|
returnType = pi.PropertyType;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case MemberTypes.Field:
|
|
|
|
|
{
|
|
|
|
|
var fi = member as FieldInfo;
|
|
|
|
|
cached = new CacheField() { FieldInfo = fi };
|
|
|
|
|
returnType = fi.FieldType;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default: return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cachedSigs.Add(sig);
|
|
|
|
|
|
|
|
|
|
cached.Initialize(_inspector, declaringType, member, returnType);
|
|
|
|
|
|
|
|
|
|
list.Add(cached);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
ExplorerCore.LogWarning($"Exception caching member {member.DeclaringType.FullName}.{member.Name}!");
|
|
|
|
|
ExplorerCore.Log(e.ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static string GetSig(MemberInfo member) => $"{member.DeclaringType.Name}.{member.Name}";
|
|
|
|
|
|
|
|
|
|
internal static string AppendArgsToSig(ParameterInfo[] args)
|
|
|
|
|
{
|
|
|
|
|
string ret = " (";
|
|
|
|
|
foreach (var param in args)
|
|
|
|
|
ret += $"{param.ParameterType.Name} {param.Name}, ";
|
|
|
|
|
ret += ")";
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Blacklists
|
|
|
|
|
private static readonly HashSet<string> bl_typeAndMember = new HashSet<string>
|
|
|
|
|
{
|
|
|
|
|
// these cause a crash in IL2CPP
|
|
|
|
|
#if CPP
|
|
|
|
|
"Type.DeclaringMethod",
|
|
|
|
|
"Rigidbody2D.Cast",
|
|
|
|
|
"Collider2D.Cast",
|
|
|
|
|
"Collider2D.Raycast",
|
|
|
|
|
"Texture2D.SetPixelDataImpl",
|
|
|
|
|
"Camera.CalculateProjectionMatrixFromPhysicalProperties",
|
|
|
|
|
#endif
|
|
|
|
|
// These were deprecated a long time ago, still show up in some games for some reason
|
|
|
|
|
"MonoBehaviour.allowPrefabModeInPlayMode",
|
|
|
|
|
"MonoBehaviour.runInEditMode",
|
|
|
|
|
"Component.animation",
|
|
|
|
|
"Component.audio",
|
|
|
|
|
"Component.camera",
|
|
|
|
|
"Component.collider",
|
|
|
|
|
"Component.collider2D",
|
|
|
|
|
"Component.constantForce",
|
|
|
|
|
"Component.hingeJoint",
|
|
|
|
|
"Component.light",
|
|
|
|
|
"Component.networkView",
|
|
|
|
|
"Component.particleSystem",
|
|
|
|
|
"Component.renderer",
|
|
|
|
|
"Component.rigidbody",
|
|
|
|
|
"Component.rigidbody2D",
|
|
|
|
|
};
|
|
|
|
|
private static readonly HashSet<string> bl_methodNameStartsWith = new HashSet<string>
|
|
|
|
|
{
|
|
|
|
|
// these are redundant
|
|
|
|
|
"get_",
|
|
|
|
|
"set_",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
internal static bool IsBlacklisted(string sig) => bl_typeAndMember.Any(it => sig.Contains(it));
|
|
|
|
|
internal static bool IsBlacklisted(MethodInfo method) => bl_methodNameStartsWith.Any(it => method.Name.StartsWith(it));
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|