Enum parse support, start work on CSConsole, cleanup

This commit is contained in:
Sinai
2021-05-09 20:18:33 +10:00
parent 7b700cbe55
commit e6b253fed9
30 changed files with 1616 additions and 213 deletions

View File

@ -1,76 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Mono.CSharp;
// Thanks to ManlyMarco for most of this
namespace UnityExplorer.Core.CSharp
{
public class ScriptEvaluator : Evaluator, IDisposable
{
private static readonly HashSet<string> StdLib = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
{
"mscorlib", "System.Core", "System", "System.Xml"
};
internal static TextWriter _textWriter;
internal static StreamReportPrinter _reportPrinter;
public ScriptEvaluator(TextWriter tw) : base(BuildContext(tw))
{
_textWriter = tw;
ImportAppdomainAssemblies(ReferenceAssembly);
AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
}
public void Dispose()
{
AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;
_textWriter.Dispose();
}
private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
{
string name = args.LoadedAssembly.GetName().Name;
if (StdLib.Contains(name))
return;
ReferenceAssembly(args.LoadedAssembly);
}
private static CompilerContext BuildContext(TextWriter tw)
{
_reportPrinter = new StreamReportPrinter(tw);
var settings = new CompilerSettings
{
Version = LanguageVersion.Experimental,
GenerateDebugInfo = false,
StdLib = true,
Target = Target.Library,
WarningLevel = 0,
EnhancedWarnings = false
};
return new CompilerContext(settings, _reportPrinter);
}
private static void ImportAppdomainAssemblies(Action<Assembly> import)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
string name = assembly.GetName().Name;
if (StdLib.Contains(name))
{
continue;
}
import(assembly);
}
}
}
}

View File

@ -1,64 +0,0 @@
using System;
using Mono.CSharp;
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using UnityExplorer.Core.Runtime;
namespace UnityExplorer.Core.CSharp
{
public class ScriptInteraction : InteractiveBase
{
public static void Log(object message)
{
ExplorerCore.Log(message);
}
public static void StartCoroutine(IEnumerator ienumerator)
{
RuntimeProvider.Instance.StartCoroutine(ienumerator);
}
//public static void AddUsing(string directive)
//{
// CSharpConsole.Instance.AddUsing(directive);
//}
//public static void GetUsing()
//{
// ExplorerCore.Log(CSharpConsole.Instance.Evaluator.GetUsing());
//}
//public static void Reset()
//{
// CSharpConsole.Instance.ResetConsole();
//}
//public static object CurrentTarget()
//{
// return InspectorManager.Instance?.m_activeInspector?.Target;
//}
//public static object[] AllTargets()
//{
// int count = InspectorManager.Instance?.m_currentInspectors.Count ?? 0;
// object[] ret = new object[count];
// for (int i = 0; i < count; i++)
// {
// ret[i] = InspectorManager.Instance?.m_currentInspectors[i].Target;
// }
// return ret;
//}
//public static void Inspect(object obj)
//{
// InspectorManager.Instance.Inspect(obj);
//}
//public static void Inspect(Type type)
//{
// InspectorManager.Instance.Inspect(type);
//}
}
}

View File

