From 2cc403ad1732b965814fa3eaabd1b77175eff957 Mon Sep 17 00:00:00 2001 From: Sinai Date: Wed, 7 Apr 2021 17:20:09 +1000 Subject: [PATCH] Cleanup runtime-specific --- README.md | 2 +- src/Core/CSharp/ScriptInteraction.cs | 2 +- src/Core/Input/CursorUnlocker.cs | 2 +- src/Core/Input/IHandleInput.cs | 2 +- src/Core/Input/InputSystem.cs | 15 +- src/Core/Input/LegacyInput.cs | 2 +- src/Core/Input/NoInput.cs | 2 +- src/Core/ReflectionUtility.cs | 6 +- src/Core/Runtime/Il2Cpp/Il2CppProvider.cs | 59 +++++++- src/Core/Runtime/Il2Cpp/Il2CppReflection.cs | 130 ++++++++++++++++++ .../Mono}/DummyBehaviour.cs | 2 +- src/Core/Runtime/Mono/MonoProvider.cs | 25 +++- src/Core/Runtime/Mono/MonoReflection.cs | 12 ++ src/Core/Runtime/ReflectionProvider.cs | 11 ++ src/Core/Runtime/RuntimeProvider.cs | 45 ++++-- src/Core/Search/SearchProvider.cs | 40 +----- src/Core/TestClass.cs | 7 + src/ExplorerCore.cs | 6 +- src/Loader/ML/MelonLoaderConfigHandler.cs | 26 ++++ src/UI/CacheObject/CachePaired.cs | 8 +- .../Inspectors/GameObjects/ComponentList.cs | 10 -- src/UI/Inspectors/InspectUnderMouse.cs | 14 +- src/UI/Inspectors/InspectorManager.cs | 12 +- .../InteractiveDictionary.cs | 96 ++----------- .../InteractiveEnumerable.cs | 83 +---------- src/UI/InteractiveValues/InteractiveString.cs | 8 +- src/UI/Main/BaseMenuPage.cs | 11 +- src/UI/Main/CSConsole/CSharpConsole.cs | 10 +- src/UnityExplorer.csproj | 2 +- 29 files changed, 362 insertions(+), 288 deletions(-) rename src/Core/{CSharp => Runtime/Mono}/DummyBehaviour.cs (93%) diff --git a/README.md b/README.md index 4e813a7..7fc463e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ An in-game explorer and a suite of debugging tools for IL2CPP and Mono Unity games, to aid with modding development.

