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 [](../../releases/latest) [](../../releases) [](../../releases/latest)
+## Releases [](../../releases/latest) [](../../releases) [](../../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 @@
-
+