@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Panels;
namespace UnityExplorer
{
public static class InspectorManager
{
public static readonly List<InspectorBase> Inspectors = new List<InspectorBase>();
public static InspectorBase ActiveInspector { get; private set; }
private static InspectorBase lastActiveInspector;
public static float PanelWidth;
public static void Inspect(object obj, CacheObjectBase sourceCache = null)
{
if (obj.IsNullOrDestroyed())
return;
obj = obj.TryCast();
if (TryFocusActiveInspector(obj))
return;
if (obj is GameObject)
CreateInspector<GameObjectInspector>(obj);
else
CreateInspector<ReflectionInspector>(obj, false, sourceCache);
}
private static bool TryFocusActiveInspector(object target)
{
foreach (var inspector in Inspectors)
{
if (inspector.Target.ReferenceEqual(target))
{
UIManager.SetPanelActive(UIManager.Panels.Inspector, true);
SetInspectorActive(inspector);
return true;
}
}
return false;
}
public static void Inspect(Type type)
{
CreateInspector<ReflectionInspector>(type, true);
}
public static void SetInspectorActive(InspectorBase inspector)
{
UnsetActiveInspector();
ActiveInspector = inspector;
inspector.OnSetActive();
}
public static void UnsetActiveInspector()
{
if (ActiveInspector != null)
{
lastActiveInspector = ActiveInspector;
ActiveInspector.OnSetInactive();
ActiveInspector = null;
}
}
private static void CreateInspector<T>(object target, bool staticReflection = false, CacheObjectBase sourceCache = null) where T : InspectorBase
{
var inspector = Pool<T>.Borrow();
Inspectors.Add(inspector);
inspector.Target = target;
if (sourceCache != null && sourceCache.CanWrite)
{
// only set parent cache object if we are inspecting a struct, otherwise there is no point.
if (target.GetType().IsValueType && inspector is ReflectionInspector ri)
ri.ParentCacheObject = sourceCache;
}
UIManager.SetPanelActive(UIManager.Panels.Inspector, true);
inspector.UIRoot.transform.SetParent(InspectorPanel.Instance.ContentHolder.transform, false);
if (inspector is ReflectionInspector reflectInspector)
reflectInspector.StaticOnly = staticReflection;
inspector.OnBorrowedFromPool(target);
SetInspectorActive(inspector);
}
internal static void ReleaseInspector<T>(T inspector) where T : InspectorBase
{
if (lastActiveInspector == inspector)
lastActiveInspector = null;
bool wasActive = ActiveInspector == inspector;
int wasIdx = Inspectors.IndexOf(inspector);
Inspectors.Remove(inspector);
inspector.OnReturnToPool();
Pool<T>.Return(inspector);
if (wasActive)
{
ActiveInspector = null;
// Try focus another inspector, or close the window.
if (lastActiveInspector != null)
{
SetInspectorActive(lastActiveInspector);
lastActiveInspector = null;
}
else if (Inspectors.Any())
{
int newIdx = Math.Min(Inspectors.Count - 1, Math.Max(0, wasIdx - 1));
SetInspectorActive(Inspectors[newIdx]);
}
else
{
UIManager.SetPanelActive(UIManager.Panels.Inspector, false);
}
}
}
internal static void Update()
{
for (int i = Inspectors.Count - 1; i >= 0; i--)
Inspectors[i].Update();
}
internal static void OnPanelResized(float width)
{
PanelWidth = width;
foreach (var obj in Inspectors)
{
if (obj is ReflectionInspector inspector)
{
inspector.SetLayouts();
}
}
}
}
}

View File

@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UnityExplorer.Core.Search
{
public enum ChildFilter
{
Any,
RootObject,
HasParent
}
}

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UnityExplorer.Core.Search
{
public enum SceneFilter
{
Any,
ActivelyLoaded,
DontDestroyOnLoad,
HideAndDontSave,
}
}

View File

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UnityExplorer.Core.Search
{
public enum SearchContext
{
UnityObject,
GameObject,
//Component,
//Custom,
Singleton,
StaticClass
}
}

View File

@ -1,188 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityExplorer.Core.Runtime;
namespace UnityExplorer.Core.Search
{
public static class SearchProvider
{
private static bool Filter(Scene scene, SceneFilter filter)
{
switch (filter)
{
case SceneFilter.Any:
return true;
case SceneFilter.DontDestroyOnLoad:
return scene == SceneHandler.DontDestroyScene;
case SceneFilter.HideAndDontSave:
return scene == SceneHandler.AssetScene;
case SceneFilter.ActivelyLoaded:
return scene != SceneHandler.DontDestroyScene && scene != SceneHandler.AssetScene;
default:
return false;
}
}
internal static List<object> UnityObjectSearch(string input, string customTypeInput, SearchContext context,
ChildFilter childFilter, SceneFilter sceneFilter)
{
var results = new List<object>();
Type searchType;
switch (context)
{
case SearchContext.GameObject:
searchType = typeof(GameObject);
break;
case SearchContext.UnityObject:
default:
if (!string.IsNullOrEmpty(customTypeInput))
{
if (ReflectionUtility.GetTypeByName(customTypeInput) is Type customType)
{
if (typeof(UnityEngine.Object).IsAssignableFrom(customType))
{
searchType = customType;
break;
}
else
ExplorerCore.LogWarning($"Custom type '{customType.FullName}' is not assignable from UnityEngine.Object!");
}
else
ExplorerCore.LogWarning($"Could not find any type by name '{customTypeInput}'!");
}
searchType = typeof(UnityEngine.Object);
break;
}
if (searchType == null)
return results;
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(searchType);
// perform filter comparers
string nameFilter = null;
if (!string.IsNullOrEmpty(input))
nameFilter = input;
bool canGetGameObject = context == SearchContext.GameObject || typeof(Component).IsAssignableFrom(searchType);
foreach (var obj in allObjects)
{
// name check
if (!string.IsNullOrEmpty(nameFilter) && !obj.name.ContainsIgnoreCase(nameFilter))
continue;
if (canGetGameObject)
{
var go = context == SearchContext.GameObject
? obj.TryCast<GameObject>()
: obj.TryCast<Component>().gameObject;
if (go)
{
// scene check
if (sceneFilter != SceneFilter.Any)
{
if (!Filter(go.scene, sceneFilter))
continue;
}
if (childFilter != ChildFilter.Any)
{
if (!go)
continue;
// root object check (no parent)
if (childFilter == ChildFilter.HasParent && !go.transform.parent)
continue;
else if (childFilter == ChildFilter.RootObject && go.transform.parent)
continue;
}
}
}
results.Add(obj);
}
return results;
}
internal static List<object> StaticClassSearch(string input)
{
var list = new List<object>();
var nameFilter = "";
if (!string.IsNullOrEmpty(input))
nameFilter = input;
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in asm.TryGetTypes().Where(it => it.IsSealed && it.IsAbstract))
{
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ContainsIgnoreCase(nameFilter))
continue;
list.Add(type);
}
}
return list;
}
internal static string[] instanceNames = new string[]
{
"m_instance",
"m_Instance",
"s_instance",
"s_Instance",
"_instance",
"_Instance",
"instance",
"Instance",
"<Instance>k__BackingField",
"<instance>k__BackingField",
};
internal static List<object> SingletonSearch(string input)
{
var instances = new List<object>();
var nameFilter = "";
if (!string.IsNullOrEmpty(input))
nameFilter = input;
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
// Search all non-static, non-enum classes.
foreach (var type in asm.TryGetTypes().Where(it => !(it.IsSealed && it.IsAbstract) && !it.IsEnum))
{
try
{
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ContainsIgnoreCase(nameFilter))
continue;
ReflectionUtility.FindSingleton(instanceNames, type, flags, instances);
}
catch { }
}
}
return instances;
}
}
}