-## Releases [![](https://img.shields.io/github/release/sinai-dev/Explorer.svg?label=release%20notes)](../../releases/latest) [![](https://img.shields.io/github/downloads/sinai-dev/Explorer/total.svg)](../../releases) [![](https://img.shields.io/github/downloads/sinai-dev/Explorer/latest/total.svg)](../../releases/latest) +## Releases [![](https://img.shields.io/github/release/sinai-dev/UnityExplorer.svg?label=release%20notes)](../../releases/latest) [![](https://img.shields.io/github/downloads/sinai-dev/UnityExplorer/total.svg)](../../releases) [![](https://img.shields.io/github/downloads/sinai-dev/UnityExplorer/latest/total.svg)](../../releases/latest) | Mod Loader | IL2CPP | Mono | | ----------- | ------ | ---- | diff --git a/src/Core/CSharp/ScriptInteraction.cs b/src/Core/CSharp/ScriptInteraction.cs index 034b3c9..0c71220 100644 --- a/src/Core/CSharp/ScriptInteraction.cs +++ b/src/Core/CSharp/ScriptInteraction.cs @@ -20,7 +20,7 @@ namespace UnityExplorer.Core.CSharp public static void StartCoroutine(IEnumerator ienumerator) { - RuntimeProvider.Instance.StartConsoleCoroutine(ienumerator); + RuntimeProvider.Instance.StartCoroutine(ienumerator); } public static void AddUsing(string directive) diff --git a/src/Core/Input/CursorUnlocker.cs b/src/Core/Input/CursorUnlocker.cs index 7cb3d5c..86a218a 100644 --- a/src/Core/Input/CursorUnlocker.cs +++ b/src/Core/Input/CursorUnlocker.cs @@ -189,4 +189,4 @@ namespace UnityExplorer.Core.Input } } } -} +} \ No newline at end of file diff --git a/src/Core/Input/IHandleInput.cs b/src/Core/Input/IHandleInput.cs index 279e929..6fe0bfe 100644 --- a/src/Core/Input/IHandleInput.cs +++ b/src/Core/Input/IHandleInput.cs @@ -18,4 +18,4 @@ namespace UnityExplorer.Core.Input void AddUIInputModule(); void ActivateModule(); } -} +} \ No newline at end of file diff --git a/src/Core/Input/InputSystem.cs b/src/Core/Input/InputSystem.cs index 51c1e31..cb1c1bd 100644 --- a/src/Core/Input/InputSystem.cs +++ b/src/Core/Input/InputSystem.cs @@ -6,9 +6,6 @@ using UnityEngine.EventSystems; using UnityExplorer.UI; using System.Collections.Generic; using UnityExplorer.UI.Inspectors; -#if CPP -using UnhollowerRuntimeLib; -#endif namespace UnityExplorer.Core.Input { @@ -152,13 +149,9 @@ namespace UnityExplorer.Core.Input } var assetType = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionAsset"); -#if CPP - m_newInputModule = UIManager.CanvasRoot.AddComponent(Il2CppType.From(TInputSystemUIInputModule)).TryCast(); - var asset = ScriptableObject.CreateInstance(Il2CppType.From(assetType)); -#else - m_newInputModule = (BaseInputModule)UIManager.CanvasRoot.AddComponent(TInputSystemUIInputModule); - var asset = ScriptableObject.CreateInstance(assetType); -#endif + m_newInputModule = RuntimeProvider.Instance.AddComponent(UIManager.CanvasRoot, TInputSystemUIInputModule); + var asset = RuntimeProvider.Instance.CreateScriptable(assetType); + inputExtensions = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionSetupExtensions"); var addMap = inputExtensions.GetMethod("AddActionMap", new Type[] { assetType, typeof(string) }); @@ -205,4 +198,4 @@ namespace UnityExplorer.Core.Input UI_Enable.Invoke(UI_ActionMap, new object[0]); } } -} +} \ No newline at end of file diff --git a/src/Core/Input/LegacyInput.cs b/src/Core/Input/LegacyInput.cs index bdcebd4..65d4ad1 100644 --- a/src/Core/Input/LegacyInput.cs +++ b/src/Core/Input/LegacyInput.cs @@ -54,4 +54,4 @@ namespace UnityExplorer.Core.Input m_inputModule.ActivateModule(); } } -} +} \ No newline at end of file diff --git a/src/Core/Input/NoInput.cs b/src/Core/Input/NoInput.cs index 3fcf8ca..159767e 100644 --- a/src/Core/Input/NoInput.cs +++ b/src/Core/Input/NoInput.cs @@ -19,4 +19,4 @@ namespace UnityExplorer.Core.Input public void ActivateModule() { } public void AddUIInputModule() { } } -} +} \ No newline at end of file diff --git a/src/Core/ReflectionUtility.cs b/src/Core/ReflectionUtility.cs index 916d536..863b1ee 100644 --- a/src/Core/ReflectionUtility.cs +++ b/src/Core/ReflectionUtility.cs @@ -43,6 +43,9 @@ namespace UnityExplorer public static object Cast(this object obj, Type castTo) => ReflectionProvider.Instance.Cast(obj, castTo); + public static T TryCast(this object obj) + => ReflectionProvider.Instance.TryCast(obj); + /// /// Check if the provided Type is assignable to IEnumerable. /// @@ -201,10 +204,9 @@ namespace UnityExplorer { while (e.InnerException != null) { -#if CPP if (e.InnerException is System.Runtime.CompilerServices.RuntimeWrappedException) break; -#endif + e = e.InnerException; } } diff --git a/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs b/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs index 8d2f920..ad580ae 100644 --- a/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs +++ b/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs @@ -50,12 +50,47 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp ExplorerCore.Log(condition, type, true); } - public override void StartConsoleCoroutine(IEnumerator routine) + public override void StartCoroutine(IEnumerator routine) { Il2CppCoroutine.Start(routine); } - // Unity API Handlers + public override void Update() + { + Il2CppCoroutine.Process(); + } + + public override T AddComponent(GameObject obj, Type type) + { + return obj.AddComponent(Il2CppType.From(type)).TryCast(); + } + + public override ScriptableObject CreateScriptable(Type type) + { + return ScriptableObject.CreateInstance(Il2CppType.From(type)); + } + + public override void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List list) + { + var il2cppList = new Il2CppSystem.Collections.Generic.List(); + + raycaster.Raycast(data, il2cppList); + + if (il2cppList.Count > 0) + list.AddRange(il2cppList.ToArray()); + } + + public override bool IsReferenceEqual(object a, object b) + { + if (a.TryCast() is UnityEngine.Object ua) + { + var ub = b.TryCast(); + if (ub && ua.m_CachedPtr == ub.m_CachedPtr) + return true; + } + + return base.IsReferenceEqual(a, b); + } // LayerMask.LayerToName @@ -162,6 +197,26 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp return colors; } + + public override void FindSingleton(string[] possibleNames, Type type, BF flags, List instances) + { + PropertyInfo pi; + foreach (var name in possibleNames) + { + pi = type.GetProperty(name, flags); + if (pi != null) + { + var instance = pi.GetValue(null, null); + if (instance != null) + { + instances.Add(instance); + return; + } + } + } + + base.FindSingleton(possibleNames, type, flags, instances); + } } } diff --git a/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs b/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs index 7a96665..1513b0f 100644 --- a/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs +++ b/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs @@ -32,6 +32,18 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp return Il2CppCast(obj, castTo); } + public override T TryCast(object obj) + { + try + { + return (T)Il2CppCast(obj, typeof(T)); + } + catch + { + return default; + } + } + public override string ProcessTypeNameInString(Type type, string theString, ref string typeName) { if (!Il2CppTypeNotNull(type)) @@ -367,6 +379,124 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp return s_unboxMethods[name].Invoke(obj, new object[0]); } + + public override string UnboxString(object value) + { + string s = null; + // strings boxed as Il2CppSystem.Objects can behave weirdly. + // GetActualType will find they are a string, but if its boxed + // then we need to unbox it like this... + if (!(value is string) && value is Il2CppSystem.Object cppobj) + s = cppobj.ToString(); + + return s; + } + + internal static readonly Dictionary s_getEnumeratorMethods = new Dictionary(); + + internal static readonly Dictionary s_enumeratorInfos = new Dictionary(); + + internal class EnumeratorInfo + { + internal MethodInfo moveNext; + internal PropertyInfo current; + } + + public override IEnumerable EnumerateEnumerable(object value) + { + if (value == null) + return null; + + var cppEnumerable = (value as Il2CppSystem.Object)?.TryCast(); + if (cppEnumerable != null) + { + var type = value.GetType(); + if (!s_getEnumeratorMethods.ContainsKey(type)) + s_getEnumeratorMethods.Add(type, type.GetMethod("GetEnumerator")); + + var enumerator = s_getEnumeratorMethods[type].Invoke(value, null); + var enumeratorType = enumerator.GetType(); + + if (!s_enumeratorInfos.ContainsKey(enumeratorType)) + { + s_enumeratorInfos.Add(enumeratorType, new EnumeratorInfo + { + current = enumeratorType.GetProperty("Current"), + moveNext = enumeratorType.GetMethod("MoveNext"), + }); + } + var info = s_enumeratorInfos[enumeratorType]; + + // iterate + var list = new List(); + while ((bool)info.moveNext.Invoke(enumerator, null)) + list.Add(info.current.GetValue(enumerator)); + + return list; + } + + return null; + } + + public override IDictionary EnumerateDictionary(object value, Type typeOfKeys, Type typeOfValues) + { + var valueType = ReflectionUtility.GetActualType(value); + + var keyList = new List(); + var valueList = new List(); + + var hashtable = value.Cast(typeof(Il2CppSystem.Collections.Hashtable)) as Il2CppSystem.Collections.Hashtable; + + if (hashtable != null) + { + EnumerateCppHashtable(hashtable, keyList, valueList); + } + else + { + var keys = valueType.GetProperty("Keys").GetValue(value, null); + var values = valueType.GetProperty("Values").GetValue(value, null); + + EnumerateCppIDictionary(keys, keyList); + EnumerateCppIDictionary(values, valueList); + } + + var dict = Activator.CreateInstance(typeof(Dictionary<,>) + .MakeGenericType(typeOfKeys, typeOfValues)) + as IDictionary; + + for (int i = 0; i < keyList.Count; i++) + dict.Add(keyList[i], valueList[i]); + + return dict; + } + + private void EnumerateCppIDictionary(object collection, List list) + { + // invoke GetEnumerator + var enumerator = collection.GetType().GetMethod("GetEnumerator").Invoke(collection, null); + // get the type of it + var enumeratorType = enumerator.GetType(); + // reflect MoveNext and Current + var moveNext = enumeratorType.GetMethod("MoveNext"); + var current = enumeratorType.GetProperty("Current"); + // iterate + while ((bool)moveNext.Invoke(enumerator, null)) + { + list.Add(current.GetValue(enumerator, null)); + } + } + + private void EnumerateCppHashtable(Il2CppSystem.Collections.Hashtable hashtable, List keys, List values) + { + for (int i = 0; i < hashtable.buckets.Count; i++) + { + var bucket = hashtable.buckets[i]; + if (bucket == null || bucket.key == null) + continue; + keys.Add(bucket.key); + values.Add(bucket.val); + } + } } } diff --git a/src/Core/CSharp/DummyBehaviour.cs b/src/Core/Runtime/Mono/DummyBehaviour.cs similarity index 93% rename from src/Core/CSharp/DummyBehaviour.cs rename to src/Core/Runtime/Mono/DummyBehaviour.cs index 3aed5ea..3a4888f 100644 --- a/src/Core/CSharp/DummyBehaviour.cs +++ b/src/Core/Runtime/Mono/DummyBehaviour.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; using UnityEngine; -namespace UnityExplorer.Core.CSharp +namespace UnityExplorer.Core.Runtime.Mono { public class DummyBehaviour : MonoBehaviour { diff --git a/src/Core/Runtime/Mono/MonoProvider.cs b/src/Core/Runtime/Mono/MonoProvider.cs index aec08f8..e3c6a5f 100644 --- a/src/Core/Runtime/Mono/MonoProvider.cs +++ b/src/Core/Runtime/Mono/MonoProvider.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.Text; using UnityEngine; using UnityEngine.Events; +using UnityEngine.EventSystems; using UnityEngine.SceneManagement; using UnityEngine.UI; using UnityExplorer.Core; @@ -20,6 +21,8 @@ namespace UnityExplorer.Core.Runtime.Mono { Reflection = new MonoReflection(); TextureUtil = new MonoTextureUtil(); + + DummyBehaviour.Setup(); } public override void SetupEvents() @@ -32,11 +35,31 @@ namespace UnityExplorer.Core.Runtime.Mono ExplorerCore.Log(condition, type, true); } - public override void StartConsoleCoroutine(IEnumerator routine) + public override void StartCoroutine(IEnumerator routine) { DummyBehaviour.Instance.StartCoroutine(routine); } + public override void Update() + { + + } + + public override T AddComponent(GameObject obj, Type type) + { + return (T)obj.AddComponent(type); + } + + public override ScriptableObject CreateScriptable(Type type) + { + return ScriptableObject.CreateInstance(type); + } + + public override void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List list) + { + raycaster.Raycast(data, list); + } + public override string LayerToName(int layer) => LayerMask.LayerToName(layer); diff --git a/src/Core/Runtime/Mono/MonoReflection.cs b/src/Core/Runtime/Mono/MonoReflection.cs index 2c2c3c1..9b96854 100644 --- a/src/Core/Runtime/Mono/MonoReflection.cs +++ b/src/Core/Runtime/Mono/MonoReflection.cs @@ -12,6 +12,18 @@ namespace UnityExplorer.Core.Runtime.Mono public override object Cast(object obj, Type castTo) => obj; + public override T TryCast(object obj) + { + try + { + return (T)obj; + } + catch + { + return default; + } + } + // Vanilla GetType is fine for mono public override Type GetActualType(object obj) => obj.GetType(); diff --git a/src/Core/Runtime/ReflectionProvider.cs b/src/Core/Runtime/ReflectionProvider.cs index 769eb98..6ddd10b 100644 --- a/src/Core/Runtime/ReflectionProvider.cs +++ b/src/Core/Runtime/ReflectionProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; @@ -18,6 +19,8 @@ namespace UnityExplorer.Core.Runtime public abstract object Cast(object obj, Type castTo); + public abstract T TryCast(object obj); + public abstract bool IsAssignableFrom(Type toAssignTo, Type toAssignFrom); public abstract bool IsReflectionSupported(Type type); @@ -27,5 +30,13 @@ namespace UnityExplorer.Core.Runtime public abstract bool LoadModule(string module); public abstract void BoxStringToType(ref object _string, Type castTo); + + public virtual string UnboxString(object value) => (string)value; + + public virtual IDictionary EnumerateDictionary(object value, Type typeOfKeys, Type typeOfValues) + => null; + + public virtual IEnumerable EnumerateEnumerable(object value) + => null; } } diff --git a/src/Core/Runtime/RuntimeProvider.cs b/src/Core/Runtime/RuntimeProvider.cs index 1e6c38f..7b6c817 100644 --- a/src/Core/Runtime/RuntimeProvider.cs +++ b/src/Core/Runtime/RuntimeProvider.cs @@ -2,16 +2,17 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; using UnityEngine; +using UnityEngine.EventSystems; using UnityEngine.SceneManagement; using UnityEngine.UI; +using UnityExplorer.Core.Runtime; -namespace UnityExplorer.Core.Runtime +// Intentionally project-wide namespace so that its always easily accessible. +namespace UnityExplorer { - // Work in progress, this will be used to replace all the "if CPP / if MONO" - // pre-processor directives all over the codebase. - public abstract class RuntimeProvider { public static RuntimeProvider Instance; @@ -28,24 +29,33 @@ namespace UnityExplorer.Core.Runtime public static void Init() => #if CPP - Instance = new Il2Cpp.Il2CppProvider(); + Instance = new Core.Runtime.Il2Cpp.Il2CppProvider(); #else - Instance = new Mono.MonoProvider(); + Instance = new Core.Runtime.Mono.MonoProvider(); #endif - public abstract void Initialize(); public abstract void SetupEvents(); - public abstract void StartConsoleCoroutine(IEnumerator routine); + public abstract void StartCoroutine(IEnumerator routine); + + public abstract void Update(); + + public virtual bool IsReferenceEqual(object a, object b) => ReferenceEquals(a, b); // Unity API handlers + public abstract T AddComponent(GameObject obj, Type type) where T : Component; + + public abstract ScriptableObject CreateScriptable(Type type); + public abstract string LayerToName(int layer); public abstract UnityEngine.Object[] FindObjectsOfTypeAll(Type type); + public abstract void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List list); + public abstract int GetSceneHandle(Scene scene); public abstract GameObject[] GetRootGameObjects(Scene scene); @@ -53,5 +63,24 @@ namespace UnityExplorer.Core.Runtime public abstract int GetRootCount(Scene scene); public abstract ColorBlock SetColorBlock(ColorBlock colors, Color? normal = null, Color? highlighted = null, Color? pressed = null); + + public virtual void FindSingleton(string[] s_instanceNames, Type type, BindingFlags flags, List instances) + { + // Look for a typical Instance backing field. + FieldInfo fi; + foreach (var name in s_instanceNames) + { + fi = type.GetField(name, flags); + if (fi != null) + { + var instance = fi.GetValue(null); + if (instance != null) + { + instances.Add(instance); + return; + } + } + } + } } } diff --git a/src/Core/Search/SearchProvider.cs b/src/Core/Search/SearchProvider.cs index 5ae6301..a21f20a 100644 --- a/src/Core/Search/SearchProvider.cs +++ b/src/Core/Search/SearchProvider.cs @@ -67,38 +67,8 @@ namespace UnityExplorer.Core.Search { if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ToLower().Contains(nameFilter)) continue; -#if CPP - // Only look for Properties in IL2CPP, not for Mono. - PropertyInfo pi; - foreach (var name in s_instanceNames) - { - pi = type.GetProperty(name, flags); - if (pi != null) - { - var instance = pi.GetValue(null, null); - if (instance != null) - { - instances.Add(instance); - continue; - } - } - } -#endif - // Look for a typical Instance backing field. - FieldInfo fi; - foreach (var name in s_instanceNames) - { - fi = type.GetField(name, flags); - if (fi != null) - { - var instance = fi.GetValue(null); - if (instance != null) - { - instances.Add(instance); - break; - } - } - } + + RuntimeProvider.Instance.FindSingleton(s_instanceNames, type, flags, instances); } catch { } } @@ -175,15 +145,9 @@ namespace UnityExplorer.Core.Search if (canGetGameObject) { -#if MONO - var go = context == SearchContext.GameObject - ? obj as GameObject - : (obj as Component).gameObject; -#else var go = context == SearchContext.GameObject ? obj.TryCast() : obj.TryCast().gameObject; -#endif // scene check if (sceneFilter != SceneFilter.Any) diff --git a/src/Core/TestClass.cs b/src/Core/TestClass.cs index de489bb..b9747c9 100644 --- a/src/Core/TestClass.cs +++ b/src/Core/TestClass.cs @@ -16,6 +16,7 @@ namespace UnityExplorer public static string nullString = null; public static Il2CppSystem.Collections.Hashtable testHashset; + public static Il2CppSystem.Collections.Generic.List testList; static TestClass() { @@ -23,6 +24,12 @@ namespace UnityExplorer testHashset.Add("key1", "itemOne"); testHashset.Add("key2", "itemTwo"); testHashset.Add("key3", "itemThree"); + + testList = new Il2CppSystem.Collections.Generic.List(3); + testList.Add("One"); + testList.Add("Two"); + testList.Add("Three"); + //testIList = list.TryCast(); } #endif } diff --git a/src/ExplorerCore.cs b/src/ExplorerCore.cs index 3193e4d..03f173f 100644 --- a/src/ExplorerCore.cs +++ b/src/ExplorerCore.cs @@ -13,7 +13,7 @@ namespace UnityExplorer public class ExplorerCore { public const string NAME = "UnityExplorer"; - public const string VERSION = "3.3.8"; + public const string VERSION = "3.3.9"; public const string AUTHOR = "Sinai"; public const string GUID = "com.sinai.unityexplorer"; @@ -48,11 +48,13 @@ namespace UnityExplorer Log($"{NAME} {VERSION} initialized."); - //InspectorManager.Instance.Inspect(typeof(TestClass)); + InspectorManager.Instance.Inspect(typeof(TestClass)); } public static void Update() { + RuntimeProvider.Instance.Update(); + UIManager.Update(); } diff --git a/src/Loader/ML/MelonLoaderConfigHandler.cs b/src/Loader/ML/MelonLoaderConfigHandler.cs index d900fed..80f2bac 100644 --- a/src/Loader/ML/MelonLoaderConfigHandler.cs +++ b/src/Loader/ML/MelonLoaderConfigHandler.cs @@ -23,7 +23,9 @@ namespace UnityExplorer.Loader.ML try { + // TEMPORARY - JUST REQUIRED UNTIL ML 0.3.1 RELEASED MelonPreferences.Mapper.RegisterMapper(KeycodeReader, KeycodeWriter); + MelonPreferences.Mapper.RegisterMapper(MenuPagesReader, MenuPagesWriter); } catch { } } @@ -80,6 +82,8 @@ namespace UnityExplorer.Loader.ML MelonPreferences.Save(); } + // TEMPORARY - JUST REQUIRED UNTIL ML 0.3.1 RELEASED + public static KeyCode KeycodeReader(TomlObject value) { try @@ -101,6 +105,28 @@ namespace UnityExplorer.Loader.ML { return MelonPreferences.Mapper.ToToml(value.ToString()); } + + public static UI.Main.MenuPages MenuPagesReader(TomlObject value) + { + try + { + var kc = (UI.Main.MenuPages)Enum.Parse(typeof(UI.Main.MenuPages), (value as TomlString).Value); + + if (kc == default) + throw new Exception(); + + return kc; + } + catch + { + return UI.Main.MenuPages.Home; + } + } + + public static TomlObject MenuPagesWriter(UI.Main.MenuPages value) + { + return MelonPreferences.Mapper.ToToml(value.ToString()); + } } } diff --git a/src/UI/CacheObject/CachePaired.cs b/src/UI/CacheObject/CachePaired.cs index 3e09264..ec508df 100644 --- a/src/UI/CacheObject/CachePaired.cs +++ b/src/UI/CacheObject/CachePaired.cs @@ -56,8 +56,12 @@ namespace UnityExplorer.UI.CacheObject var rowObj = UIFactory.CreateHorizontalGroup(m_mainContent, "PairedGroup", false, false, true, true, 0, new Vector4(0,0,5,2), bgColor); - - var indexLabel = UIFactory.CreateLabel(rowObj, "IndexLabel", $"{this.PairType} {this.Index}:", TextAnchor.MiddleLeft); + + string lbl = $"{this.PairType}"; + if (this.PairType == PairTypes.Key) + lbl = $"[{Index}] {lbl}"; + + var indexLabel = UIFactory.CreateLabel(rowObj, "IndexLabel", lbl, TextAnchor.MiddleLeft); UIFactory.SetLayoutElement(indexLabel.gameObject, minWidth: 80, flexibleWidth: 30, minHeight: 25); IValue.m_mainContentParent = rowObj; diff --git a/src/UI/Inspectors/GameObjects/ComponentList.cs b/src/UI/Inspectors/GameObjects/ComponentList.cs index 1b9e834..8d29b21 100644 --- a/src/UI/Inspectors/GameObjects/ComponentList.cs +++ b/src/UI/Inspectors/GameObjects/ComponentList.cs @@ -78,11 +78,7 @@ namespace UnityExplorer.UI.Inspectors.GameObjects text.text = SignatureHighlighter.ParseFullSyntax(ReflectionUtility.GetActualType(comp), true); var toggle = s_compToggles[i]; -#if CPP if (comp.TryCast() is Behaviour behaviour) -#else - if (comp is Behaviour behaviour) -#endif { if (!toggle.gameObject.activeSelf) toggle.gameObject.SetActive(true); @@ -109,19 +105,13 @@ namespace UnityExplorer.UI.Inspectors.GameObjects internal static void OnCompToggleClicked(int index, bool value) { var comp = s_compShortlist[index]; -#if CPP comp.TryCast().enabled = value; -#else - (comp as Behaviour).enabled = value; -#endif } internal static void OnCompListObjectClicked(int index) { if (index >= s_compShortlist.Count || !s_compShortlist[index]) - { return; - } InspectorManager.Instance.Inspect(s_compShortlist[index]); } diff --git a/src/UI/Inspectors/InspectUnderMouse.cs b/src/UI/Inspectors/InspectUnderMouse.cs index feb4528..ae837c6 100644 --- a/src/UI/Inspectors/InspectUnderMouse.cs +++ b/src/UI/Inspectors/InspectUnderMouse.cs @@ -203,11 +203,6 @@ namespace UnityExplorer.UI.Main.Home position = mousePos }; -#if MONO - var list = new List(); -#else - var list = new Il2CppSystem.Collections.Generic.List(); -#endif //ExplorerCore.Log("~~~~~~~~~ begin raycast ~~~~~~~~"); GameObject hitObject = null; int highestLayer = int.MinValue; @@ -215,7 +210,10 @@ namespace UnityExplorer.UI.Main.Home int highestDepth = int.MinValue; foreach (var gr in graphicRaycasters) { - gr.Raycast(ped, list); + var list = new List(); + RuntimeProvider.Instance.GraphicRaycast(gr, ped, list); + + //gr.Raycast(ped, list); if (list.Count > 0) { @@ -290,8 +288,6 @@ namespace UnityExplorer.UI.Main.Home _wasDisabledGraphics.Clear(); } - #region UI - internal static Text s_objNameLabel; internal static Text s_objPathLabel; internal static Text s_mousePosLabel; @@ -328,7 +324,5 @@ namespace UnityExplorer.UI.Main.Home s_UIContent.SetActive(false); } - - #endregion } } diff --git a/src/UI/Inspectors/InspectorManager.cs b/src/UI/Inspectors/InspectorManager.cs index 4c85427..c371411 100644 --- a/src/UI/Inspectors/InspectorManager.cs +++ b/src/UI/Inspectors/InspectorManager.cs @@ -54,21 +54,11 @@ namespace UnityExplorer.UI.Inspectors // check if currently inspecting this object foreach (InspectorBase tab in m_currentInspectors) { - if (ReferenceEquals(obj, tab.Target)) + if (RuntimeProvider.Instance.IsReferenceEqual(obj, tab.Target)) { SetInspectorTab(tab); return; } -#if CPP - else if (unityObj && tab.Target is UnityEngine.Object uTabObj) - { - if (unityObj.m_CachedPtr == uTabObj.m_CachedPtr) - { - SetInspectorTab(tab); - return; - } - } -#endif } InspectorBase inspector; diff --git a/src/UI/InteractiveValues/InteractiveDictionary.cs b/src/UI/InteractiveValues/InteractiveDictionary.cs index 10de489..e2a182c 100644 --- a/src/UI/InteractiveValues/InteractiveDictionary.cs +++ b/src/UI/InteractiveValues/InteractiveDictionary.cs @@ -13,7 +13,9 @@ using UnityExplorer.UI.CacheObject; using UnityExplorer.Core; using UnityExplorer.UI.Utility; #if CPP -using CppDictionary = Il2CppSystem.Collections.IDictionary; +using AltIDictionary = Il2CppSystem.Collections.IDictionary; +#else +using AltIDictionary = System.Collections.IDictionary; #endif namespace UnityExplorer.UI.InteractiveValues @@ -48,11 +50,7 @@ namespace UnityExplorer.UI.InteractiveValues } internal IDictionary RefIDictionary; -#if CPP - internal CppDictionary RefCppDictionary; -#else - internal IDictionary RefCppDictionary = null; -#endif + internal AltIDictionary RefAltIDictionary; internal Type m_typeOfKeys; internal Type m_typeofValues; @@ -73,10 +71,11 @@ namespace UnityExplorer.UI.InteractiveValues { RefIDictionary = Value as IDictionary; -#if CPP - try { RefCppDictionary = (Value as Il2CppSystem.Object).TryCast(); } - catch { } -#endif + if (RefIDictionary == null) + { + try { RefAltIDictionary = Value.TryCast(); } + catch { } + } if (m_subContentParent.activeSelf) { @@ -129,10 +128,8 @@ namespace UnityExplorer.UI.InteractiveValues m_entries.Clear(); } -#if CPP if (RefIDictionary == null && Value != null) - RefIDictionary = EnumerateWithReflection(); -#endif + RefIDictionary = RuntimeProvider.Instance.Reflection.EnumerateDictionary(Value, m_typeOfKeys, m_typeofValues); if (RefIDictionary != null) { @@ -212,82 +209,11 @@ namespace UnityExplorer.UI.InteractiveValues RefreshDisplay(); } -#region CPP fixes -#if CPP - // temp fix for Il2Cpp IDictionary until interfaces are fixed - - private IDictionary EnumerateWithReflection() - { - var valueType = ReflectionUtility.GetActualType(Value); - - var keyList = new List(); - var valueList = new List(); - - var hashtable = Value.Cast(typeof(Il2CppSystem.Collections.Hashtable)) as Il2CppSystem.Collections.Hashtable; - - if (hashtable != null) - { - EnumerateCppHashtable(hashtable, keyList, valueList); - } - else - { - var keys = valueType.GetProperty("Keys").GetValue(Value, null); - var values = valueType.GetProperty("Values").GetValue(Value, null); - - EnumerateCppIDictionary(keys, keyList); - EnumerateCppIDictionary(values, valueList); - } - - var dict = Activator.CreateInstance(typeof(Dictionary<,>) - .MakeGenericType(m_typeOfKeys, m_typeofValues)) - as IDictionary; - - for (int i = 0; i < keyList.Count; i++) - dict.Add(keyList[i], valueList[i]); - - return dict; - } - - private void EnumerateCppIDictionary(object collection, List list) - { - // invoke GetEnumerator - var enumerator = collection.GetType().GetMethod("GetEnumerator").Invoke(collection, null); - // get the type of it - var enumeratorType = enumerator.GetType(); - // reflect MoveNext and Current - var moveNext = enumeratorType.GetMethod("MoveNext"); - var current = enumeratorType.GetProperty("Current"); - // iterate - while ((bool)moveNext.Invoke(enumerator, null)) - { - list.Add(current.GetValue(enumerator, null)); - } - } - - private void EnumerateCppHashtable(Il2CppSystem.Collections.Hashtable hashtable, List keys, List values) - { - for (int i = 0; i < hashtable.buckets.Count; i++) - { - var bucket = hashtable.buckets[i]; - if (bucket == null || bucket.key == null) - continue; - keys.Add(bucket.key); - values.Add(bucket.val); - } - } -#endif - - #endregion - - #region UI CONSTRUCTION - internal GameObject m_listContent; internal LayoutElement m_listLayout; internal PageHandler m_pageHandler; - //internal List m_rowHolders = new List(); - public override void ConstructUI(GameObject parent, GameObject subGroup) { base.ConstructUI(parent, subGroup); @@ -317,7 +243,5 @@ namespace UnityExplorer.UI.InteractiveValues contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; } - -#endregion } } diff --git a/src/UI/InteractiveValues/InteractiveEnumerable.cs b/src/UI/InteractiveValues/InteractiveEnumerable.cs index 9bf6f5b..65731db 100644 --- a/src/UI/InteractiveValues/InteractiveEnumerable.cs +++ b/src/UI/InteractiveValues/InteractiveEnumerable.cs @@ -39,11 +39,6 @@ namespace UnityExplorer.UI.InteractiveValues internal IEnumerable RefIEnumerable; internal IList RefIList; -//#if CPP -// internal object CppICollection; -//#else -// internal object CppICollection = null; -//#endif internal readonly Type m_baseEntryType; @@ -56,18 +51,6 @@ namespace UnityExplorer.UI.InteractiveValues RefIEnumerable = Value as IEnumerable; RefIList = Value as IList; -//#if CPP -// if (Value != null && RefIList == null) -// { -// try -// { -// var type = typeof(Il2CppSystem.Collections.ICollection).MakeGenericType(this.m_baseEntryType); -// CppICollection = (Value as Il2CppSystem.Object).Cast(type); -// } -// catch { } -// } -//#endif - if (m_subContentParent.activeSelf) { GetCacheEntries(); @@ -96,8 +79,8 @@ namespace UnityExplorer.UI.InteractiveValues if (Value != null) { string count = "?"; - if (m_recacheWanted && RefIList != null)// || CppICollection != null)) - count = RefIList.Count.ToString();// ?? CppICollection.Count.ToString(); + if (m_recacheWanted && RefIList != null) + count = RefIList.Count.ToString(); else if (!m_recacheWanted) count = m_entries.Count.ToString(); @@ -121,10 +104,8 @@ namespace UnityExplorer.UI.InteractiveValues m_entries.Clear(); } -#if CPP if (RefIEnumerable == null && Value != null) - RefIEnumerable = EnumerateWithReflection(); -#endif + RefIEnumerable = RuntimeProvider.Instance.Reflection.EnumerateEnumerable(Value); if (RefIEnumerable != null) { @@ -188,62 +169,6 @@ namespace UnityExplorer.UI.InteractiveValues RefreshDisplay(); } -#region CPP Helpers - -#if CPP - // some temp fixes for Il2Cpp IEnumerables until interfaces are fixed - - internal static readonly Dictionary s_getEnumeratorMethods = new Dictionary(); - - internal static readonly Dictionary s_enumeratorInfos = new Dictionary(); - - internal class EnumeratorInfo - { - internal MethodInfo moveNext; - internal PropertyInfo current; - } - - private IEnumerable EnumerateWithReflection() - { - if (Value == null) - return null; - - // new test - var CppEnumerable = (Value as Il2CppSystem.Object)?.TryCast(); - if (CppEnumerable != null) - { - var type = Value.GetType(); - if (!s_getEnumeratorMethods.ContainsKey(type)) - s_getEnumeratorMethods.Add(type, type.GetMethod("GetEnumerator")); - - var enumerator = s_getEnumeratorMethods[type].Invoke(Value, null); - var enumeratorType = enumerator.GetType(); - - if (!s_enumeratorInfos.ContainsKey(enumeratorType)) - { - s_enumeratorInfos.Add(enumeratorType, new EnumeratorInfo - { - current = enumeratorType.GetProperty("Current"), - moveNext = enumeratorType.GetMethod("MoveNext"), - }); - } - var info = s_enumeratorInfos[enumeratorType]; - - // iterate - var list = new List(); - while ((bool)info.moveNext.Invoke(enumerator, null)) - list.Add(info.current.GetValue(enumerator)); - - return list; - } - - return null; - } -#endif - -#endregion - -#region UI CONSTRUCTION internal GameObject m_listContent; internal LayoutElement m_listLayout; @@ -278,7 +203,5 @@ namespace UnityExplorer.UI.InteractiveValues contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; } - -#endregion } } diff --git a/src/UI/InteractiveValues/InteractiveString.cs b/src/UI/InteractiveValues/InteractiveString.cs index 81316a6..ed5c8ad 100644 --- a/src/UI/InteractiveValues/InteractiveString.cs +++ b/src/UI/InteractiveValues/InteractiveString.cs @@ -24,13 +24,7 @@ namespace UnityExplorer.UI.InteractiveValues public override void OnValueUpdated() { -#if CPP - // strings boxed as Il2CppSystem.Objects can behave weirdly. - // GetActualType will find they are a string, but if its boxed - // then we need to unbox it like this... - if (!(Value is string) && Value is Il2CppSystem.Object cppobj) - Value = cppobj.ToString(); -#endif + Value = RuntimeProvider.Instance.Reflection.UnboxString(Value); base.OnValueUpdated(); } diff --git a/src/UI/Main/BaseMenuPage.cs b/src/UI/Main/BaseMenuPage.cs index 7f23fef..6ae78bb 100644 --- a/src/UI/Main/BaseMenuPage.cs +++ b/src/UI/Main/BaseMenuPage.cs @@ -7,9 +7,19 @@ using UnityEngine.UI; namespace UnityExplorer.UI.Main { + public enum MenuPages + { + Home, + Search, + CSConsole, + Options + } + public abstract class BaseMenuPage { public abstract string Name { get; } + public abstract MenuPages Type { get; } + public bool WasDisabled { get; internal set; } public GameObject Content; public Button RefNavbarButton { get; set; } @@ -20,7 +30,6 @@ namespace UnityExplorer.UI.Main set => Content?.SetActive(true); } - public abstract bool Init(); public abstract void Update(); } diff --git a/src/UI/Main/CSConsole/CSharpConsole.cs b/src/UI/Main/CSConsole/CSharpConsole.cs index 19d6dc2..9a13ba5 100644 --- a/src/UI/Main/CSConsole/CSharpConsole.cs +++ b/src/UI/Main/CSConsole/CSharpConsole.cs @@ -13,15 +13,13 @@ using UnityExplorer.UI.Main.CSConsole; using UnityExplorer.Core; using UnityExplorer.Core.Unity; using UnityExplorer.UI.Utility; -#if CPP -using UnityExplorer.Core.Runtime.Il2Cpp; -#endif namespace UnityExplorer.UI.Main.CSConsole { public class CSharpConsole : BaseMenuPage { public override string Name => "C# Console"; + public override MenuPages Type => MenuPages.CSConsole; public static CSharpConsole Instance { get; private set; } @@ -53,9 +51,6 @@ namespace UnityExplorer.UI.Main.CSConsole InitConsole(); AutoCompleter.Init(); -#if MONO - DummyBehaviour.Setup(); -#endif ResetConsole(false); // Make sure compiler is supported on this platform @@ -102,9 +97,6 @@ namespace UnityExplorer.UI.Main.CSConsole UpdateConsole(); AutoCompleter.Update(); -#if CPP - Il2CppCoroutine.Process(); -#endif } public void AddUsing(string asm) diff --git a/src/UnityExplorer.csproj b/src/UnityExplorer.csproj index c957bd5..41df8d5 100644 --- a/src/UnityExplorer.csproj +++ b/src/UnityExplorer.csproj @@ -219,7 +219,7 @@ - +