View File

@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.UI.IValues;
using System.Reflection;
#if CPP
using UnhollowerRuntimeLib;
using UnhollowerBaseLib;
@ -11,8 +13,69 @@ using UnhollowerBaseLib;
namespace UnityExplorer.Tests
{
public struct TestValueStruct
{
public const object TestIgnoreThis = null;
public const string TestIgnoreButValid = "";
public string aString;
public int anInt;
public float aFloat;
public bool aBool;
public Vector3 AVector3;
public Vector4 aVector4;
public DateTime aDateTime;
public Color32 aColor32;
public CameraClearFlags clearFlags;
}
public enum TestEnum : long
{
Neg50 = -50,
Neg1 = -1,
Zero = 0,
One = 1,
Pos49 = 49,
Implicit50,
Also50 = 50,
AlsoAlso50 = 50,
};
public enum TestEnum2 : ulong
{
Min = ulong.MinValue,
Max = ulong.MaxValue
}
[Flags]
public enum TestFlags : int
{
All = -1,
Zero = 0,
Ok = 1,
Two = 2,
Three = 4,
Four = 8,
Five = 16,
Six = 32,
Seven = 64,
Thirteen = Six | Seven,
Fifteen = Four | Five | Six,
}
public static class TestClass
{
public static void ATestMethod(string s, float f, Vector3 vector, DateTime date, Quaternion quater, bool b, CameraClearFlags enumvalue)
{
ExplorerCore.Log($"{s}, {f}, {vector.ToString()}, {date}, {quater.eulerAngles.ToString()}, {b}, {enumvalue}");
}
public static TestValueStruct AATestStruct;
public static TestEnum AATestEnumOne = TestEnum.Neg50;
public static TestEnum2 AATestEnumTwo = TestEnum2.Max;
public static TestFlags AATestFlags = TestFlags.Thirteen;
public static BindingFlags AATestbinding;
public static HideFlags AAHideFlags;
public static List<int> AWritableList = new List<int> { 1, 2, 3, 4, 5 };
public static Dictionary<string, int> AWritableDict = new Dictionary<string, int> { { "one", 1 }, { "two", 2 } };
@ -67,6 +130,9 @@ namespace UnityExplorer.Tests
public const int ConstantInt = 5;
public static Color AColor = Color.magenta;
public static Color32 AColor32 = Color.red;
public static byte[] ByteArray = new byte[16];
public static string LongString = new string('#', 10000);
public static List<string> BigList = new List<string>(10000);
@ -123,7 +189,6 @@ namespace UnityExplorer.Tests
}
#if CPP
public static List<Il2CppSystem.Object> TestWritableBoxedList;
public static string testStringOne = "Test";
public static Il2CppSystem.Object testStringTwo = "string boxed as cpp object";
@ -141,6 +206,21 @@ namespace UnityExplorer.Tests
public static Il2CppSystem.Object cppDecimalBoxed;
public static Il2CppSystem.Object cppVector3Boxed;
public static Il2CppSystem.Object RandomBoxedColor
{
get
{
int ran = UnityEngine.Random.Range(0, 3);
switch (ran)
{
case 1: return new Color32().BoxIl2CppObject();
case 2: return Color.magenta.BoxIl2CppObject();
default:
return null;
}
}
}
public static Il2CppSystem.Collections.Hashtable cppHashset;
public static Dictionary<Il2CppSystem.String, Il2CppSystem.Object> CppBoxedDict;
@ -167,6 +247,7 @@ namespace UnityExplorer.Tests
CppBoxedList = new List<Il2CppSystem.Object>();
CppBoxedList.Add((Il2CppSystem.String)"boxedString");
CppBoxedList.Add(new Il2CppSystem.Int32 { m_value = 5 }.BoxIl2CppObject());
CppBoxedList.Add(Color.red.BoxIl2CppObject());
try
{
@ -205,12 +286,6 @@ namespace UnityExplorer.Tests
cppBoxedInt = new Il2CppSystem.Int32() { m_value = 5 }.BoxIl2CppObject();
cppInt = new Il2CppSystem.Int32 { m_value = 420 };
TestWritableBoxedList = new List<Il2CppSystem.Object>();
TestWritableBoxedList.Add(new Il2CppSystem.Int32 { m_value = 1 }.BoxIl2CppObject());
TestWritableBoxedList.Add(new Il2CppSystem.Int32 { m_value = 2 }.BoxIl2CppObject());
TestWritableBoxedList.Add(new Il2CppSystem.Int32 { m_value = 3 }.BoxIl2CppObject());
TestWritableBoxedList.Add(new Il2CppSystem.Int32 { m_value = 4 }.BoxIl2CppObject());
cppHashset = new Il2CppSystem.Collections.Hashtable();
cppHashset.Add("key1", "itemOne");
cppHashset.Add("key2", "itemTwo");

View File

@ -23,7 +23,7 @@ namespace UnityExplorer
{
if (string.IsNullOrEmpty(type.FullName))
return false;
return type.IsPrimitive || nonPrimitiveTypes.Contains(type) || customTypes.ContainsKey(type.FullName);
return type.IsPrimitive || type.IsEnum || nonPrimitiveTypes.Contains(type) || customTypes.ContainsKey(type.FullName);
}
public static bool TryParse(string input, Type type, out object obj, out Exception parseException)
@ -40,6 +40,20 @@ namespace UnityExplorer
return true;
}
if (type.IsEnum)
{
try
{
obj = Enum.Parse(type, input);
return true;
}
catch (Exception ex)
{
parseException = ex.GetInnerMostException();
return false;
}
}
try
{
if (customTypes.ContainsKey(type.FullName))
@ -63,6 +77,12 @@ namespace UnityExplorer
return false;
}
private static readonly HashSet<Type> nonFormattedTypes = new HashSet<Type>
{
typeof(IntPtr),
typeof(UIntPtr),
};
public static string ToStringForInput(object obj, Type type)
{
if (type == null || obj == null)
@ -71,6 +91,13 @@ namespace UnityExplorer
if (type == typeof(string))
return obj as string;
if (type.IsEnum)
{
return Enum.IsDefined(type, obj)
? Enum.GetName(type, obj)
: obj.ToString();
}
try
{
if (customTypes.ContainsKey(type.FullName))
@ -79,10 +106,8 @@ namespace UnityExplorer
}
else
{
if (obj is IntPtr ptr)
return ptr.ToString();
else if (obj is UIntPtr uPtr)
return uPtr.ToString();
if (nonFormattedTypes.Contains(type))
return obj.ToString();
else
return ReflectionUtility.GetMethodInfo(type, "ToString", new Type[] { typeof(IFormatProvider) })
.Invoke(obj, new object[] { en_US })
@ -104,8 +129,15 @@ namespace UnityExplorer
{
try
{
var instance = Activator.CreateInstance(type);
typeInputExamples.Add(type.AssemblyQualifiedName, ToStringForInput(instance, type));
if (type.IsEnum)
{
typeInputExamples.Add(type.AssemblyQualifiedName, Enum.GetNames(type).First());
}
else
{
var instance = Activator.CreateInstance(type);
typeInputExamples.Add(type.AssemblyQualifiedName, ToStringForInput(instance, type));
}
}
catch (Exception ex)
{

View File

@ -231,6 +231,18 @@ namespace UnityExplorer
return sb.ToString();
}
public static string GetMemberInfoColor(MemberTypes type)
{
switch (type)
{
case MemberTypes.Method: return METHOD_INSTANCE;
case MemberTypes.Property: return PROP_INSTANCE;
case MemberTypes.Field: return FIELD_INSTANCE;
default: return null;
}
}
public static string GetMemberInfoColor(MemberInfo memberInfo, out bool isStatic)
{
isStatic = false;