diff --git a/README.md b/README.md
index fbfcdf4..f43780b 100644
--- a/README.md
+++ b/README.md
@@ -12,16 +12,11 @@
-
-
-
-
- [Releases](#releases)
-- [How to install](#how-to-install)
-- [How to use](#how-to-use)
- - [Mod Config](#mod-config)
- [Features](#features)
- - [Mouse Control](#mouse-control)
+- [How to install](#how-to-install)
+- [Mod Config](#mod-config)
+- [Mouse Control](#mouse-control)
- [Building](#building)
- [Credits](#credits)
@@ -33,10 +28,23 @@
| [BepInEx](https://github.com/BepInEx/BepInEx) | ❔ [link](https://github.com/sinai-dev/Explorer/releases/latest/download/Explorer.BepInEx.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/Explorer/releases/latest/download/Explorer.BepInEx.Mono.zip) |
Il2Cpp Issues:
-* Some methods may still fail with a `MissingMethodException`, please let me know if you experience this (with full MelonLoader log please).
+* Some methods may still fail with a `MissingMethodException`, please let me know if you experience this (with full debug log please).
* Reflection may fail with certain types, see [here](https://github.com/knah/Il2CppAssemblyUnhollower#known-issues) for more details.
* Scrolling with mouse wheel in the Explorer menu may not work on all games at the moment.
+## Features
+
+
+
+
+
+* Scene Explorer : Simple menu to traverse the Transform heirarchy of the scene.
+* GameObject Inspector : Various helpful tools to see and manipulate the GameObject, similar to what you can do in the Editor.
+* Reflection Inspector : Inspect Properties and Fields. Can also set primitive values and evaluate primitive methods.
+* Search : Search for UnityEngine.Objects with various filters, or use the helpers for static Instances and Classes.
+* C# Console : Interactive console for evaluating C# methods on the fly, with some basic helpers.
+* Inspect-under-mouse : Hover over an object with a collider and inspect it by clicking on it.
+
## How to install
### MelonLoader
@@ -53,73 +61,26 @@ Requires [BepInEx](https://github.com/BepInEx/BepInEx) to be installed for your
2. Unzip the file into the `BepInEx\plugins\` folder in your game's installation directory, created by BepInEx.
3. Make sure it's not in a sub-folder, `Explorer.dll` should be directly in the `plugins\` folder.
-## How to use
-
-* Press F7 to show or hide the menu.
-* Use the Scene Explorer or the Object Search to start Exploring, or the C# Console to test some code.
-* See below for more specific details.
-
-### Mod Config
+## Mod Config
There is a simple Mod Config for the Explorer. You can access the settings via the "Options" page of the main menu.
-`Main Menu Toggle` (KeyCode)
-* Sets the keybinding for the Main Menu toggle (show/hide all Explorer windows)
+`Main Menu Toggle` (KeyCode) | Default: `F7`
* See [this article](https://docs.unity3d.com/ScriptReference/KeyCode.html) for a full list of all accepted KeyCodes.
-* Default: `F7`
-`Default Window Size` (Vector2)
+`Default Window Size` (Vector2) | Default: `x: 550, y: 700`
* Sets the default width and height for all Explorer windows when created.
-* `x` is width, `y` is height.
-* Default: `550 700 `
-`Default Items per Page` (Int)
+`Default Items per Page` (int) | Default: `20`
* Sets the default items per page when viewing lists or search results.
-* Default: `20`
-## Features
+`Enable Bitwise Editing` (bool) | Default: `false`
+* Whether or not to show the Bitwise Editing helper when inspecting integers
-### Scene Explorer
+`Enable Tab View` (bool) | Default: `true`
+* Whether or not all inspector windows a grouped into a single window with tabs.
-* A simple menu which allows you to traverse the Transform heirarchy of the scene.
-* Click on a GameObject to set it as the current path, or Inspect it to send it to an Inspector Window.
-
-### Inspectors
-
-Explorer has two main inspector modes: GameObject Inspector , and Reflection Inspector .
-
-Tips:
-* When in Tab View, GameObjects are denoted by a [G] prefix, and Reflection objects are denoted by a [R] prefix.
-* Hold Left Shift when you click the Inspect button to force Reflection mode for GameObjects and Transforms.
-
-### GameObject Inspector
-
-* Allows you to see the children and components on a GameObject.
-* Can use some basic GameObject Controls such as translating and rotating the object, destroy it, clone it, etc.
-
-### Reflection Inspector
-
-* The Reflection Inspector is used for all other supported objects.
-* Allows you to inspect Properties, Fields and basic Methods, as well as set primitive values and evaluate primitive methods.
-* Can search and filter members for the ones you are interested in.
-
-### Object Search
-
-* You can search for an `UnityEngine.Object` with the Object Search feature.
-* Filter by name, type, etc.
-* For GameObjects and Transforms you can filter which scene they are found in too.
-
-### C# console
-
-* A simple C# console, allows you to execute a method body on the fly.
-
-### Inspect-under-mouse
-
-* Press Shift+RMB (Right Mouse Button) while the Explorer menu is open to begin Inspect-Under-Mouse.
-* Hover over your desired object, if you see the name appear then you can click on it to inspect it.
-* Only objects with Colliders are supported.
-
-### Mouse Control
+## Mouse Control
Explorer can force the mouse to be visible and unlocked when the menu is open, if you have enabled "Force Unlock Mouse" (Left-Alt toggle). However, you may also want to prevent the mouse clicking-through onto the game behind Explorer, this is possible but it requires specific patches for that game.
diff --git a/src/CacheObject/CacheEnumerated.cs b/src/CacheObject/CacheEnumerated.cs
new file mode 100644
index 0000000..3f7d172
--- /dev/null
+++ b/src/CacheObject/CacheEnumerated.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Explorer.UI;
+
+namespace Explorer.CacheObject
+{
+ public class CacheEnumerated : CacheObjectBase
+ {
+ public int Index { get; set; }
+ public IList RefIList { get; set; }
+ public InteractiveEnumerable ParentEnumeration { get; set; }
+
+ public override bool CanWrite => RefIList != null && ParentEnumeration.OwnerCacheObject.CanWrite;
+
+ public override void SetValue()
+ {
+ RefIList[Index] = IValue.Value;
+ ParentEnumeration.Value = RefIList;
+
+ ParentEnumeration.OwnerCacheObject.SetValue();
+ }
+ }
+}
diff --git a/src/CacheObject/CacheFactory.cs b/src/CacheObject/CacheFactory.cs
new file mode 100644
index 0000000..4c1bfaa
--- /dev/null
+++ b/src/CacheObject/CacheFactory.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Reflection;
+using Explorer.CacheObject;
+using UnityEngine;
+
+namespace Explorer
+{
+ public static class CacheFactory
+ {
+ public static CacheObjectBase GetCacheObject(object obj)
+ {
+ if (obj == null) return null;
+
+ return GetCacheObject(obj, ReflectionHelpers.GetActualType(obj));
+ }
+
+ public static CacheObjectBase GetCacheObject(object obj, Type type)
+ {
+ var ret = new CacheObjectBase();
+ ret.Init(obj, type);
+ return ret;
+ }
+
+ public static CacheMember GetCacheObject(MemberInfo member, object declaringInstance)
+ {
+ CacheMember ret;
+
+ if (member is MethodInfo mi && CanProcessArgs(mi.GetParameters()))
+ {
+ ret = new CacheMethod();
+ ret.InitMember(mi, declaringInstance);
+ }
+ else if (member is PropertyInfo pi && CanProcessArgs(pi.GetIndexParameters()))
+ {
+ ret = new CacheProperty();
+ ret.InitMember(pi, declaringInstance);
+ }
+ else if (member is FieldInfo fi)
+ {
+ ret = new CacheField();
+ ret.InitMember(fi, declaringInstance);
+ }
+ else
+ {
+ return null;
+ }
+
+ return ret;
+ }
+
+ 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.IsPrimitive || pType == typeof(string))
+ {
+ continue;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/CacheObject/CacheField.cs b/src/CacheObject/CacheField.cs
new file mode 100644
index 0000000..6495225
--- /dev/null
+++ b/src/CacheObject/CacheField.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+
+namespace Explorer.CacheObject
+{
+ public class CacheField : CacheMember
+ {
+ public override bool IsStatic => (MemInfo as FieldInfo).IsStatic;
+
+ public override void InitMember(MemberInfo member, object declaringInstance)
+ {
+ base.InitMember(member, declaringInstance);
+
+ base.Init(null, (member as FieldInfo).FieldType);
+
+ UpdateValue();
+ }
+
+ public override void UpdateValue()
+ {
+ try
+ {
+ var fi = MemInfo as FieldInfo;
+ IValue.Value = fi.GetValue(fi.IsStatic ? null : DeclaringInstance);
+
+ base.UpdateValue();
+ }
+ catch (Exception e)
+ {
+ ReflectionException = ReflectionHelpers.ExceptionToString(e);
+ }
+ }
+
+ public override void SetValue()
+ {
+ var fi = MemInfo as FieldInfo;
+ fi.SetValue(fi.IsStatic ? null : DeclaringInstance, IValue.Value);
+
+ base.SetValue();
+ }
+ }
+}
diff --git a/src/CacheObject/CacheMember.cs b/src/CacheObject/CacheMember.cs
new file mode 100644
index 0000000..bd55929
--- /dev/null
+++ b/src/CacheObject/CacheMember.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+using Explorer.UI;
+using Explorer.UI.Shared;
+
+namespace Explorer.CacheObject
+{
+ public class CacheMember : CacheObjectBase
+ {
+ public MemberInfo MemInfo { get; set; }
+ public Type DeclaringType { get; set; }
+ public object DeclaringInstance { get; set; }
+
+ public virtual bool IsStatic { get; private set; }
+
+ public override bool HasParameters => m_arguments != null && m_arguments.Length > 0;
+ public override bool IsMember => true;
+
+ public string RichTextName => m_richTextName ?? GetRichTextName();
+ private string m_richTextName;
+
+ public override bool CanWrite => m_canWrite ?? GetCanWrite();
+ private bool? m_canWrite;
+
+ public string ReflectionException { get; set; }
+
+ public bool m_evaluated = false;
+ public bool m_isEvaluating;
+ public ParameterInfo[] m_arguments = new ParameterInfo[0];
+ public string[] m_argumentInput = new string[0];
+
+ public virtual void InitMember(MemberInfo member, object declaringInstance)
+ {
+ MemInfo = member;
+ DeclaringInstance = declaringInstance;
+ DeclaringType = member.DeclaringType;
+ }
+
+ public override void UpdateValue()
+ {
+ base.UpdateValue();
+ }
+
+ public override void SetValue()
+ {
+ // ...
+ }
+
+ public object[] ParseArguments()
+ {
+ if (m_arguments.Length < 1)
+ {
+ return null;
+ }
+
+ var parsedArgs = new List();
+ for (int i = 0; i < m_arguments.Length; i++)
+ {
+ var input = m_argumentInput[i];
+ var type = m_arguments[i].ParameterType;
+
+ if (type.IsByRef)
+ {
+ type = type.GetElementType();
+ }
+
+ if (!string.IsNullOrEmpty(input))
+ {
+ if (type == typeof(string))
+ {
+ parsedArgs.Add(input);
+ continue;
+ }
+ else
+ {
+ try
+ {
+ var arg = type.GetMethod("Parse", new Type[] { typeof(string) })
+ .Invoke(null, new object[] { input });
+
+ parsedArgs.Add(arg);
+ continue;
+ }
+ catch
+ {
+ ExplorerCore.Log($"Argument #{i} '{m_arguments[i].Name}' ({type.Name}), could not parse input '{input}'.");
+ }
+ }
+ }
+
+ // No input, see if there is a default value.
+ if (HasDefaultValue(m_arguments[i]))
+ {
+ parsedArgs.Add(m_arguments[i].DefaultValue);
+ continue;
+ }
+
+ // Try add a null arg I guess
+ parsedArgs.Add(null);
+ }
+
+ return parsedArgs.ToArray();
+ }
+
+ public static bool HasDefaultValue(ParameterInfo arg) => arg.DefaultValue != DBNull.Value;
+
+ public void DrawArgsInput()
+ {
+ GUILayout.Label($"Arguments: ", new GUILayoutOption[0]);
+ for (int i = 0; i < this.m_arguments.Length; i++)
+ {
+ var name = this.m_arguments[i].Name;
+ var input = this.m_argumentInput[i];
+ var type = this.m_arguments[i].ParameterType.Name;
+
+ var label = $"{type} ";
+ label += $"{name} ";
+ if (HasDefaultValue(this.m_arguments[i]))
+ {
+ label = $"[{label} = {this.m_arguments[i].DefaultValue ?? "null"}] ";
+ }
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+
+ GUI.skin.label.alignment = TextAnchor.MiddleCenter;
+ GUILayout.Label(i.ToString(), new GUILayoutOption[] { GUILayout.Width(15) });
+ this.m_argumentInput[i] = GUIUnstrip.TextField(input, new GUILayoutOption[] { GUILayout.Width(150) });
+ GUI.skin.label.alignment = TextAnchor.MiddleLeft;
+ GUILayout.Label(label, new GUILayoutOption[0]);
+
+ GUILayout.EndHorizontal();
+ }
+ }
+
+ private bool GetCanWrite()
+ {
+ if (MemInfo is FieldInfo fi)
+ m_canWrite = !(fi.IsLiteral && !fi.IsInitOnly);
+ else if (MemInfo is PropertyInfo pi)
+ m_canWrite = pi.CanWrite;
+ else
+ m_canWrite = false;
+
+ return (bool)m_canWrite;
+ }
+
+ private string GetRichTextName()
+ {
+ string memberColor = "";
+ bool isStatic = false;
+
+ if (MemInfo is FieldInfo fi)
+ {
+ if (fi.IsStatic)
+ {
+ isStatic = true;
+ memberColor = Syntax.Field_Static;
+ }
+ else
+ memberColor = Syntax.Field_Instance;
+ }
+ else if (MemInfo is MethodInfo mi)
+ {
+ if (mi.IsStatic)
+ {
+ isStatic = true;
+ memberColor = Syntax.Method_Static;
+ }
+ else
+ memberColor = Syntax.Method_Instance;
+ }
+ else if (MemInfo is PropertyInfo pi)
+ {
+ if (pi.GetAccessors()[0].IsStatic)
+ {
+ isStatic = true;
+ memberColor = Syntax.Prop_Static;
+ }
+ else
+ memberColor = Syntax.Prop_Instance;
+ }
+
+ string classColor;
+ if (MemInfo.DeclaringType.IsValueType)
+ {
+ classColor = Syntax.StructGreen;
+ }
+ else if (MemInfo.DeclaringType.IsAbstract && MemInfo.DeclaringType.IsSealed)
+ {
+ classColor = Syntax.Class_Static;
+ }
+ else
+ {
+ classColor = Syntax.Class_Instance;
+ }
+
+ m_richTextName = $"{MemInfo.DeclaringType.Name} .";
+ if (isStatic) m_richTextName += "";
+ m_richTextName += $"{MemInfo.Name} ";
+ if (isStatic) m_richTextName += " ";
+
+ // generic method args
+ if (this is CacheMethod cm && cm.GenericArgs.Length > 0)
+ {
+ m_richTextName += "<";
+
+ var args = "";
+ for (int i = 0; i < cm.GenericArgs.Length; i++)
+ {
+ if (args != "") args += ", ";
+ args += $"{cm.GenericArgs[i].Name} ";
+ }
+ m_richTextName += args;
+
+ m_richTextName += ">";
+ }
+
+ return m_richTextName;
+ }
+ }
+}
diff --git a/src/CachedObjects/Other/CacheMethod.cs b/src/CacheObject/CacheMethod.cs
similarity index 56%
rename from src/CachedObjects/Other/CacheMethod.cs
rename to src/CacheObject/CacheMethod.cs
index 1435d86..1b3e012 100644
--- a/src/CachedObjects/Other/CacheMethod.cs
+++ b/src/CacheObject/CacheMethod.cs
@@ -3,23 +3,28 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
+using Explorer.UI.Shared;
-namespace Explorer
+namespace Explorer.CacheObject
{
- public class CacheMethod : CacheObjectBase
+ public class CacheMethod : CacheMember
{
private CacheObjectBase m_cachedReturnValue;
public override bool HasParameters => base.HasParameters || GenericArgs.Length > 0;
+ public override bool IsStatic => (MemInfo as MethodInfo).IsStatic;
+
public Type[] GenericArgs { get; private set; }
public Type[][] GenericConstraints { get; private set; }
public string[] GenericArgInput = new string[0];
- public override void Init()
+ public override void InitMember(MemberInfo member, object declaringInstance)
{
- var mi = (MemInfo as MethodInfo);
+ base.InitMember(member, declaringInstance);
+
+ var mi = MemInfo as MethodInfo;
GenericArgs = mi.GetGenericArguments();
GenericConstraints = GenericArgs.Select(x => x.GetGenericParameterConstraints())
@@ -27,12 +32,15 @@ namespace Explorer
GenericArgInput = new string[GenericArgs.Length];
- ValueType = mi.ReturnType;
+ m_arguments = mi.GetParameters();
+ m_argumentInput = new string[m_arguments.Length];
+
+ base.Init(null, mi.ReturnType);
}
public override void UpdateValue()
{
- //base.UpdateValue();
+ // CacheMethod cannot UpdateValue directly. Need to Evaluate.
}
public void Evaluate()
@@ -64,7 +72,8 @@ namespace Explorer
if (ret != null)
{
- m_cachedReturnValue = CacheFactory.GetTypeAndCacheObject(ret);
+ //m_cachedReturnValue = CacheFactory.GetTypeAndCacheObject(ret);
+ m_cachedReturnValue = CacheFactory.GetCacheObject(ret, IValue.ValueType);
m_cachedReturnValue.UpdateValue();
}
else
@@ -91,11 +100,11 @@ namespace Explorer
{
foreach (var constraint in GenericConstraints[i].Where(x => x != null))
{
- if (!constraint.IsAssignableFrom(t))
- {
+ if (!constraint.IsAssignableFrom(t))
+ {
ExplorerCore.LogWarning($"Generic argument #{i}, '{input}' is not assignable from the constraint '{constraint}'!");
return null;
- }
+ }
}
list.Add(t);
@@ -117,15 +126,20 @@ namespace Explorer
// ==== GUI DRAW ====
- public override void DrawValue(Rect window, float width)
+ //public override void Draw(Rect window, float width)
+ //{
+ // base.Draw(window, width);
+ //}
+
+ public void DrawValue(Rect window, float width)
{
- string typeLabel = $"{ValueType.FullName} ";
+ string typeLabel = $"{IValue.ValueType.FullName} ";
if (m_evaluated)
{
if (m_cachedReturnValue != null)
{
- m_cachedReturnValue.DrawValue(window, width);
+ m_cachedReturnValue.IValue.DrawValue(window, width);
}
else
{
@@ -137,5 +151,49 @@ namespace Explorer
GUILayout.Label($"Not yet evaluated ({typeLabel})", new GUILayoutOption[0]);
}
}
+
+ public void DrawGenericArgsInput()
+ {
+ GUILayout.Label($"Generic Arguments: ", new GUILayoutOption[0]);
+
+ for (int i = 0; i < this.GenericArgs.Length; i++)
+ {
+ string types = "";
+ if (this.GenericConstraints[i].Length > 0)
+ {
+ foreach (var constraint in this.GenericConstraints[i])
+ {
+ if (types != "") types += ", ";
+
+ string type;
+
+ if (constraint == null)
+ type = "Any";
+ else
+ type = constraint.ToString();
+
+ types += $"{type} ";
+ }
+ }
+ else
+ {
+ types = $"Any ";
+ }
+ var input = this.GenericArgInput[i];
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+
+ GUI.skin.label.alignment = TextAnchor.MiddleCenter;
+ GUILayout.Label(
+ $"{this.GenericArgs[i].Name} ",
+ new GUILayoutOption[] { GUILayout.Width(15) }
+ );
+ this.GenericArgInput[i] = GUIUnstrip.TextField(input, new GUILayoutOption[] { GUILayout.Width(150) });
+ GUI.skin.label.alignment = TextAnchor.MiddleLeft;
+ GUILayout.Label(types, new GUILayoutOption[0]);
+
+ GUILayout.EndHorizontal();
+ }
+ }
}
}
diff --git a/src/CacheObject/CacheObjectBase.cs b/src/CacheObject/CacheObjectBase.cs
new file mode 100644
index 0000000..270529d
--- /dev/null
+++ b/src/CacheObject/CacheObjectBase.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+using Explorer.UI;
+using Explorer.UI.Shared;
+
+namespace Explorer.CacheObject
+{
+ public class CacheObjectBase
+ {
+ public InteractiveValue IValue;
+
+ public virtual bool CanWrite => false;
+ public virtual bool HasParameters => false;
+ public virtual bool IsMember => false;
+
+ public bool IsStaticClassSearchResult { get; set; }
+
+ public virtual void Init(object obj, Type valueType)
+ {
+ if (valueType == null && obj == null)
+ {
+ return;
+ }
+
+ InteractiveValue interactive;
+
+ if (valueType == typeof(GameObject) || valueType == typeof(Transform))
+ {
+ interactive = new InteractiveGameObject();
+ }
+ else if (valueType.IsPrimitive || valueType == typeof(string))
+ {
+ interactive = new InteractivePrimitive();
+ }
+ else if (valueType.IsEnum)
+ {
+ if (valueType.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] attributes && attributes.Length > 0)
+ {
+ interactive = new InteractiveFlags();
+ }
+ else
+ {
+ interactive = new InteractiveEnum();
+ }
+ }
+ else if (valueType == typeof(Vector2) || valueType == typeof(Vector3) || valueType == typeof(Vector4))
+ {
+ interactive = new InteractiveVector();
+ }
+ else if (valueType == typeof(Quaternion))
+ {
+ interactive = new InteractiveQuaternion();
+ }
+ else if (valueType == typeof(Color))
+ {
+ interactive = new InteractiveColor();
+ }
+ else if (valueType == typeof(Rect))
+ {
+ interactive = new InteractiveRect();
+ }
+ // must check this before IsEnumerable
+ else if (ReflectionHelpers.IsDictionary(valueType))
+ {
+ interactive = new InteractiveDictionary();
+ }
+ else if (ReflectionHelpers.IsEnumerable(valueType))
+ {
+ interactive = new InteractiveEnumerable();
+ }
+ else
+ {
+ interactive = new InteractiveValue();
+ }
+
+ interactive.Value = obj;
+ interactive.ValueType = valueType;
+
+ this.IValue = interactive;
+ this.IValue.OwnerCacheObject = this;
+
+ UpdateValue();
+
+ this.IValue.Init();
+ }
+
+ public virtual void Draw(Rect window, float width)
+ {
+ IValue.Draw(window, width);
+ }
+
+ public virtual void UpdateValue()
+ {
+ IValue.UpdateValue();
+ }
+
+ public virtual void SetValue() => throw new NotImplementedException();
+ }
+}
diff --git a/src/CacheObject/CacheProperty.cs b/src/CacheObject/CacheProperty.cs
new file mode 100644
index 0000000..5959f44
--- /dev/null
+++ b/src/CacheObject/CacheProperty.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+
+namespace Explorer.CacheObject
+{
+ public class CacheProperty : CacheMember
+ {
+ public override bool IsStatic => (MemInfo as PropertyInfo).GetAccessors()[0].IsStatic;
+
+ public override void InitMember(MemberInfo member, object declaringInstance)
+ {
+ base.InitMember(member, declaringInstance);
+
+ var pi = member as PropertyInfo;
+
+ this.m_arguments = pi.GetIndexParameters();
+ this.m_argumentInput = new string[m_arguments.Length];
+
+ base.Init(null, pi.PropertyType);
+
+ UpdateValue();
+ }
+
+ public override void UpdateValue()
+ {
+ if (HasParameters && !m_isEvaluating)
+ {
+ // Need to enter parameters first.
+ return;
+ }
+
+ try
+ {
+ var pi = MemInfo as PropertyInfo;
+ var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance;
+
+ IValue.Value = pi.GetValue(target, ParseArguments());
+
+ base.UpdateValue();
+ }
+ catch (Exception e)
+ {
+ ReflectionException = ReflectionHelpers.ExceptionToString(e);
+ }
+ }
+
+ public override void SetValue()
+ {
+ var pi = MemInfo as PropertyInfo;
+ var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance;
+
+ pi.SetValue(target, IValue.Value, ParseArguments());
+
+ base.SetValue();
+ }
+ }
+}
diff --git a/src/CachedObjects/CacheFactory.cs b/src/CachedObjects/CacheFactory.cs
deleted file mode 100644
index 6faf977..0000000
--- a/src/CachedObjects/CacheFactory.cs
+++ /dev/null
@@ -1,169 +0,0 @@
-using System;
-using System.Reflection;
-using UnityEngine;
-
-namespace Explorer
-{
- public static class CacheFactory
- {
- public static CacheObjectBase GetTypeAndCacheObject(object obj)
- => GetTypeAndCacheObject(obj, null, null);
-
- public static CacheObjectBase GetTypeAndCacheObject(MemberInfo memberInfo, object declarer)
- => GetTypeAndCacheObject(null, memberInfo, declarer);
-
- public static CacheObjectBase GetTypeAndCacheObject(object obj, MemberInfo memberInfo, object declarer)
- {
- Type type = null;
-
- if (memberInfo != null)
- {
- if (memberInfo is FieldInfo fi)
- {
- type = fi.FieldType;
- }
- else if (memberInfo is PropertyInfo pi)
- {
- type = pi.PropertyType;
- }
- else if (memberInfo is MethodInfo mi)
- {
- type = mi.ReturnType;
- }
- }
- else if (obj != null)
- {
- type = ReflectionHelpers.GetActualType(obj);
- }
-
- if (type == null)
- {
- return null;
- }
-
- return GetCacheObject(obj, memberInfo, declarer, type);
- }
-
- public static CacheObjectBase GetCacheObject(object obj, Type valueType)
- => GetCacheObject(obj, null, null, valueType);
-
- private static CacheObjectBase GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance, Type valueType)
- {
- CacheObjectBase cached;
-
- var pi = memberInfo as PropertyInfo;
- var mi = memberInfo as MethodInfo;
-
- // Check if can process args
- if ((pi != null && !CanProcessArgs(pi.GetIndexParameters()))
- || (mi != null && !CanProcessArgs(mi.GetParameters())))
- {
- return null;
- }
-
- if (mi != null)
- {
- cached = new CacheMethod();
- }
- else if (valueType == typeof(GameObject) || valueType == typeof(Transform))
- {
- cached = new CacheGameObject();
- }
- else if (valueType.IsPrimitive || valueType == typeof(string))
- {
- cached = new CachePrimitive();
- }
- else if (valueType.IsEnum)
- {
- if (valueType.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] attributes && attributes.Length > 0)
- {
- cached = new CacheEnumFlags();
- }
- else
- {
- cached = new CacheEnum();
- }
- }
- else if (valueType == typeof(Vector2) || valueType == typeof(Vector3) || valueType == typeof(Vector4))
- {
- cached = new CacheVector();
- }
- else if (valueType == typeof(Quaternion))
- {
- cached = new CacheQuaternion();
- }
- else if (valueType == typeof(Color))
- {
- cached = new CacheColor();
- }
- else if (valueType == typeof(Rect))
- {
- cached = new CacheRect();
- }
- // must check this before IsEnumerable
- else if (ReflectionHelpers.IsDictionary(valueType))
- {
- cached = new CacheDictionary();
- }
- else if (ReflectionHelpers.IsEnumerable(valueType))
- {
- cached = new CacheList();
- }
- else
- {
- cached = new CacheOther();
- }
-
- cached.Value = obj;
- cached.ValueType = valueType;
-
- if (memberInfo != null)
- {
- cached.MemInfo = memberInfo;
- cached.DeclaringType = memberInfo.DeclaringType;
- cached.DeclaringInstance = declaringInstance;
- }
-
- if (pi != null)
- {
- cached.m_arguments = pi.GetIndexParameters();
- }
- else if (mi != null)
- {
- cached.m_arguments = mi.GetParameters();
- }
-
- cached.m_argumentInput = new string[cached.m_arguments.Length];
-
- cached.UpdateValue();
-
- cached.Init();
-
- return cached;
- }
-
- 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.IsPrimitive || pType == typeof(string))
- {
- continue;
- }
- else
- {
- return false;
- }
- }
-
- return true;
- }
- }
-}
diff --git a/src/CachedObjects/CacheObjectBase.cs b/src/CachedObjects/CacheObjectBase.cs
deleted file mode 100644
index 9b8e3d7..0000000
--- a/src/CachedObjects/CacheObjectBase.cs
+++ /dev/null
@@ -1,430 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using UnityEngine;
-
-namespace Explorer
-{
- public abstract class CacheObjectBase
- {
- public object Value;
- public Type ValueType;
-
- public MemberInfo MemInfo { get; set; }
- public Type DeclaringType { get; set; }
- public object DeclaringInstance { get; set; }
-
- public virtual bool HasParameters => m_arguments != null && m_arguments.Length > 0;
-
- public bool m_evaluated = false;
- public bool m_isEvaluating;
- public ParameterInfo[] m_arguments = new ParameterInfo[0];
- public string[] m_argumentInput = new string[0];
-
- public string ReflectionException { get; set; }
-
- public string RichTextName => m_richTextName ?? GetRichTextName();
- private string m_richTextName;
-
- public bool CanWrite => m_canWrite ?? GetCanWrite();
- private bool? m_canWrite;
-
- public virtual void Init() { }
-
- public abstract void DrawValue(Rect window, float width);
-
- public virtual void UpdateValue()
- {
- if (MemInfo == null)
- {
- return;
- }
-
- if (HasParameters && !m_isEvaluating)
- {
- // Need to enter parameters first
- return;
- }
-
- try
- {
- if (MemInfo.MemberType == MemberTypes.Field)
- {
- var fi = MemInfo as FieldInfo;
- Value = fi.GetValue(fi.IsStatic ? null : DeclaringInstance);
- }
- else if (MemInfo.MemberType == MemberTypes.Property)
- {
- var pi = MemInfo as PropertyInfo;
- var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance;
-
- Value = pi.GetValue(target, ParseArguments());
- }
-
- ReflectionException = null;
- m_evaluated = true;
- m_isEvaluating = false;
- }
- catch (Exception e)
- {
- ReflectionException = ReflectionHelpers.ExceptionToString(e);
- }
- }
-
- public void SetValue()
- {
- try
- {
- if (MemInfo.MemberType == MemberTypes.Field)
- {
- var fi = MemInfo as FieldInfo;
- fi.SetValue(fi.IsStatic ? null : DeclaringInstance, Value);
- }
- else if (MemInfo.MemberType == MemberTypes.Property)
- {
- var pi = MemInfo as PropertyInfo;
-
- if (HasParameters)
- {
- pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value, ParseArguments());
- }
- else
- {
- pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value, null);
- }
- }
- }
- catch (Exception e)
- {
- ExplorerCore.LogWarning($"Error setting value: {e.GetType()}, {e.Message}");
- }
- }
-
- public object[] ParseArguments()
- {
- var parsedArgs = new List();
- for (int i = 0; i < m_arguments.Length; i++)
- {
- var input = m_argumentInput[i];
- var type = m_arguments[i].ParameterType;
-
- if (type.IsByRef)
- {
- type = type.GetElementType();
- }
-
- if (!string.IsNullOrEmpty(input))
- {
- if (type == typeof(string))
- {
- parsedArgs.Add(input);
- continue;
- }
- else
- {
- try
- {
- var arg = type.GetMethod("Parse", new Type[] { typeof(string) })
- .Invoke(null, new object[] { input });
-
- parsedArgs.Add(arg);
- continue;
- }
- catch
- {
- ExplorerCore.Log($"Argument #{i} '{m_arguments[i].Name}' ({type.Name}), could not parse input '{input}'.");
- }
- }
- }
-
- // No input, see if there is a default value.
- if (HasDefaultValue(m_arguments[i]))
- {
- parsedArgs.Add(m_arguments[i].DefaultValue);
- continue;
- }
-
- // Try add a null arg I guess
- parsedArgs.Add(null);
- }
-
- return parsedArgs.ToArray();
- }
-
- public static bool HasDefaultValue(ParameterInfo arg) => arg.DefaultValue != DBNull.Value;
-
- // ========= Gui Draw ==========
-
- public const float MAX_LABEL_WIDTH = 400f;
- public const string EVALUATE_LABEL = "Evaluate ";
-
- public float CalcWhitespace(Rect window)
- {
- if (!(this is IExpandHeight)) return 0f;
-
- float whitespace = (this as IExpandHeight).WhiteSpace;
- if (whitespace > 0)
- {
- ClampLabelWidth(window, ref whitespace);
- }
-
- return whitespace;
- }
-
- public static void ClampLabelWidth(Rect window, ref float labelWidth)
- {
- float min = window.width * 0.37f;
- if (min > MAX_LABEL_WIDTH) min = MAX_LABEL_WIDTH;
-
- labelWidth = Mathf.Clamp(labelWidth, min, MAX_LABEL_WIDTH);
- }
-
- public void Draw(Rect window, float labelWidth = 215f)
- {
- if (labelWidth > 0)
- {
- ClampLabelWidth(window, ref labelWidth);
- }
-
- if (MemInfo != null)
- {
- GUILayout.Label(RichTextName, new GUILayoutOption[] { GUILayout.Width(labelWidth) });
- }
- else
- {
- GUIUnstrip.Space(labelWidth);
- }
-
- var cm = this as CacheMethod;
-
- if (HasParameters)
- {
- GUILayout.BeginVertical(new GUILayoutOption[0]);
-
- if (m_isEvaluating)
- {
- if (cm != null && cm.GenericArgs.Length > 0)
- {
- GUILayout.Label($"Generic Arguments: ", new GUILayoutOption[0]);
-
- for (int i = 0; i < cm.GenericArgs.Length; i++)
- {
- string types = "";
- if (cm.GenericConstraints[i].Length > 0)
- {
- foreach (var constraint in cm.GenericConstraints[i])
- {
- if (types != "") types += ", ";
-
- string type;
-
- if (constraint == null)
- type = "Any";
- else
- type = constraint.ToString();
-
- types += $"{type} ";
- }
- }
- else
- {
- types = $"Any ";
- }
- var input = cm.GenericArgInput[i];
-
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
-
- GUI.skin.label.alignment = TextAnchor.MiddleCenter;
- GUILayout.Label(
- $"{cm.GenericArgs[i].Name} ",
- new GUILayoutOption[] { GUILayout.Width(15) }
- );
- cm.GenericArgInput[i] = GUIUnstrip.TextField(input, new GUILayoutOption[] { GUILayout.Width(150) });
- GUI.skin.label.alignment = TextAnchor.MiddleLeft;
- GUILayout.Label(types, new GUILayoutOption[0]);
-
- GUILayout.EndHorizontal();
- }
- }
-
- if (m_arguments.Length > 0)
- {
- GUILayout.Label($"Arguments: ", new GUILayoutOption[0]);
- for (int i = 0; i < m_arguments.Length; i++)
- {
- var name = m_arguments[i].Name;
- var input = m_argumentInput[i];
- var type = m_arguments[i].ParameterType.Name;
-
- var label = $"{type} ";
- label += $"{name} ";
- if (HasDefaultValue(m_arguments[i]))
- {
- label = $"[{label} = {m_arguments[i].DefaultValue ?? "null"}] ";
- }
-
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
-
- GUI.skin.label.alignment = TextAnchor.MiddleCenter;
- GUILayout.Label(i.ToString(), new GUILayoutOption[] { GUILayout.Width(15) });
- m_argumentInput[i] = GUIUnstrip.TextField(input, new GUILayoutOption[] { GUILayout.Width(150) });
- GUI.skin.label.alignment = TextAnchor.MiddleLeft;
- GUILayout.Label(label, new GUILayoutOption[0]);
-
- GUILayout.EndHorizontal();
- }
- }
-
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) }))
- {
- if (cm != null)
- cm.Evaluate();
- else
- UpdateValue();
- }
- if (GUILayout.Button("Cancel", new GUILayoutOption[] { GUILayout.Width(70) }))
- {
- m_isEvaluating = false;
- }
- GUILayout.EndHorizontal();
- }
- else
- {
- var lbl = $"Evaluate (";
- int len = m_arguments.Length;
- if (cm != null) len += cm.GenericArgs.Length;
- lbl += len + " params)";
-
- if (GUILayout.Button(lbl, new GUILayoutOption[] { GUILayout.Width(150) }))
- {
- m_isEvaluating = true;
- }
- }
-
- GUILayout.EndVertical();
-
- GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUIUnstrip.Space(labelWidth);
- }
- else if (cm != null)
- {
- if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) }))
- {
- cm.Evaluate();
- }
-
- GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUIUnstrip.Space(labelWidth);
- }
-
- string typeName = $"{ValueType.FullName} ";
-
- if (!string.IsNullOrEmpty(ReflectionException))
- {
- GUILayout.Label("Reflection failed! (" + ReflectionException + ")", new GUILayoutOption[0]);
- }
- else if ((HasParameters || this is CacheMethod) && !m_evaluated)
- {
- GUILayout.Label($"Not yet evaluated ({typeName})", new GUILayoutOption[0]);
- }
- else if (Value == null && !(this is CacheMethod))
- {
- GUILayout.Label($"null ({typeName}) ", new GUILayoutOption[0]);
- }
- else
- {
- DrawValue(window, window.width - labelWidth - 90);
- }
- }
-
- private bool GetCanWrite()
- {
- if (MemInfo is FieldInfo fi)
- m_canWrite = !(fi.IsLiteral && !fi.IsInitOnly);
- else if (MemInfo is PropertyInfo pi)
- m_canWrite = pi.CanWrite;
- else
- m_canWrite = false;
-
- return (bool)m_canWrite;
- }
-
- private string GetRichTextName()
- {
- string memberColor = "";
- bool isStatic = false;
-
- if (MemInfo is FieldInfo fi)
- {
- if (fi.IsStatic)
- {
- isStatic = true;
- memberColor = UIStyles.Syntax.Field_Static;
- }
- else
- memberColor = UIStyles.Syntax.Field_Instance;
- }
- else if (MemInfo is MethodInfo mi)
- {
- if (mi.IsStatic)
- {
- isStatic = true;
- memberColor = UIStyles.Syntax.Method_Static;
- }
- else
- memberColor = UIStyles.Syntax.Method_Instance;
- }
- else if (MemInfo is PropertyInfo pi)
- {
- if (pi.GetAccessors()[0].IsStatic)
- {
- isStatic = true;
- memberColor = UIStyles.Syntax.Prop_Static;
- }
- else
- memberColor = UIStyles.Syntax.Prop_Instance;
- }
-
- string classColor;
- if (MemInfo.DeclaringType.IsValueType)
- {
- classColor = UIStyles.Syntax.StructGreen;
- }
- else if (MemInfo.DeclaringType.IsAbstract && MemInfo.DeclaringType.IsSealed)
- {
- classColor = UIStyles.Syntax.Class_Static;
- }
- else
- {
- classColor = UIStyles.Syntax.Class_Instance;
- }
-
- m_richTextName = $"{MemInfo.DeclaringType.Name} .";
- if (isStatic) m_richTextName += "";
- m_richTextName += $"{MemInfo.Name} ";
- if (isStatic) m_richTextName += " ";
-
- // generic method args
- if (this is CacheMethod cm && cm.GenericArgs.Length > 0)
- {
- m_richTextName += "<";
-
- var args = "";
- for (int i = 0; i < cm.GenericArgs.Length; i++)
- {
- if (args != "") args += ", ";
- args += $"{cm.GenericArgs[i].Name} ";
- }
- m_richTextName += args;
-
- m_richTextName += ">";
- }
-
- return m_richTextName;
- }
- }
-}
diff --git a/src/CachedObjects/Object/CacheGameObject.cs b/src/CachedObjects/Object/CacheGameObject.cs
deleted file mode 100644
index baba7e5..0000000
--- a/src/CachedObjects/Object/CacheGameObject.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using UnityEngine;
-
-namespace Explorer
-{
- public class CacheGameObject : CacheObjectBase
- {
- public override void DrawValue(Rect window, float width)
- {
- UIHelpers.GOButton(Value, null, false, width);
- }
-
- public override void UpdateValue()
- {
- base.UpdateValue();
- }
- }
-}
diff --git a/src/CachedObjects/Other/CacheOther.cs b/src/CachedObjects/Other/CacheOther.cs
deleted file mode 100644
index 7916aa4..0000000
--- a/src/CachedObjects/Other/CacheOther.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System;
-using System.Reflection;
-using UnityEngine;
-
-namespace Explorer
-{
- public class CacheOther : CacheObjectBase
- {
- public string ButtonLabel => m_btnLabel ?? GetButtonLabel();
- private string m_btnLabel;
-
- public MethodInfo ToStringMethod => m_toStringMethod ?? GetToStringMethod();
- private MethodInfo m_toStringMethod;
-
- public override void UpdateValue()
- {
- base.UpdateValue();
-
- GetButtonLabel();
- }
-
- public override void DrawValue(Rect window, float width)
- {
- GUI.skin.button.alignment = TextAnchor.MiddleLeft;
- if (GUILayout.Button(ButtonLabel, new GUILayoutOption[] { GUILayout.Width(width - 15) }))
- {
- WindowManager.InspectObject(Value, out bool _);
- }
- GUI.skin.button.alignment = TextAnchor.MiddleCenter;
- }
-
- private MethodInfo GetToStringMethod()
- {
- try
- {
- m_toStringMethod = ReflectionHelpers.GetActualType(Value).GetMethod("ToString", new Type[0])
- ?? typeof(object).GetMethod("ToString", new Type[0]);
-
- // test invoke
- m_toStringMethod.Invoke(Value, null);
- }
- catch
- {
- m_toStringMethod = typeof(object).GetMethod("ToString", new Type[0]);
- }
- return m_toStringMethod;
- }
-
- private string GetButtonLabel()
- {
- if (Value == null) return null;
-
- string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
-
- var classColor = ValueType.IsAbstract && ValueType.IsSealed
- ? UIStyles.Syntax.Class_Static
- : UIStyles.Syntax.Class_Instance;
-
- string typeLabel = $"{ValueType.FullName} ";
-
- if (Value is UnityEngine.Object)
- {
- label = label.Replace($"({ValueType.FullName})", $"({typeLabel})");
- }
- else
- {
- if (!label.Contains(ValueType.FullName))
- {
- label += $" ({typeLabel})";
- }
- else
- {
- label = label.Replace(ValueType.FullName, typeLabel);
- }
- }
-
- return m_btnLabel = label;
- }
- }
-}
diff --git a/src/Config/ModConfig.cs b/src/Config/ModConfig.cs
index df2d9f8..b7ffd2e 100644
--- a/src/Config/ModConfig.cs
+++ b/src/Config/ModConfig.cs
@@ -2,7 +2,7 @@
using System.Xml.Serialization;
using UnityEngine;
-namespace Explorer
+namespace Explorer.Config
{
public class ModConfig
{
@@ -13,9 +13,13 @@ namespace Explorer
[XmlIgnore] public static ModConfig Instance;
- public KeyCode Main_Menu_Toggle = KeyCode.F7;
+ // Actual configs
+ public KeyCode Main_Menu_Toggle = KeyCode.F7;
public Vector2 Default_Window_Size = new Vector2(550, 700);
- public int Default_Page_Limit = 20;
+ public int Default_Page_Limit = 20;
+ public bool Bitwise_Support = false;
+ public bool Tab_View = true;
+ //public bool Main_Toggle_Global = true;
public static void OnLoad()
{
@@ -43,7 +47,7 @@ namespace Explorer
Instance = (ModConfig)Serializer.Deserialize(file);
}
}
- catch
+ catch
{
return false;
}
diff --git a/src/Explorer.csproj b/src/Explorer.csproj
index 52a2762..45bcfc7 100644
--- a/src/Explorer.csproj
+++ b/src/Explorer.csproj
@@ -197,58 +197,67 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -257,6 +266,7 @@
+
diff --git a/src/ExplorerCore.cs b/src/ExplorerCore.cs
index f1828f7..28b0b90 100644
--- a/src/ExplorerCore.cs
+++ b/src/ExplorerCore.cs
@@ -1,11 +1,16 @@
-using UnityEngine;
+using Explorer.Config;
+using Explorer.UI;
+using Explorer.UI.Inspectors;
+using Explorer.UI.Main;
+using Explorer.UI.Shared;
+using UnityEngine;
namespace Explorer
{
public class ExplorerCore
{
- public const string NAME = "Explorer (" + PLATFORM + ", " + MODLOADER + ")";
- public const string VERSION = "1.8.3.1";
+ public const string NAME = "Explorer " + VERSION + " (" + PLATFORM + ", " + MODLOADER + ")";
+ public const string VERSION = "2.0.0";
public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.explorer";
@@ -34,9 +39,11 @@ namespace Explorer
new WindowManager();
InputManager.Init();
- CursorControl.Init();
+ ForceUnlockCursor.Init();
- Log($"{NAME} {VERSION} initialized.");
+ ShowMenu = true;
+
+ Log($"{NAME} initialized.");
}
public static bool ShowMenu
@@ -49,7 +56,7 @@ namespace Explorer
private static void SetShowMenu(bool show)
{
m_showMenu = show;
- CursorControl.UpdateCursorControl();
+ ForceUnlockCursor.UpdateCursorControl();
}
public static void Update()
@@ -61,7 +68,7 @@ namespace Explorer
if (ShowMenu)
{
- CursorControl.Update();
+ //CursorControl.Update();
InspectUnderMouse.Update();
MainMenu.Instance.Update();
@@ -89,30 +96,30 @@ namespace Explorer
SearchPage.Instance?.OnSceneChange();
}
- public static void Log(string message)
+ public static void Log(object message)
{
#if ML
- MelonLoader.MelonLogger.Log(message);
+ MelonLoader.MelonLogger.Log(message.ToString());
#else
- ExplorerBepInPlugin.Logging?.LogMessage(message);
+ ExplorerBepInPlugin.Logging?.LogMessage(message.ToString());
#endif
}
- public static void LogWarning(string message)
+ public static void LogWarning(object message)
{
#if ML
- MelonLoader.MelonLogger.LogWarning(message);
+ MelonLoader.MelonLogger.LogWarning(message.ToString());
#else
- ExplorerBepInPlugin.Logging?.LogWarning(message);
+ ExplorerBepInPlugin.Logging?.LogWarning(message.ToString());
#endif
}
- public static void LogError(string message)
+ public static void LogError(object message)
{
#if ML
- MelonLoader.MelonLogger.LogError(message);
+ MelonLoader.MelonLogger.LogError(message.ToString());
#else
- ExplorerBepInPlugin.Logging?.LogError(message);
+ ExplorerBepInPlugin.Logging?.LogError(message.ToString());
#endif
}
}
diff --git a/src/Helpers/ReflectionHelpers.cs b/src/Helpers/ReflectionHelpers.cs
index 8a507c4..74f0c4d 100644
--- a/src/Helpers/ReflectionHelpers.cs
+++ b/src/Helpers/ReflectionHelpers.cs
@@ -19,11 +19,11 @@ namespace Explorer
public static BF CommonFlags = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
#if CPP
- public static ILType GameObjectType => Il2CppType.Of();
- public static ILType TransformType => Il2CppType.Of();
- public static ILType ObjectType => Il2CppType.Of();
- public static ILType ComponentType => Il2CppType.Of();
- public static ILType BehaviourType => Il2CppType.Of();
+ public static ILType GameObjectType => Il2CppType.Of();
+ public static ILType TransformType => Il2CppType.Of();
+ public static ILType ObjectType => Il2CppType.Of();
+ public static ILType ComponentType => Il2CppType.Of();
+ public static ILType BehaviourType => Il2CppType.Of();
private static readonly MethodInfo tryCastMethodInfo = typeof(Il2CppObjectBase).GetMethod("TryCast");
private static readonly Dictionary cachedTryCastMethods = new Dictionary();
@@ -131,12 +131,12 @@ namespace Explorer
return obj.GetType();
}
- public static Type[] GetAllBaseTypes(object obj)
+ public static Type[] GetAllBaseTypes(object obj) => GetAllBaseTypes(GetActualType(obj));
+
+ public static Type[] GetAllBaseTypes(Type type)
{
var list = new List();
- var type = GetActualType(obj);
-
while (type != null)
{
list.Add(type);
diff --git a/src/Input/InputManager.cs b/src/Input/InputManager.cs
index 6885cc0..eb3dbf0 100644
--- a/src/Input/InputManager.cs
+++ b/src/Input/InputManager.cs
@@ -19,7 +19,7 @@ namespace Explorer
{
inputModule = new LegacyInput();
}
-
+
if (inputModule == null)
{
ExplorerCore.LogWarning("Could not find any Input module!");
diff --git a/src/Menu/MainMenu/Pages/Console/REPL.cs b/src/Menu/MainMenu/Pages/Console/REPL.cs
deleted file mode 100644
index 6fc97ce..0000000
--- a/src/Menu/MainMenu/Pages/Console/REPL.cs
+++ /dev/null
@@ -1,126 +0,0 @@
-using System;
-using Mono.CSharp;
-using UnityEngine;
-using Attribute = System.Attribute;
-using Object = UnityEngine.Object;
-
-namespace Explorer
-{
- public class REPL : InteractiveBase
- {
- static REPL()
- {
- var go = new GameObject("UnityREPL");
- GameObject.DontDestroyOnLoad(go);
- //go.transform.parent = HPExplorer.Instance.transform;
- MB = go.AddComponent();
- }
-
- [Documentation("MB - A dummy MonoBehaviour for accessing Unity.")]
- public static ReplHelper MB { get; }
-
- [Documentation("find() - find a UnityEngine.Object of type T.")]
- public static T find() where T : Object
- {
- return MB.Find();
- }
-
- [Documentation("findAll() - find all UnityEngine.Object of type T.")]
- public static T[] findAll() where T : Object
- {
- return MB.FindAll();
- }
-
- //[Documentation("runCoroutine(enumerator) - runs an IEnumerator as a Unity coroutine.")]
- //public static object runCoroutine(IEnumerator i)
- //{
- // return MB.RunCoroutine(i);
- //}
-
- //[Documentation("endCoroutine(co) - ends a Unity coroutine.")]
- //public static void endCoroutine(Coroutine c)
- //{
- // MB.EndCoroutine(c);
- //}
-
- ////[Documentation("type() - obtain type info about a type T. Provides some Reflection helpers.")]
- ////public static TypeHelper type()
- ////{
- //// return new TypeHelper(typeof(T));
- ////}
-
- ////[Documentation("type(obj) - obtain type info about object obj. Provides some Reflection helpers.")]
- ////public static TypeHelper type(object instance)
- ////{
- //// return new TypeHelper(instance);
- ////}
-
- //[Documentation("dir(obj) - lists all available methods and fiels of a given obj.")]
- //public static string dir(object instance)
- //{
- // return type(instance).info();
- //}
-
- //[Documentation("dir() - lists all available methods and fields of type T.")]
- //public static string dir()
- //{
- // return type().info();
- //}
-
- //[Documentation("findrefs(obj) - find references to the object in currently loaded components.")]
- //public static Component[] findrefs(object obj)
- //{
- // if (obj == null) throw new ArgumentNullException(nameof(obj));
-
- // var results = new List();
- // foreach (var component in Object.FindObjectsOfType())
- // {
- // var type = component.GetType();
-
- // var nameBlacklist = new[] { "parent", "parentInternal", "root", "transform", "gameObject" };
- // var typeBlacklist = new[] { typeof(bool) };
-
- // foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
- // .Where(x => x.CanRead && !nameBlacklist.Contains(x.Name) && !typeBlacklist.Contains(x.PropertyType)))
- // {
- // try
- // {
- // if (Equals(prop.GetValue(component, null), obj))
- // {
- // results.Add(component);
- // goto finish;
- // }
- // }
- // catch { }
- // }
- // foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
- // .Where(x => !nameBlacklist.Contains(x.Name) && !typeBlacklist.Contains(x.FieldType)))
- // {
- // try
- // {
- // if (Equals(field.GetValue(component), obj))
- // {
- // results.Add(component);
- // goto finish;
- // }
- // }
- // catch { }
- // }
- // finish:;
- // }
-
- // return results.ToArray();
- //}
-
- [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
- private class DocumentationAttribute : Attribute
- {
- public DocumentationAttribute(string doc)
- {
- Docs = doc;
- }
-
- public string Docs { get; }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Menu/MainMenu/Pages/Console/REPLHelper.cs b/src/Menu/MainMenu/Pages/Console/REPLHelper.cs
deleted file mode 100644
index eb95555..0000000
--- a/src/Menu/MainMenu/Pages/Console/REPLHelper.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using UnityEngine;
-using Object = UnityEngine.Object;
-
-namespace Explorer
-{
- public class ReplHelper : MonoBehaviour
- {
-#if CPP
- public ReplHelper(IntPtr intPtr) : base(intPtr) { }
-#endif
-
- public T Find() where T : Object
- {
- return FindObjectOfType();
- }
-
- public T[] FindAll() where T : Object
- {
- return FindObjectsOfType();
- }
-
- //public object RunCoroutine(IEnumerator enumerator)
- //{
- // return MelonCoroutines.Start(enumerator);
- //}
-
- //public void EndCoroutine(Coroutine c)
- //{
- // StopCoroutine(c);
- //}
- }
-}
\ No newline at end of file
diff --git a/src/Menu/MainMenu/Pages/ConsolePage.cs b/src/Menu/MainMenu/Pages/ConsolePage.cs
deleted file mode 100644
index db9d4cd..0000000
--- a/src/Menu/MainMenu/Pages/ConsolePage.cs
+++ /dev/null
@@ -1,253 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Text;
-using Mono.CSharp;
-using UnityEngine;
-
-namespace Explorer
-{
- public class ConsolePage : WindowPage
- {
- public override string Name { get => "C# Console"; }
-
- private ScriptEvaluator _evaluator;
- private readonly StringBuilder _sb = new StringBuilder();
-
- private Vector2 inputAreaScroll;
-
- private string MethodInput = "";
- private string UsingInput = "";
-
- public static List UsingDirectives;
-
- private static readonly string[] m_defaultUsing = new string[]
- {
- "System",
- "UnityEngine",
- "System.Linq",
- "System.Collections",
- "System.Collections.Generic",
- "System.Reflection",
-#if ML
- "MelonLoader"
-#endif
- };
-
- public override void Init()
- {
-#if CPP
- UnhollowerRuntimeLib.ClassInjector.RegisterTypeInIl2Cpp();
-#endif
- try
- {
- MethodInput = @"// This is a basic C# console.
-// Some common using directives are added by default, you can add more below.
-// If you want to return some output, Debug.Log() or MelonLogger.Log() it.
-
-"
-#if ML
-+ @"MelonLogger.Log(""hello world"");";
-#else
-+ @"Debug.Log(""hello world"");";
-#endif
- ;
-
- ResetConsole();
-
- foreach (var use in m_defaultUsing)
- {
- AddUsing(use);
- }
- }
- catch (Exception e)
- {
- ExplorerCore.Log($"Error setting up console!\r\nMessage: {e.Message}");
- MainMenu.SetCurrentPage(0);
- MainMenu.Pages.Remove(this);
- }
- }
-
- public void ResetConsole()
- {
- if (_evaluator != null)
- {
- _evaluator.Dispose();
- }
-
- _evaluator = new ScriptEvaluator(new StringWriter(_sb)) { InteractiveBaseClass = typeof(REPL) };
-
- UsingDirectives = new List();
- }
-
- public string AsmToUsing(string asm, bool richtext = false)
- {
- if (richtext)
- {
- return $"using {asm};";
- }
- return $"using {asm};";
- }
-
- public void AddUsing(string asm)
- {
- if (!UsingDirectives.Contains(asm))
- {
- UsingDirectives.Add(asm);
- Evaluate(AsmToUsing(asm), true);
- }
- }
-
- public object Evaluate(string str, bool suppressWarning = false)
- {
- object ret = VoidType.Value;
-
- _evaluator.Compile(str, out var compiled);
-
- try
- {
- if (compiled == null)
- {
- throw new Exception("Mono.Csharp Service was unable to compile the code provided.");
- }
-
- compiled.Invoke(ref ret);
- }
- catch (Exception e)
- {
- if (!suppressWarning)
- {
- ExplorerCore.LogWarning(e.GetType() + ", " + e.Message);
- }
- }
-
- return ret;
- }
-
-
- public override void DrawWindow()
- {
- GUILayout.Label("C# Console ", new GUILayoutOption[0]);
-
- GUI.skin.label.alignment = TextAnchor.UpperLeft;
-
- GUILayout.Label("Enter code here as though it is a method body:", new GUILayoutOption[0]);
-
- inputAreaScroll = GUIUnstrip.BeginScrollView(inputAreaScroll, new GUILayoutOption[] { GUILayout.Height(250) });
-
- MethodInput = GUIUnstrip.TextArea(MethodInput, new GUILayoutOption[] { GUILayout.ExpandHeight(true) });
-
- GUIUnstrip.EndScrollView();
-
- if (GUILayout.Button("Execute ", new GUILayoutOption[0]))
- {
- try
- {
- MethodInput = MethodInput.Trim();
-
- if (!string.IsNullOrEmpty(MethodInput))
- {
- var result = Evaluate(MethodInput);
-
- if (result != null && !Equals(result, VoidType.Value))
- {
- ExplorerCore.Log("[Console Output]\r\n" + result.ToString());
- }
- }
- }
- catch (Exception e)
- {
- ExplorerCore.LogError("Exception compiling!\r\nMessage: " + e.Message + "\r\nStack: " + e.StackTrace);
- }
- }
-
- GUILayout.Label("Using directives: ", new GUILayoutOption[0]);
-
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUILayout.Label("Add namespace:", new GUILayoutOption[] { GUILayout.Width(105) });
- UsingInput = GUIUnstrip.TextField(UsingInput, new GUILayoutOption[] { GUILayout.Width(150) });
- if (GUILayout.Button("Add ", new GUILayoutOption[] { GUILayout.Width(120) }))
- {
- AddUsing(UsingInput);
- }
- if (GUILayout.Button("Clear All ", new GUILayoutOption[] { GUILayout.Width(120) }))
- {
- ResetConsole();
- }
- GUILayout.EndHorizontal();
-
- foreach (var asm in UsingDirectives)
- {
- GUILayout.Label(AsmToUsing(asm, true), new GUILayoutOption[0]);
- }
- }
-
- public override void Update() { }
-
- private class VoidType
- {
- public static readonly VoidType Value = new VoidType();
- private VoidType() { }
- }
-
- }
-
- internal class ScriptEvaluator : Evaluator, IDisposable
- {
- private static readonly HashSet StdLib =
- new HashSet(StringComparer.InvariantCultureIgnoreCase) { "mscorlib", "System.Core", "System", "System.Xml" };
-
- private readonly TextWriter _logger;
-
- public ScriptEvaluator(TextWriter logger) : base(BuildContext(logger))
- {
- _logger = logger;
-
- ImportAppdomainAssemblies(ReferenceAssembly);
- AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
- }
-
- public void Dispose()
- {
- AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;
- _logger.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)
- {
- var reporter = 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, reporter);
- }
-
- private static void ImportAppdomainAssemblies(Action import)
- {
- foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
- {
- string name = assembly.GetName().Name;
- if (StdLib.Contains(name))
- continue;
- import(assembly);
- }
- }
- }
-}
diff --git a/src/Menu/MainMenu/Pages/OptionsPage.cs b/src/Menu/MainMenu/Pages/OptionsPage.cs
deleted file mode 100644
index 50291dc..0000000
--- a/src/Menu/MainMenu/Pages/OptionsPage.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Explorer.Tests;
-using UnityEngine;
-
-namespace Explorer
-{
- public class OptionsPage : WindowPage
- {
- public override string Name => "Options";
-
- public string toggleKeyInputString = "";
- public Vector2 defaultSizeInputVector;
- public int defaultPageLimit;
-
- private CacheObjectBase toggleKeyInput;
- private CacheObjectBase defaultSizeInput;
- private CacheObjectBase defaultPageLimitInput;
-
- public override void Init()
- {
- toggleKeyInputString = ModConfig.Instance.Main_Menu_Toggle.ToString();
- toggleKeyInput = CacheFactory.GetTypeAndCacheObject(typeof(OptionsPage).GetField("toggleKeyInputString"), this);
-
- defaultSizeInputVector = ModConfig.Instance.Default_Window_Size;
- defaultSizeInput = CacheFactory.GetTypeAndCacheObject(typeof(OptionsPage).GetField("defaultSizeInputVector"), this);
-
- defaultPageLimit = ModConfig.Instance.Default_Page_Limit;
- defaultPageLimitInput = CacheFactory.GetTypeAndCacheObject(typeof(OptionsPage).GetField("defaultPageLimit"), this);
- }
-
- public override void Update() { }
-
- public override void DrawWindow()
- {
- GUI.skin.label.alignment = TextAnchor.MiddleCenter;
- GUILayout.Label("Settings ", new GUILayoutOption[0]);
- GUI.skin.label.alignment = TextAnchor.MiddleLeft;
-
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[0]);
-
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUILayout.Label($"Menu Toggle Key:", new GUILayoutOption[] { GUILayout.Width(215f) });
- toggleKeyInput.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
- GUILayout.EndHorizontal();
-
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUILayout.Label($"Default Window Size:", new GUILayoutOption[] { GUILayout.Width(215f) });
- defaultSizeInput.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
- GUILayout.EndHorizontal();
-
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUILayout.Label($"Default Items per Page:", new GUILayoutOption[] { GUILayout.Width(215f) });
- defaultPageLimitInput.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
- GUILayout.EndHorizontal();
-
- if (GUILayout.Button("Apply and Save ", new GUILayoutOption[0]))
- {
- ApplyAndSave();
- }
-
- GUILayout.EndVertical();
-
- //GUIUnstrip.Space(10f);
-
- //GUI.skin.label.alignment = TextAnchor.MiddleCenter;
- //GUILayout.Label("Other ", new GUILayoutOption[0]);
- //GUI.skin.label.alignment = TextAnchor.MiddleLeft;
-
- //GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[0]);
-
- //if (GUILayout.Button("Inspect Test Class", new GUILayoutOption[0]))
- //{
- // WindowManager.InspectObject(TestClass.Instance, out bool _);
- //}
-
- //GUILayout.EndVertical();
- }
-
- private void ApplyAndSave()
- {
- if (Enum.Parse(typeof(KeyCode), toggleKeyInputString) is KeyCode key)
- {
- ModConfig.Instance.Main_Menu_Toggle = key;
- }
- else
- {
- ExplorerCore.LogWarning($"Could not parse '{toggleKeyInputString}' to KeyCode!");
- }
-
- ModConfig.Instance.Default_Window_Size = defaultSizeInputVector;
- ModConfig.Instance.Default_Page_Limit = defaultPageLimit;
-
- ModConfig.SaveSettings();
- }
- }
-}
diff --git a/src/Tests/TestClass.cs b/src/Tests/TestClass.cs
index 512cec2..ff57f2b 100644
--- a/src/Tests/TestClass.cs
+++ b/src/Tests/TestClass.cs
@@ -3,46 +3,35 @@ using System.Collections.Generic;
using System;
using UnityEngine;
using System.Reflection;
-using System.Collections.Specialized;
-
-// used to test multiple generic constraints
-public class TestGeneric : IComparable
-{
- public TestGeneric() { }
-
- public int CompareTo(string other) => throw new NotImplementedException();
-}
-
-[Flags]
-public enum TestFlags
-{
- Red,
- Green,
- Blue
-}
-
-// test non-flags weird enum
-public enum WeirdEnum
-{
- First = 1,
- Second,
- Third = 2,
- Fourth,
- Fifth
-}
namespace Explorer.Tests
{
+ public static class StaticTestClass
+ {
+ public static int StaticProperty => 5;
+
+ public static int StaticField = 69;
+
+ public static List StaticList = new List
+ {
+ "one",
+ "two",
+ "three",
+ };
+
+ public static void StaticMethod() { }
+
+ }
+
public class TestClass
{
- public static TestFlags testFlags = TestFlags.Blue | TestFlags.Green;
- public static WeirdEnum testWeird = WeirdEnum.First;
-
- public static int testBitmask;
-
public static TestClass Instance => m_instance ?? (m_instance = new TestClass());
private static TestClass m_instance;
+ public static int StaticProperty => 5;
+ public static int StaticField = 5;
+ public int NonStaticField;
+
#if CPP
public static Il2CppSystem.Collections.Generic.HashSet ILHashSetTest;
#endif
@@ -55,17 +44,6 @@ namespace Explorer.Tests
ILHashSetTest.Add("2");
ILHashSetTest.Add("3");
#endif
-
- testBitmask = 1 | 2;
- }
-
- public static int StaticProperty => 5;
- public static int StaticField = 5;
- public int NonStaticField;
-
- public static string TestGeneric(string arg0) where C : Component where T : TestGeneric, IComparable
- {
- return $"C: '{typeof(C).FullName}', T: '{typeof(T).FullName}', arg0: '{arg0}'";
}
public static string TestRefInOutGeneric(ref string arg0, in int arg1, out string arg2)
@@ -75,12 +53,6 @@ namespace Explorer.Tests
return $"T: '{typeof(T).FullName}', ref arg0: '{arg0}', in arg1: '{arg1}', out arg2: '{arg2}'";
}
- //// this type of generic is not supported, due to requiring a non-primitive argument.
- //public static T TestDifferentGeneric(T obj) where T : Component
- //{
- // return obj;
- //}
-
// test a non-generic dictionary
public Hashtable TestNonGenericDict()
@@ -93,18 +65,6 @@ namespace Explorer.Tests
};
}
- // IL2CPP HASHTABLE NOT SUPPORTED! Cannot assign Il2CppSystem.Object from primitive struct / string.
- // Technically they are "supported" but if they contain System types they will not work.
-
- //public Il2CppSystem.Collections.Hashtable TestIl2CppNonGenericDict()
- //{
- // var table = new Il2CppSystem.Collections.Hashtable();
- // table.Add("One", 1);
- // table.Add("One", 2);
- // table.Add("One", 3);
- // return table;
- //}
-
// test HashSets
public static HashSet HashSetTest = new HashSet
diff --git a/src/Menu/CursorControl.cs b/src/UI/ForceUnlockCursor.cs
similarity index 81%
rename from src/Menu/CursorControl.cs
rename to src/UI/ForceUnlockCursor.cs
index dc1bdff..a6ec1bf 100644
--- a/src/Menu/CursorControl.cs
+++ b/src/UI/ForceUnlockCursor.cs
@@ -6,21 +6,22 @@ using Harmony;
using HarmonyLib;
#endif
-namespace Explorer
+namespace Explorer.UI
{
- public class CursorControl
+ public class ForceUnlockCursor
{
- public static bool ForceUnlockMouse
+ public static bool Unlock
{
get => m_forceUnlock;
set => SetForceUnlock(value);
}
private static bool m_forceUnlock;
+
private static CursorLockMode m_lastLockMode;
private static bool m_lastVisibleState;
private static bool m_currentlySettingCursor = false;
- public static bool ShouldForceMouse => ExplorerCore.ShowMenu && ForceUnlockMouse;
+ public static bool ShouldForceMouse => ExplorerCore.ShowMenu && Unlock;
private static Type CursorType => m_cursorType ?? (m_cursorType = ReflectionHelpers.GetTypeByName("UnityEngine.Cursor"));
private static Type m_cursorType;
@@ -49,29 +50,24 @@ namespace Explorer
m_lastVisibleState = Cursor.visible;
// Setup Harmony Patches
- TryPatch("lockState", new HarmonyMethod(typeof(CursorControl).GetMethod(nameof(Prefix_set_lockState))), true);
- TryPatch("lockState", new HarmonyMethod(typeof(CursorControl).GetMethod(nameof(Postfix_get_lockState))), false);
+ TryPatch("lockState", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_lockState))), true);
+ TryPatch("lockState", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Postfix_get_lockState))), false);
- TryPatch("visible", new HarmonyMethod(typeof(CursorControl).GetMethod(nameof(Prefix_set_visible))), true);
- TryPatch("visible", new HarmonyMethod(typeof(CursorControl).GetMethod(nameof(Postfix_get_visible))), false);
+ TryPatch("visible", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_visible))), true);
+ TryPatch("visible", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Postfix_get_visible))), false);
}
catch (Exception e)
{
ExplorerCore.Log($"Exception on CursorControl.Init! {e.GetType()}, {e.Message}");
}
- // Enable ShowMenu and ForceUnlockMouse
- // (set m_showMenu directly to not call UpdateCursorState twice)
- ExplorerCore.m_showMenu = true;
- ForceUnlockMouse = true;
+ Unlock = true;
}
private static void TryPatch(string property, HarmonyMethod patch, bool setter)
{
try
{
- // var harmony = ExplorerCore.Instance.harmonyInstance;
-
var harmony =
#if ML
ExplorerMelonMod.Instance.harmonyInstance;
@@ -85,12 +81,12 @@ namespace Explorer
if (setter)
{
// setter is prefix
- harmony.Patch(prop.GetSetMethod(), patch);
+ harmony.Patch(prop.GetSetMethod(), prefix: patch);
}
else
{
// getter is postfix
- harmony.Patch(prop.GetGetMethod(), null, patch);
+ harmony.Patch(prop.GetGetMethod(), postfix: patch);
}
}
catch (Exception e)
@@ -110,7 +106,7 @@ namespace Explorer
// Check Force-Unlock input
if (InputManager.GetKeyDown(KeyCode.LeftAlt))
{
- ForceUnlockMouse = !ForceUnlockMouse;
+ Unlock = !Unlock;
}
}
diff --git a/src/Menu/Windows/GameObjectWindow.cs b/src/UI/Inspectors/GameObjectInspector.cs
similarity index 89%
rename from src/Menu/Windows/GameObjectWindow.cs
rename to src/UI/Inspectors/GameObjectInspector.cs
index e10d79e..cb70a34 100644
--- a/src/Menu/Windows/GameObjectWindow.cs
+++ b/src/UI/Inspectors/GameObjectInspector.cs
@@ -1,18 +1,19 @@
using System;
using System.Collections.Generic;
using UnityEngine;
-
+using Explorer.UI.Shared;
+using Explorer.UI.Main;
#if CPP
using UnhollowerRuntimeLib;
#endif
-namespace Explorer
+namespace Explorer.UI.Inspectors
{
- public class GameObjectWindow : UIWindow
+ public class GameObjectInspector : WindowBase
{
public override string Title => WindowManager.TabView
- ? $"[G] {TargetGO.name}"
- : $"GameObject Inspector ({TargetGO.name})";
+ ? $"[G] {TargetGO.name}"
+ : $"GameObject Inspector ({TargetGO.name})";
public GameObject TargetGO;
@@ -49,7 +50,7 @@ namespace Explorer
public bool GetObjectAsGameObject()
{
- var targetType = Target.GetType();
+ var targetType = Target?.GetType();
if (targetType == typeof(GameObject))
{
@@ -75,8 +76,8 @@ namespace Explorer
}
m_name = TargetGO.name;
- m_scene = string.IsNullOrEmpty(TargetGO.scene.name)
- ? "None (Asset/Resource)"
+ m_scene = string.IsNullOrEmpty(TargetGO.scene.name)
+ ? "None (Asset/Resource)"
: TargetGO.scene.name;
CacheTransformValues();
@@ -109,19 +110,11 @@ namespace Explorer
DestroyWindow();
return;
}
- if (Target is UnityEngine.Object uObj)
- {
- if (!uObj)
- {
- ExplorerCore.Log("Target was destroyed!");
- DestroyWindow();
- return;
- }
- }
-
if (!TargetGO && !GetObjectAsGameObject())
{
- throw new Exception("Object is null!");
+ ExplorerCore.Log("Target was destroyed!");
+ DestroyWindow();
+ return;
}
if (m_freeze)
@@ -176,7 +169,7 @@ namespace Explorer
private void InspectGameObject(Transform obj)
{
var window = WindowManager.InspectObject(obj, out bool created);
-
+
if (created)
{
window.m_rect = new Rect(this.m_rect.x, this.m_rect.y, this.m_rect.width, this.m_rect.height);
@@ -189,7 +182,7 @@ namespace Explorer
#else
private void ReflectObject(object obj)
#endif
- {
+ {
var window = WindowManager.InspectObject(obj, out bool created, true);
if (created)
@@ -223,7 +216,7 @@ namespace Explorer
scroll = GUIUnstrip.BeginScrollView(scroll);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Scene: " + (m_scene == "" ? "n/a" : m_scene) + " ", new GUILayoutOption[0]);
if (m_scene == UnityHelpers.ActiveSceneName)
{
@@ -239,7 +232,7 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Path:", new GUILayoutOption[] { GUILayout.Width(50) });
string pathlabel = TargetGO.transform.GetGameObjectPath();
if (TargetGO.transform.parent != null)
@@ -252,19 +245,19 @@ namespace Explorer
GUIUnstrip.TextArea(pathlabel, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Name:", new GUILayoutOption[] { GUILayout.Width(50) });
GUIUnstrip.TextArea(m_name, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
// --- Horizontal Columns section ---
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
- GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(rect.width / 2 - 17) });
+ GUIUnstrip.BeginVertical(new GUILayoutOption[] { GUILayout.Width(rect.width / 2 - 17) });
TransformList(rect);
GUILayout.EndVertical();
- GUILayout.BeginVertical(new GUILayoutOption[] { GUILayout.Width(rect.width / 2 - 17) });
+ GUIUnstrip.BeginVertical(new GUILayoutOption[] { GUILayout.Width(rect.width / 2 - 17) });
ComponentList(rect);
GUILayout.EndVertical();
@@ -289,12 +282,12 @@ namespace Explorer
private void TransformList(Rect m_rect)
{
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
m_transformScroll = GUIUnstrip.BeginScrollView(m_transformScroll);
GUILayout.Label("Children ", new GUILayoutOption[0]);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
ChildPages.DrawLimitInputArea();
if (ChildPages.ItemCount > ChildPages.ItemsPerPage)
@@ -302,7 +295,7 @@ namespace Explorer
ChildPages.CurrentPageLabel();
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
{
@@ -329,7 +322,7 @@ namespace Explorer
continue;
}
- UIHelpers.GOButton(obj.gameObject, InspectGameObject, false, m_rect.width / 2 - 80);
+ Buttons.GameObjectButton(obj.gameObject, InspectGameObject, false, m_rect.width / 2 - 80);
}
}
else
@@ -343,11 +336,11 @@ namespace Explorer
private void ComponentList(Rect m_rect)
{
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
m_compScroll = GUIUnstrip.BeginScrollView(m_compScroll);
GUILayout.Label("Components ", new GUILayoutOption[0]);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
CompPages.DrawLimitInputArea();
if (CompPages.ItemCount > CompPages.ItemsPerPage)
@@ -355,7 +348,7 @@ namespace Explorer
CompPages.CurrentPageLabel();
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
{
@@ -368,7 +361,7 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
var width = m_rect.width / 2 - 135f;
m_addComponentInput = GUIUnstrip.TextField(m_addComponentInput, new GUILayoutOption[] { GUILayout.Width(width) });
if (GUILayout.Button("Add Comp", new GUILayoutOption[0]))
@@ -417,7 +410,7 @@ namespace Explorer
#else
component.GetType();
#endif
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
if (ReflectionHelpers.BehaviourType.IsAssignableFrom(type))
{
#if CPP
@@ -484,7 +477,7 @@ namespace Explorer
{
if (m_hideControls)
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("GameObject Controls ", new GUILayoutOption[] { GUILayout.Width(200) });
if (GUILayout.Button("^ Show ^", new GUILayoutOption[] { GUILayout.Width(75) }))
{
@@ -495,9 +488,9 @@ namespace Explorer
return;
}
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[] { GUILayout.Width(520) });
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[] { GUILayout.Width(520) });
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("GameObject Controls ", new GUILayoutOption[] { GUILayout.Width(200) });
if (GUILayout.Button("v Hide v", new GUILayoutOption[] { GUILayout.Width(75) }))
{
@@ -505,13 +498,13 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
bool m_active = TargetGO.activeSelf;
m_active = GUILayout.Toggle(m_active, (m_active ? "Enabled " : "Disabled") + " ",
new GUILayoutOption[] { GUILayout.Width(80) });
if (TargetGO.activeSelf != m_active) { TargetGO.SetActive(m_active); }
- UIHelpers.InstantiateButton(TargetGO, 100);
+ Buttons.InstantiateButton(TargetGO, 100);
if (GUILayout.Button("Set DontDestroyOnLoad", new GUILayoutOption[] { GUILayout.Width(170) }))
{
@@ -530,7 +523,7 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
m_setParentInput = GUIUnstrip.TextField(m_setParentInput, new GUILayoutOption[0]);
if (GUILayout.Button("Set Parent", new GUILayoutOption[] { GUILayout.Width(80) }))
@@ -551,13 +544,13 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
- m_cachedInput[0] = TranslateControl(TranslateType.Position, ref m_translateAmount, false);
- m_cachedInput[1] = TranslateControl(TranslateType.Rotation, ref m_rotateAmount, true);
- m_cachedInput[2] = TranslateControl(TranslateType.Scale, ref m_scaleAmount, false);
+ m_cachedInput[0] = TranslateControl(TranslateType.Position, ref m_translateAmount, false);
+ m_cachedInput[1] = TranslateControl(TranslateType.Rotation, ref m_rotateAmount, true);
+ m_cachedInput[2] = TranslateControl(TranslateType.Scale, ref m_scaleAmount, false);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
if (GUILayout.Button("Apply to Transform ", new GUILayoutOption[0]) || m_autoApplyTransform)
{
if (m_localContext)
@@ -583,7 +576,7 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
BoolToggle(ref m_autoApplyTransform, "Auto-apply to Transform?");
BoolToggle(ref m_autoUpdateTransform, "Auto-update from transform?");
GUILayout.EndHorizontal();
@@ -645,8 +638,8 @@ namespace Explorer
private Vector3 TranslateControl(TranslateType mode, ref float amount, bool multByTime)
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUILayout.Label($"{(m_localContext ? "Local " : "")}{mode} :",
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label($"{(m_localContext ? "Local " : "")}{mode} :",
new GUILayoutOption[] { GUILayout.Width(m_localContext ? 110 : 65) });
var transform = TargetGO.transform;
@@ -668,7 +661,7 @@ namespace Explorer
Vector3 input = m_cachedInput[(int)mode];
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.MiddleRight;
GUILayout.Label("X: ", new GUILayoutOption[] { GUILayout.Width(20) });
@@ -678,7 +671,7 @@ namespace Explorer
PlusMinusFloat(ref input.y, amount, multByTime);
GUILayout.Label("Z: ", new GUILayoutOption[] { GUILayout.Width(20) });
- PlusMinusFloat(ref input.z, amount, multByTime);
+ PlusMinusFloat(ref input.z, amount, multByTime);
GUILayout.Label("+/-:", new GUILayoutOption[] { GUILayout.Width(30) });
var amountInput = amount.ToString("F3");
diff --git a/src/Menu/InspectUnderMouse.cs b/src/UI/Inspectors/InspectUnderMouse.cs
similarity index 96%
rename from src/Menu/InspectUnderMouse.cs
rename to src/UI/Inspectors/InspectUnderMouse.cs
index 85d390e..96fc08d 100644
--- a/src/Menu/InspectUnderMouse.cs
+++ b/src/UI/Inspectors/InspectUnderMouse.cs
@@ -1,12 +1,12 @@
using UnityEngine;
-namespace Explorer
+namespace Explorer.UI.Inspectors
{
public class InspectUnderMouse
{
public static bool EnableInspect { get; set; } = false;
- private static string m_objUnderMouseName = "";
+ private static string m_objUnderMouseName = "";
public static void Update()
{
diff --git a/src/UI/Inspectors/Reflection/InstanceInspector.cs b/src/UI/Inspectors/Reflection/InstanceInspector.cs
new file mode 100644
index 0000000..172ad01
--- /dev/null
+++ b/src/UI/Inspectors/Reflection/InstanceInspector.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+using Explorer.UI;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
+#if CPP
+using UnhollowerBaseLib;
+#endif
+
+namespace Explorer.UI.Inspectors
+{
+ public class InstanceInspector : ReflectionInspector
+ {
+ public override bool IsStaticInspector => false;
+
+ // some extra cast-caching
+ public UnityEngine.Object m_uObj;
+ private Component m_component;
+
+ public override void Init()
+ {
+ // cache the extra cast-caching
+#if CPP
+ if (!IsStaticInspector && Target is Il2CppSystem.Object ilObject)
+ {
+ var unityObj = ilObject.TryCast();
+ if (unityObj)
+ {
+ m_uObj = unityObj;
+
+ var component = ilObject.TryCast();
+ if (component)
+ {
+ m_component = component;
+ }
+ }
+ }
+#else
+ if (!IsStaticInspector)
+ {
+ m_uObj = Target as UnityEngine.Object;
+ m_component = Target as Component;
+ }
+#endif
+
+ base.Init();
+ }
+
+ public override void Update()
+ {
+ if (Target == null)
+ {
+ ExplorerCore.Log("Target is null!");
+ DestroyWindow();
+ return;
+ }
+ if (Target is UnityEngine.Object uObj)
+ {
+ if (!uObj)
+ {
+ ExplorerCore.Log("Target was destroyed!");
+ DestroyWindow();
+ return;
+ }
+ }
+
+ base.Update();
+ }
+
+ public void DrawInstanceControls(Rect rect)
+ {
+ if (m_uObj)
+ {
+ GUILayout.Label("Name: " + m_uObj.name, new GUILayoutOption[0]);
+ }
+ GUILayout.EndHorizontal();
+
+ if (m_uObj)
+ {
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label("Tools: ", new GUILayoutOption[] { GUILayout.Width(80) });
+ Buttons.InstantiateButton(m_uObj);
+ if (m_component && m_component.gameObject is GameObject obj)
+ {
+ GUI.skin.label.alignment = TextAnchor.MiddleRight;
+ GUILayout.Label("GameObject:", new GUILayoutOption[] { GUILayout.Width(135) });
+ var charWidth = obj.name.Length * 15;
+ var maxWidth = rect.width - 350;
+ var labelWidth = charWidth < maxWidth ? charWidth : maxWidth;
+ if (GUILayout.Button("" + obj.name + " ", new GUILayoutOption[] { GUILayout.Width(labelWidth) }))
+ {
+ WindowManager.InspectObject(obj, out bool _);
+ }
+ GUI.skin.label.alignment = TextAnchor.UpperLeft;
+ }
+ GUILayout.EndHorizontal();
+ }
+ }
+ }
+}
diff --git a/src/UI/Inspectors/Reflection/StaticInspector.cs b/src/UI/Inspectors/Reflection/StaticInspector.cs
new file mode 100644
index 0000000..c3cc84e
--- /dev/null
+++ b/src/UI/Inspectors/Reflection/StaticInspector.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Explorer.CacheObject;
+
+namespace Explorer.UI.Inspectors
+{
+ public class StaticInspector : ReflectionInspector
+ {
+ public override bool IsStaticInspector => true;
+
+ public override void Init()
+ {
+ base.Init();
+ }
+
+ public override bool ShouldProcessMember(CacheMember holder)
+ {
+ return base.ShouldProcessMember(holder);
+ }
+
+ public override void WindowFunction(int windowID)
+ {
+ base.WindowFunction(windowID);
+ }
+ }
+}
diff --git a/src/Menu/Windows/ReflectionWindow.cs b/src/UI/Inspectors/ReflectionInspector.cs
similarity index 55%
rename from src/Menu/Windows/ReflectionWindow.cs
rename to src/UI/Inspectors/ReflectionInspector.cs
index 8e45db9..2fcbfc7 100644
--- a/src/Menu/Windows/ReflectionWindow.cs
+++ b/src/UI/Inspectors/ReflectionInspector.cs
@@ -3,33 +3,43 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
+using Explorer.UI;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
+using Explorer.UI.Inspectors;
#if CPP
using UnhollowerBaseLib;
#endif
-namespace Explorer
+namespace Explorer.UI.Inspectors
{
- public class ReflectionWindow : UIWindow
+ public abstract class ReflectionInspector : WindowBase
{
public override string Title => WindowManager.TabView
- ? $"[R] {TargetType.Name}"
+ ? $"[R] {TargetType.Name}"
: $"Reflection Inspector ({TargetType.Name})";
+ public virtual bool IsStaticInspector { get; }
+
public Type TargetType;
- private CacheObjectBase[] m_allCachedMembers;
- private CacheObjectBase[] m_cachedMembersFiltered;
+ private CacheMember[] m_allCachedMembers;
+ private CacheMember[] m_cachedMembersFiltered;
public PageHelper Pages = new PageHelper();
private bool m_autoUpdate = false;
private string m_search = "";
- public MemberTypes m_filter = MemberTypes.Property;
+ public MemberTypes m_typeFilter = MemberTypes.Property;
private bool m_hideFailedReflection = false;
- // some extra cast-caching
- private UnityEngine.Object m_uObj;
- private Component m_component;
+ private MemberScopes m_scopeFilter;
+ private enum MemberScopes
+ {
+ Both,
+ Instance,
+ Static
+ }
private static readonly HashSet _typeAndMemberBlacklist = new HashSet
{
@@ -48,49 +58,23 @@ namespace Explorer
public override void Init()
{
- TargetType = ReflectionHelpers.GetActualType(Target);
-
- CacheMembers(ReflectionHelpers.GetAllBaseTypes(Target));
-
- // cache the extra cast-caching
-#if CPP
- if (Target is Il2CppSystem.Object ilObject)
+ if (!IsStaticInspector)
{
- var unityObj = ilObject.TryCast();
- if (unityObj)
- {
- m_uObj = unityObj;
-
- var component = ilObject.TryCast();
- if (component)
- {
- m_component = component;
- }
- }
+ TargetType = ReflectionHelpers.GetActualType(Target);
+ CacheMembers(ReflectionHelpers.GetAllBaseTypes(Target));
+ }
+ else
+ {
+ CacheMembers(new Type[] { TargetType });
}
-#else
- m_uObj = Target as UnityEngine.Object;
- m_component = Target as Component;
-#endif
}
public override void Update()
{
- if (Target == null)
+ if (m_allCachedMembers == null)
{
- ExplorerCore.Log("Target is null!");
- DestroyWindow();
return;
}
- if (Target is UnityEngine.Object uObj)
- {
- if (!uObj)
- {
- ExplorerCore.Log("Target was destroyed!");
- DestroyWindow();
- return;
- }
- }
m_cachedMembersFiltered = m_allCachedMembers.Where(x => ShouldProcessMember(x)).ToArray();
@@ -108,18 +92,28 @@ namespace Explorer
}
}
- private bool ShouldProcessMember(CacheObjectBase holder)
+ public virtual bool ShouldProcessMember(CacheMember holder)
{
// check MemberTypes filter
- if (m_filter != MemberTypes.All && m_filter != holder.MemInfo?.MemberType)
+ if (m_typeFilter != MemberTypes.All && m_typeFilter != holder.MemInfo?.MemberType)
return false;
+ // check scope filter
+ if (m_scopeFilter == MemberScopes.Instance)
+ {
+ return !holder.IsStatic;
+ }
+ else if (m_scopeFilter == MemberScopes.Static)
+ {
+ return holder.IsStatic;
+ }
+
// hide failed reflection
- if (!string.IsNullOrEmpty(holder.ReflectionException) && m_hideFailedReflection)
+ if (!string.IsNullOrEmpty(holder.ReflectionException) && m_hideFailedReflection)
return false;
// see if we should do name search
- if (m_search == "" || holder.MemInfo == null)
+ if (m_search == "" || holder.MemInfo == null)
return true;
// ok do name search
@@ -130,7 +124,7 @@ namespace Explorer
private void CacheMembers(Type[] types)
{
- var list = new List();
+ var list = new List();
var cachedSigs = new List();
foreach (var declaringType in types)
@@ -140,7 +134,7 @@ namespace Explorer
{
infos = declaringType.GetMembers(ReflectionHelpers.CommonFlags);
}
- catch
+ catch
{
ExplorerCore.Log($"Exception getting members for type: {declaringType.FullName}");
continue;
@@ -150,7 +144,7 @@ namespace Explorer
string exception = null;
#if CPP
- if (target is Il2CppSystem.Object ilObject)
+ if (!IsStaticInspector && target is Il2CppSystem.Object ilObject)
{
try
{
@@ -162,61 +156,79 @@ namespace Explorer
}
}
#endif
-
foreach (var member in infos)
{
- // make sure member type is Field, Method of Property (4 / 8 / 16)
- int m = (int)member.MemberType;
- if (m < 4 || m > 16)
- continue;
-
- // check blacklisted members
- var sig = $"{member.DeclaringType.Name}.{member.Name}";
- if (_typeAndMemberBlacklist.Any(it => it == sig))
- continue;
-
- if (_methodStartsWithBlacklist.Any(it => member.Name.StartsWith(it)))
- continue;
-
- if (member is MethodInfo mi)
- {
- AppendParams(mi.GetParameters());
- }
- else if (member is PropertyInfo pi)
- {
- AppendParams(pi.GetIndexParameters());
- }
-
- void AppendParams(ParameterInfo[] _args)
- {
- sig += " (";
- foreach (var param in _args)
- {
- sig += $"{param.ParameterType.Name} {param.Name}, ";
- }
- sig += ")";
- }
-
- if (cachedSigs.Contains(sig))
- {
- continue;
- }
-
- //ExplorerCore.Log($"Trying to cache member {sig}...");
-
try
{
- var cached = CacheFactory.GetTypeAndCacheObject(member, target);
- if (cached != null)
+ // make sure member type is Field, Method of Property (4 / 8 / 16)
+ int m = (int)member.MemberType;
+ if (m < 4 || m > 16)
+ continue;
+
+ var fi = member as FieldInfo;
+ var pi = member as PropertyInfo;
+ var mi = member as MethodInfo;
+
+ if (IsStaticInspector)
{
- cachedSigs.Add(sig);
- list.Add(cached);
- cached.ReflectionException = exception;
+ if (fi != null && !fi.IsStatic) continue;
+ else if (pi != null && !pi.GetAccessors()[0].IsStatic) continue;
+ else if (mi != null && !mi.IsStatic) continue;
}
- }
+
+ // check blacklisted members
+ var sig = $"{member.DeclaringType.Name}.{member.Name}";
+ if (_typeAndMemberBlacklist.Any(it => it == sig))
+ continue;
+
+ if (_methodStartsWithBlacklist.Any(it => member.Name.StartsWith(it)))
+ continue;
+
+ if (mi != null)
+ {
+ AppendParams(mi.GetParameters());
+ }
+ else if (pi != null)
+ {
+ AppendParams(pi.GetIndexParameters());
+ }
+
+ void AppendParams(ParameterInfo[] _args)
+ {
+ sig += " (";
+ foreach (var param in _args)
+ {
+ sig += $"{param.ParameterType.Name} {param.Name}, ";
+ }
+ sig += ")";
+ }
+
+ if (cachedSigs.Contains(sig))
+ {
+ continue;
+ }
+
+ //ExplorerCore.Log($"Trying to cache member {sig}...");
+
+ try
+ {
+ var cached = CacheFactory.GetCacheObject(member, target);
+ if (cached != null)
+ {
+ cachedSigs.Add(sig);
+ list.Add(cached);
+ cached.ReflectionException = exception;
+ }
+ }
+ catch (Exception e)
+ {
+ ExplorerCore.LogWarning($"Exception caching member {sig}!");
+ ExplorerCore.Log(e.ToString());
+ }
+ }
catch (Exception e)
{
- ExplorerCore.LogWarning($"Exception caching member {sig}!");
+ ExplorerCore.LogWarning($"Exception caching member {member.DeclaringType.FullName}.{member.Name}!");
ExplorerCore.Log(e.ToString());
}
}
@@ -241,51 +253,49 @@ namespace Explorer
GUIUnstrip.BeginArea(new Rect(5, 25, rect.width - 10, rect.height - 35), GUI.skin.box);
}
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUILayout.Label("Type: " + TargetType.FullName + " ", new GUILayoutOption[] { GUILayout.Width(245f) });
- if (m_uObj)
- {
- GUILayout.Label("Name: " + m_uObj.name, new GUILayoutOption[0]);
- }
- GUILayout.EndHorizontal();
+ var asInstance = this as InstanceInspector;
- if (m_uObj)
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ var labelWidth = (asInstance != null && asInstance.m_uObj)
+ ? new GUILayoutOption[] { GUILayout.Width(245f) }
+ : new GUILayoutOption[0];
+ GUILayout.Label("Type: " + TargetType.FullName + " ", labelWidth);
+
+ if (asInstance != null)
+ {
+ asInstance.DrawInstanceControls(rect);
+ }
+ else
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUILayout.Label("Tools: ", new GUILayoutOption[] { GUILayout.Width(80) });
- UIHelpers.InstantiateButton(m_uObj);
- if (m_component && m_component.gameObject is GameObject obj)
- {
- GUI.skin.label.alignment = TextAnchor.MiddleRight;
- GUILayout.Label("GameObject:", new GUILayoutOption[] { GUILayout.Width(135) });
- var charWidth = obj.name.Length * 15;
- var maxWidth = rect.width - 350;
- var labelWidth = charWidth < maxWidth ? charWidth : maxWidth;
- if (GUILayout.Button("" + obj.name + " ", new GUILayoutOption[] { GUILayout.Width(labelWidth) }))
- {
- WindowManager.InspectObject(obj, out bool _);
- }
- GUI.skin.label.alignment = TextAnchor.UpperLeft;
- }
GUILayout.EndHorizontal();
}
UIStyles.HorizontalLine(Color.grey);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Search: ", new GUILayoutOption[] { GUILayout.Width(75) });
- m_search = GUIUnstrip.TextField(m_search, new GUILayoutOption[0]);
+ m_search = GUIUnstrip.TextField(m_search, new GUILayoutOption[0]);
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Filter: ", new GUILayoutOption[] { GUILayout.Width(75) });
- FilterToggle(MemberTypes.All, "All");
- FilterToggle(MemberTypes.Property, "Properties");
- FilterToggle(MemberTypes.Field, "Fields");
- FilterToggle(MemberTypes.Method, "Methods");
+ FilterTypeToggle(MemberTypes.All, "All");
+ FilterTypeToggle(MemberTypes.Property, "Properties");
+ FilterTypeToggle(MemberTypes.Field, "Fields");
+ FilterTypeToggle(MemberTypes.Method, "Methods");
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ if (this is InstanceInspector)
+ {
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label("Scope: ", new GUILayoutOption[] { GUILayout.Width(75) });
+ FilterScopeToggle(MemberScopes.Both, "Both");
+ FilterScopeToggle(MemberScopes.Instance, "Instance");
+ FilterScopeToggle(MemberScopes.Static, "Static");
+ GUILayout.EndHorizontal();
+ }
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Values: ", new GUILayoutOption[] { GUILayout.Width(75) });
if (GUILayout.Button("Update", new GUILayoutOption[] { GUILayout.Width(100) }))
{
@@ -303,7 +313,7 @@ namespace Explorer
Pages.ItemCount = m_cachedMembersFiltered.Length;
// prev/next page buttons
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
Pages.DrawLimitInputArea();
@@ -331,7 +341,7 @@ namespace Explorer
UIStyles.HorizontalLine(Color.grey);
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
var members = this.m_cachedMembersFiltered;
int start = Pages.CalculateOffsetIndex();
@@ -340,12 +350,12 @@ namespace Explorer
{
var holder = members[j];
- GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
- try
- {
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
+ try
+ {
holder.Draw(rect, 180f);
- }
- catch
+ }
+ catch
{
GUILayout.EndHorizontal();
continue;
@@ -379,9 +389,9 @@ namespace Explorer
}
}
- private void FilterToggle(MemberTypes mode, string label)
+ private void FilterTypeToggle(MemberTypes mode, string label)
{
- if (m_filter == mode)
+ if (m_typeFilter == mode)
{
GUI.color = Color.green;
}
@@ -391,7 +401,26 @@ namespace Explorer
}
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
{
- m_filter = mode;
+ m_typeFilter = mode;
+ Pages.PageOffset = 0;
+ scroll = Vector2.zero;
+ }
+ GUI.color = Color.white;
+ }
+
+ private void FilterScopeToggle(MemberScopes mode, string label)
+ {
+ if (m_scopeFilter == mode)
+ {
+ GUI.color = Color.green;
+ }
+ else
+ {
+ GUI.color = Color.white;
+ }
+ if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
+ {
+ m_scopeFilter = mode;
Pages.PageOffset = 0;
scroll = Vector2.zero;
}
diff --git a/src/UI/InteractiveValue/InteractiveValue.cs b/src/UI/InteractiveValue/InteractiveValue.cs
new file mode 100644
index 0000000..ad9e2be
--- /dev/null
+++ b/src/UI/InteractiveValue/InteractiveValue.cs
@@ -0,0 +1,232 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
+
+namespace Explorer.UI
+{
+ public class InteractiveValue
+ {
+ public const float MAX_LABEL_WIDTH = 400f;
+ public const string EVALUATE_LABEL = "Evaluate ";
+
+ public CacheObjectBase OwnerCacheObject;
+
+ public object Value { get; set; }
+ public Type ValueType;
+
+ public string ButtonLabel => m_btnLabel ?? GetButtonLabel();
+ private string m_btnLabel;
+
+ public MethodInfo ToStringMethod => m_toStringMethod ?? GetToStringMethod();
+ private MethodInfo m_toStringMethod;
+
+ public virtual void Init()
+ {
+ UpdateValue();
+ }
+
+ public virtual void UpdateValue()
+ {
+ GetButtonLabel();
+ }
+
+ public float CalcWhitespace(Rect window)
+ {
+ if (!(this is IExpandHeight)) return 0f;
+
+ float whitespace = (this as IExpandHeight).WhiteSpace;
+ if (whitespace > 0)
+ {
+ ClampLabelWidth(window, ref whitespace);
+ }
+
+ return whitespace;
+ }
+
+ public static void ClampLabelWidth(Rect window, ref float labelWidth)
+ {
+ float min = window.width * 0.37f;
+ if (min > MAX_LABEL_WIDTH) min = MAX_LABEL_WIDTH;
+
+ labelWidth = Mathf.Clamp(labelWidth, min, MAX_LABEL_WIDTH);
+ }
+
+ public void Draw(Rect window, float labelWidth = 215f)
+ {
+ if (labelWidth > 0)
+ {
+ ClampLabelWidth(window, ref labelWidth);
+ }
+
+ var cacheMember = OwnerCacheObject as CacheMember;
+
+ if (cacheMember != null && cacheMember.MemInfo != null)
+ {
+ GUILayout.Label(cacheMember.RichTextName, new GUILayoutOption[] { GUILayout.Width(labelWidth) });
+ }
+ else
+ {
+ GUIUnstrip.Space(labelWidth);
+ }
+
+ var cacheMethod = OwnerCacheObject as CacheMethod;
+
+ if (cacheMember != null && cacheMember.HasParameters)
+ {
+ GUIUnstrip.BeginVertical(new GUILayoutOption[] { GUILayout.ExpandHeight(true) } );
+
+ if (cacheMember.m_isEvaluating)
+ {
+ if (cacheMethod != null && cacheMethod.GenericArgs.Length > 0)
+ {
+ cacheMethod.DrawGenericArgsInput();
+ }
+
+ if (cacheMember.m_arguments.Length > 0)
+ {
+ cacheMember.DrawArgsInput();
+ }
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) }))
+ {
+ if (cacheMethod != null)
+ cacheMethod.Evaluate();
+ else
+ cacheMember.UpdateValue();
+ }
+ if (GUILayout.Button("Cancel", new GUILayoutOption[] { GUILayout.Width(70) }))
+ {
+ cacheMember.m_isEvaluating = false;
+ }
+ GUILayout.EndHorizontal();
+ }
+ else
+ {
+ var lbl = $"Evaluate (";
+ int len = cacheMember.m_arguments.Length;
+ if (cacheMethod != null) len += cacheMethod.GenericArgs.Length;
+ lbl += len + " params)";
+
+ if (GUILayout.Button(lbl, new GUILayoutOption[] { GUILayout.Width(150) }))
+ {
+ cacheMember.m_isEvaluating = true;
+ }
+ }
+
+ GUILayout.EndVertical();
+
+ GUILayout.EndHorizontal();
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.Space(labelWidth);
+ }
+ else if (cacheMethod != null)
+ {
+ if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) }))
+ {
+ cacheMethod.Evaluate();
+ }
+
+ GUILayout.EndHorizontal();
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.Space(labelWidth);
+ }
+
+ string typeName = $"{ValueType.FullName} ";
+
+ if (cacheMember != null && !string.IsNullOrEmpty(cacheMember.ReflectionException))
+ {
+ GUILayout.Label("Reflection failed! (" + cacheMember.ReflectionException + ")", new GUILayoutOption[0]);
+ }
+ else if (cacheMember != null && (cacheMember.HasParameters || cacheMember is CacheMethod) && !cacheMember.m_evaluated)
+ {
+ GUILayout.Label($"Not yet evaluated ({typeName})", new GUILayoutOption[0]);
+ }
+ else if (Value == null && !(cacheMember is CacheMethod))
+ {
+ GUILayout.Label($"null ({typeName}) ", new GUILayoutOption[0]);
+ }
+ else
+ {
+ float _width = window.width - labelWidth - 90;
+ if (OwnerCacheObject is CacheMethod cm)
+ {
+ cm.DrawValue(window, _width);
+ }
+ else
+ {
+ DrawValue(window, _width);
+ }
+ }
+ }
+
+ public virtual void DrawValue(Rect window, float width)
+ {
+ GUI.skin.button.alignment = TextAnchor.MiddleLeft;
+ if (GUILayout.Button(ButtonLabel, new GUILayoutOption[] { GUILayout.Width(width - 15) }))
+ {
+ if (OwnerCacheObject.IsStaticClassSearchResult)
+ {
+ WindowManager.InspectStaticReflection(Value as Type);
+ }
+ else
+ {
+ WindowManager.InspectObject(Value, out bool _);
+ }
+ }
+ GUI.skin.button.alignment = TextAnchor.MiddleCenter;
+ }
+
+ private MethodInfo GetToStringMethod()
+ {
+ try
+ {
+ m_toStringMethod = ReflectionHelpers.GetActualType(Value).GetMethod("ToString", new Type[0])
+ ?? typeof(object).GetMethod("ToString", new Type[0]);
+
+ // test invoke
+ m_toStringMethod.Invoke(Value, null);
+ }
+ catch
+ {
+ m_toStringMethod = typeof(object).GetMethod("ToString", new Type[0]);
+ }
+ return m_toStringMethod;
+ }
+
+ private string GetButtonLabel()
+ {
+ if (Value == null) return null;
+
+ string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
+
+ var classColor = ValueType.IsAbstract && ValueType.IsSealed
+ ? Syntax.Class_Static
+ : Syntax.Class_Instance;
+
+ string typeLabel = $"{ValueType.FullName} ";
+
+ if (Value is UnityEngine.Object)
+ {
+ label = label.Replace($"({ValueType.FullName})", $"({typeLabel})");
+ }
+ else
+ {
+ if (!label.Contains(ValueType.FullName))
+ {
+ label += $" ({typeLabel})";
+ }
+ else
+ {
+ label = label.Replace(ValueType.FullName, typeLabel);
+ }
+ }
+
+ return m_btnLabel = label;
+ }
+ }
+}
diff --git a/src/CachedObjects/Object/CacheDictionary.cs b/src/UI/InteractiveValue/Object/InteractiveDictionary.cs
similarity index 89%
rename from src/CachedObjects/Object/CacheDictionary.cs
rename to src/UI/InteractiveValue/Object/InteractiveDictionary.cs
index a84ce68..850a211 100644
--- a/src/CachedObjects/Object/CacheDictionary.cs
+++ b/src/UI/InteractiveValue/Object/InteractiveDictionary.cs
@@ -1,15 +1,16 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Threading;
using UnityEngine;
#if CPP
using UnhollowerBaseLib;
#endif
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
-namespace Explorer
+namespace Explorer.UI
{
- public class CacheDictionary : CacheObjectBase, IExpandHeight
+ public class InteractiveDictionary : InteractiveValue, IExpandHeight
{
public bool IsExpanded { get; set; }
public float WhiteSpace { get; set; } = 215f;
@@ -54,11 +55,11 @@ namespace Explorer
// note: "ValueType" is the Dictionary itself, TypeOfValues is the 'Dictionary.Values' type.
// get keys and values
- var keys = ValueType.GetProperty("Keys") .GetValue(Value, null);
+ var keys = ValueType.GetProperty("Keys").GetValue(Value, null);
var values = ValueType.GetProperty("Values").GetValue(Value, null);
// create lists to hold them
- var keyList = new List();
+ var keyList = new List();
var valueList = new List();
// store entries with reflection
@@ -98,8 +99,9 @@ namespace Explorer
{
if (ValueType.IsGenericType)
{
- m_keysType = ValueType.GetGenericArguments()[0];
- m_valuesType = ValueType.GetGenericArguments()[1];
+ var generics = ValueType.GetGenericArguments();
+ m_keysType = generics[0];
+ m_valuesType = generics[1];
}
else
{
@@ -114,7 +116,10 @@ namespace Explorer
// first make sure we won't run into a TypeInitializationException.
if (!EnsureDictionaryIsSupported())
{
- ReflectionException = "Dictionary Type not supported with Reflection!";
+ if (OwnerCacheObject is CacheMember cacheMember)
+ {
+ cacheMember.ReflectionException = "Dictionary Type not supported with Reflection!";
+ }
return;
}
@@ -175,9 +180,9 @@ namespace Explorer
return Il2CppSystem.Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(ptr)) is Il2CppSystem.Type;
}
}
- catch
- {
- return false;
+ catch
+ {
+ return false;
}
#else
return false;
@@ -232,7 +237,7 @@ namespace Explorer
if (count > Pages.ItemsPerPage)
{
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
@@ -262,7 +267,7 @@ namespace Explorer
//collapsing the BeginHorizontal called from ReflectionWindow.WindowFunction or previous array entry
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
//GUIUnstrip.Space(whitespace);
@@ -278,13 +283,13 @@ namespace Explorer
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
GUILayout.Label("Key:", new GUILayoutOption[] { GUILayout.Width(40) });
if (key != null)
- key.DrawValue(window, (window.width / 2) - 80f);
+ key.IValue.DrawValue(window, (window.width / 2) - 80f);
else
GUILayout.Label("null ", new GUILayoutOption[0]);
GUILayout.Label("Value:", new GUILayoutOption[] { GUILayout.Width(40) });
- if (Value != null)
- val.DrawValue(window, (window.width / 2) - 80f);
+ if (val != null)
+ val.IValue.DrawValue(window, (window.width / 2) - 80f);
else
GUILayout.Label("null ", new GUILayoutOption[0]);
}
diff --git a/src/CachedObjects/Object/CacheList.cs b/src/UI/InteractiveValue/Object/InteractiveEnumerable.cs
similarity index 86%
rename from src/CachedObjects/Object/CacheList.cs
rename to src/UI/InteractiveValue/Object/InteractiveEnumerable.cs
index be4e11c..e863390 100644
--- a/src/CachedObjects/Object/CacheList.cs
+++ b/src/UI/InteractiveValue/Object/InteractiveEnumerable.cs
@@ -4,20 +4,22 @@ using System.Collections.Generic;
using System.Threading;
using System.Reflection;
using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
-namespace Explorer
+namespace Explorer.UI
{
- public class CacheList : CacheObjectBase, IExpandHeight
+ public class InteractiveEnumerable : InteractiveValue, IExpandHeight
{
public bool IsExpanded { get; set; }
public float WhiteSpace { get; set; } = 215f;
public PageHelper Pages = new PageHelper();
- private CacheObjectBase[] m_cachedEntries = new CacheObjectBase[0];
+ private CacheEnumerated[] m_cachedEntries = new CacheEnumerated[0];
// Type of Entries in the Array
- public Type EntryType
+ public Type EntryType
{
get => GetEntryType();
set => m_entryType = value;
@@ -173,16 +175,16 @@ namespace Explorer
{
if (m_entryType == null)
{
- if (this.MemInfo != null)
+ if (OwnerCacheObject is CacheMember cacheMember && cacheMember.MemInfo != null)
{
Type memberType = null;
- switch (this.MemInfo.MemberType)
+ switch (cacheMember.MemInfo.MemberType)
{
case MemberTypes.Field:
- memberType = (MemInfo as FieldInfo).FieldType;
+ memberType = (cacheMember.MemInfo as FieldInfo).FieldType;
break;
case MemberTypes.Property:
- memberType = (MemInfo as PropertyInfo).PropertyType;
+ memberType = (cacheMember.MemInfo as PropertyInfo).PropertyType;
break;
}
@@ -201,7 +203,7 @@ namespace Explorer
}
}
- // IList probably won't be able to get any EntryType.
+ // use System.Object for non-generic.
if (m_entryType == null)
{
m_entryType = typeof(object);
@@ -230,7 +232,8 @@ namespace Explorer
return;
}
- var list = new List();
+ var list = new List();
+ int index = 0;
while (enumerator.MoveNext())
{
var obj = enumerator.Current;
@@ -252,19 +255,25 @@ namespace Explorer
}
#endif
- if (CacheFactory.GetCacheObject(obj, t) is CacheObjectBase cached)
- {
- list.Add(cached);
- }
- else
- {
- list.Add(null);
- }
+ var cached = new CacheEnumerated() { Index = index, RefIList = Value as IList, ParentEnumeration = this };
+ cached.Init(obj, EntryType);
+ list.Add(cached);
+
+ //if (CacheFactory.GetCacheObject(obj, t) is CacheObjectBase cached)
+ //{
+ // list.Add(cached);
+ //}
+ //else
+ //{
+ // list.Add(null);
+ //}
}
else
{
list.Add(null);
}
+
+ index++;
}
m_cachedEntries = list.ToArray();
@@ -318,10 +327,10 @@ namespace Explorer
if (count > Pages.ItemsPerPage)
{
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
-
+
Pages.CurrentPageLabel();
// prev/next page buttons
@@ -347,11 +356,11 @@ namespace Explorer
//collapsing the BeginHorizontal called from ReflectionWindow.WindowFunction or previous array entry
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
- if (entry == null || entry.Value == null)
+ if (entry == null || entry.IValue == null)
{
GUILayout.Label($"[{i}] (null) ", new GUILayoutOption[0]);
}
@@ -361,9 +370,9 @@ namespace Explorer
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(30) });
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
- entry.DrawValue(window, window.width - (whitespace + 85));
+ entry.IValue.DrawValue(window, window.width - (whitespace + 85));
}
-
+
}
GUI.skin.label.alignment = TextAnchor.UpperLeft;
diff --git a/src/UI/InteractiveValue/Object/InteractiveGameObject.cs b/src/UI/InteractiveValue/Object/InteractiveGameObject.cs
new file mode 100644
index 0000000..851468d
--- /dev/null
+++ b/src/UI/InteractiveValue/Object/InteractiveGameObject.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
+
+namespace Explorer.UI
+{
+ public class InteractiveGameObject : InteractiveValue
+ {
+
+
+ public override void DrawValue(Rect window, float width)
+ {
+ Buttons.GameObjectButton(Value, null, false, width);
+ }
+
+ public override void UpdateValue()
+ {
+ base.UpdateValue();
+ }
+ }
+}
diff --git a/src/CachedObjects/Struct/CacheColor.cs b/src/UI/InteractiveValue/Struct/InteractiveColor.cs
similarity index 82%
rename from src/CachedObjects/Struct/CacheColor.cs
rename to src/UI/InteractiveValue/Struct/InteractiveColor.cs
index 2ce1191..5de25b1 100644
--- a/src/CachedObjects/Struct/CacheColor.cs
+++ b/src/UI/InteractiveValue/Struct/InteractiveColor.cs
@@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
-namespace Explorer
+namespace Explorer.UI
{
- public class CacheColor : CacheObjectBase, IExpandHeight
+ public class InteractiveColor : InteractiveValue, IExpandHeight
{
private string r = "0";
private string g = "0";
@@ -32,7 +34,7 @@ namespace Explorer
public override void DrawValue(Rect window, float width)
{
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
if (!IsExpanded)
{
@@ -55,38 +57,38 @@ namespace Explorer
GUILayout.Label($"Color: {((Color)Value).ToString()}", new GUILayoutOption[0]);
//GUI.color = Color.white;
- if (CanWrite && IsExpanded)
+ if (OwnerCacheObject.CanWrite && IsExpanded)
{
GUILayout.EndHorizontal();
var whitespace = CalcWhitespace(window);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("R:", new GUILayoutOption[] { GUILayout.Width(30) });
r = GUIUnstrip.TextField(r, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("G:", new GUILayoutOption[] { GUILayout.Width(30) });
g = GUIUnstrip.TextField(g, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("B:", new GUILayoutOption[] { GUILayout.Width(30) });
b = GUIUnstrip.TextField(b, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("A:", new GUILayoutOption[] { GUILayout.Width(30) });
a = GUIUnstrip.TextField(a, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
// draw set value button
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
if (GUILayout.Button("Apply ", new GUILayoutOption[] { GUILayout.Width(155) }))
{
@@ -94,7 +96,7 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
}
}
@@ -106,7 +108,7 @@ namespace Explorer
&& float.TryParse(a, out float fA))
{
Value = new Color(fR, fG, fB, fA);
- SetValue();
+ OwnerCacheObject.SetValue();
}
}
}
diff --git a/src/CachedObjects/Struct/CacheEnum.cs b/src/UI/InteractiveValue/Struct/InteractiveEnum.cs
similarity index 78%
rename from src/CachedObjects/Struct/CacheEnum.cs
rename to src/UI/InteractiveValue/Struct/InteractiveEnum.cs
index 184c733..9899bdf 100644
--- a/src/CachedObjects/Struct/CacheEnum.cs
+++ b/src/UI/InteractiveValue/Struct/InteractiveEnum.cs
@@ -4,10 +4,12 @@ using System.Linq;
using System.Text;
using System.Reflection;
using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
-namespace Explorer
+namespace Explorer.UI
{
- public class CacheEnum : CacheObjectBase
+ public class InteractiveEnum : InteractiveValue
{
internal static Dictionary EnumNamesInternalCache = new Dictionary();
@@ -27,7 +29,10 @@ namespace Explorer
}
else
{
- ReflectionException = "Unknown, could not get Enum names.";
+ if (OwnerCacheObject is CacheMember cacheMember)
+ {
+ cacheMember.ReflectionException = "Unknown, could not get Enum names.";
+ }
}
}
@@ -54,21 +59,21 @@ namespace Explorer
public override void DrawValue(Rect window, float width)
{
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(25) }))
{
SetEnum(-1);
- SetValue();
+ OwnerCacheObject.SetValue();
}
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(25) }))
{
SetEnum(1);
- SetValue();
+ OwnerCacheObject.SetValue();
}
}
- GUILayout.Label(Value.ToString() + $" ({ValueType}) ", new GUILayoutOption[0]);
+ GUILayout.Label(Value.ToString() + $" ({ValueType}) ", new GUILayoutOption[0]);
}
public void SetEnum(int change)
diff --git a/src/CachedObjects/Struct/CacheEnumFlags.cs b/src/UI/InteractiveValue/Struct/InteractiveFlags.cs
similarity index 86%
rename from src/CachedObjects/Struct/CacheEnumFlags.cs
rename to src/UI/InteractiveValue/Struct/InteractiveFlags.cs
index de1316d..e6a1141 100644
--- a/src/CachedObjects/Struct/CacheEnumFlags.cs
+++ b/src/UI/InteractiveValue/Struct/InteractiveFlags.cs
@@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
-namespace Explorer
+namespace Explorer.UI
{
- public class CacheEnumFlags : CacheEnum, IExpandHeight
+ public class InteractiveFlags : InteractiveEnum, IExpandHeight
{
public bool[] m_enabledFlags = new bool[0];
@@ -45,7 +47,7 @@ namespace Explorer
public override void DrawValue(Rect window, float width)
{
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
if (!IsExpanded)
{
@@ -73,7 +75,7 @@ namespace Explorer
for (int i = 0; i < EnumNames.Length; i++)
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
m_enabledFlags[i] = GUILayout.Toggle(m_enabledFlags[i], EnumNames[i], new GUILayoutOption[0]);
@@ -81,7 +83,7 @@ namespace Explorer
GUILayout.EndHorizontal();
}
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
if (GUILayout.Button("Apply ", new GUILayoutOption[] { GUILayout.Width(155) }))
{
@@ -89,7 +91,7 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
}
}
@@ -105,7 +107,7 @@ namespace Explorer
}
}
Value = Enum.Parse(ValueType, val);
- SetValue();
+ OwnerCacheObject.SetValue();
}
}
}
diff --git a/src/CachedObjects/Struct/CachePrimitive.cs b/src/UI/InteractiveValue/Struct/InteractivePrimitive.cs
similarity index 88%
rename from src/CachedObjects/Struct/CachePrimitive.cs
rename to src/UI/InteractiveValue/Struct/InteractivePrimitive.cs
index 07ec5f9..5c00b05 100644
--- a/src/CachedObjects/Struct/CachePrimitive.cs
+++ b/src/UI/InteractiveValue/Struct/InteractivePrimitive.cs
@@ -6,10 +6,13 @@ using UnityEngine;
#if CPP
using UnhollowerRuntimeLib;
#endif
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
+using Explorer.Config;
-namespace Explorer
+namespace Explorer.UI
{
- public class CachePrimitive : CacheObjectBase
+ public class InteractivePrimitive : InteractiveValue
{
private string m_valueToString;
private bool m_isBool;
@@ -61,7 +64,7 @@ namespace Explorer
{
m_valueToString = Value?.ToString();
- if (m_canBitwiseOperate)
+ if (m_canBitwiseOperate && Value != null)
{
var _int = (int)Value;
m_binaryInput = Convert.ToString(_int, toBase: 2);
@@ -75,13 +78,13 @@ namespace Explorer
var b = (bool)Value;
var label = $"{b} ";
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
b = GUILayout.Toggle(b, label, new GUILayoutOption[0]);
if (b != (bool)Value)
{
Value = b;
- SetValue();
+ OwnerCacheObject.SetValue();
}
}
else
@@ -94,14 +97,14 @@ namespace Explorer
// all other non-bool values use TextField
- GUILayout.BeginVertical(new GUILayoutOption[0]);
+ GUIUnstrip.BeginVertical(new GUILayoutOption[0]);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("" + ValueType.Name + " ", new GUILayoutOption[] { GUILayout.Width(50) });
m_valueToString = GUIUnstrip.TextArea(m_valueToString, new GUILayoutOption[] { GUILayout.ExpandWidth(true) });
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
if (GUILayout.Button("Apply ", new GUILayoutOption[] { GUILayout.Width(60) }))
{
@@ -109,7 +112,7 @@ namespace Explorer
}
}
- if (m_canBitwiseOperate)
+ if (ModConfig.Instance.Bitwise_Support && m_canBitwiseOperate)
{
m_inBitwiseMode = GUILayout.Toggle(m_inBitwiseMode, "Bitwise?", new GUILayoutOption[0]);
}
@@ -118,7 +121,7 @@ namespace Explorer
GUILayout.EndHorizontal();
- if (m_inBitwiseMode)
+ if (ModConfig.Instance.Bitwise_Support && m_inBitwiseMode)
{
DrawBitwise();
}
@@ -128,9 +131,9 @@ namespace Explorer
private void DrawBitwise()
{
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.MiddleRight;
GUILayout.Label("RHS:", new GUILayoutOption[] { GUILayout.Width(35) });
@@ -191,10 +194,10 @@ namespace Explorer
GUILayout.EndHorizontal();
}
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label($"Binary: ", new GUILayoutOption[] { GUILayout.Width(60) });
m_binaryInput = GUIUnstrip.TextField(m_binaryInput, new GUILayoutOption[0]);
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
if (GUILayout.Button("Apply", new GUILayoutOption[0]))
{
@@ -206,12 +209,6 @@ namespace Explorer
public void SetValueFromInput()
{
- if (MemInfo == null)
- {
- ExplorerCore.Log("Trying to SetValue but the MemberInfo is null!");
- return;
- }
-
if (m_isString)
{
Value = m_valueToString;
@@ -228,7 +225,7 @@ namespace Explorer
}
}
- SetValue();
+ OwnerCacheObject.SetValue();
RefreshToString();
}
@@ -239,7 +236,7 @@ namespace Explorer
var method = typeof(Convert).GetMethod($"To{ValueType.Name}", new Type[] { typeof(string), typeof(int) });
Value = method.Invoke(null, new object[] { m_binaryInput, 2 });
- SetValue();
+ OwnerCacheObject.SetValue();
RefreshToString();
}
catch (Exception e)
diff --git a/src/CachedObjects/Struct/CacheQuaternion.cs b/src/UI/InteractiveValue/Struct/InteractiveQuaternion.cs
similarity index 82%
rename from src/CachedObjects/Struct/CacheQuaternion.cs
rename to src/UI/InteractiveValue/Struct/InteractiveQuaternion.cs
index 6b02684..cd00cc0 100644
--- a/src/CachedObjects/Struct/CacheQuaternion.cs
+++ b/src/UI/InteractiveValue/Struct/InteractiveQuaternion.cs
@@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
-namespace Explorer
+namespace Explorer.UI
{
- public class CacheQuaternion : CacheObjectBase, IExpandHeight
+ public class InteractiveQuaternion : InteractiveValue, IExpandHeight
{
private string x = "0";
private string y = "0";
@@ -30,7 +32,7 @@ namespace Explorer
public override void DrawValue(Rect window, float width)
{
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
if (!IsExpanded)
{
@@ -50,32 +52,32 @@ namespace Explorer
GUILayout.Label($"Quaternion : {((Quaternion)Value).eulerAngles.ToString()}", new GUILayoutOption[0]);
- if (CanWrite && IsExpanded)
+ if (OwnerCacheObject.CanWrite && IsExpanded)
{
GUILayout.EndHorizontal();
var whitespace = CalcWhitespace(window);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
x = GUIUnstrip.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
y = GUIUnstrip.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
z = GUIUnstrip.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
// draw set value button
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
if (GUILayout.Button("Apply ", new GUILayoutOption[] { GUILayout.Width(155) }))
{
@@ -83,7 +85,7 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
}
}
@@ -94,7 +96,7 @@ namespace Explorer
&& float.TryParse(z, out float fZ))
{
Value = Quaternion.Euler(new Vector3(fX, fY, fZ));
- SetValue();
+ OwnerCacheObject.SetValue();
}
}
}
diff --git a/src/CachedObjects/Struct/CacheRect.cs b/src/UI/InteractiveValue/Struct/InteractiveRect.cs
similarity index 82%
rename from src/CachedObjects/Struct/CacheRect.cs
rename to src/UI/InteractiveValue/Struct/InteractiveRect.cs
index 4a69089..5814f52 100644
--- a/src/CachedObjects/Struct/CacheRect.cs
+++ b/src/UI/InteractiveValue/Struct/InteractiveRect.cs
@@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
-namespace Explorer
+namespace Explorer.UI
{
- public class CacheRect : CacheObjectBase, IExpandHeight
+ public class InteractiveRect : InteractiveValue, IExpandHeight
{
private string x = "0";
private string y = "0";
@@ -32,7 +34,7 @@ namespace Explorer
public override void DrawValue(Rect window, float width)
{
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
if (!IsExpanded)
{
@@ -52,38 +54,38 @@ namespace Explorer
GUILayout.Label($"Rect : {((Rect)Value).ToString()}", new GUILayoutOption[0]);
- if (CanWrite && IsExpanded)
+ if (OwnerCacheObject.CanWrite && IsExpanded)
{
GUILayout.EndHorizontal();
var whitespace = CalcWhitespace(window);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
x = GUIUnstrip.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
y = GUIUnstrip.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
w = GUIUnstrip.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("H:", new GUILayoutOption[] { GUILayout.Width(30) });
h = GUIUnstrip.TextField(h, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
// draw set value button
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
if (GUILayout.Button("Apply ", new GUILayoutOption[] { GUILayout.Width(155) }))
{
@@ -91,7 +93,7 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
}
}
@@ -103,7 +105,7 @@ namespace Explorer
&& float.TryParse(h, out float fH))
{
Value = new Rect(fX, fY, fW, fH);
- SetValue();
+ OwnerCacheObject.SetValue();
}
}
}
diff --git a/src/CachedObjects/Struct/CacheVector.cs b/src/UI/InteractiveValue/Struct/InteractiveVector.cs
similarity index 81%
rename from src/CachedObjects/Struct/CacheVector.cs
rename to src/UI/InteractiveValue/Struct/InteractiveVector.cs
index 3f857b7..5306610 100644
--- a/src/CachedObjects/Struct/CacheVector.cs
+++ b/src/UI/InteractiveValue/Struct/InteractiveVector.cs
@@ -5,9 +5,9 @@ using System.Text;
using System.Reflection;
using UnityEngine;
-namespace Explorer
+namespace Explorer.UI
{
- public class CacheVector : CacheObjectBase, IExpandHeight
+ public class InteractiveVector : InteractiveValue, IExpandHeight
{
public int VectorSize = 2;
@@ -16,7 +16,7 @@ namespace Explorer
private string z = "0";
private string w = "0";
- private MethodInfo m_toStringMethod;
+ //private MethodInfo m_toStringMethod;
public bool IsExpanded { get; set; }
public float WhiteSpace { get; set; } = 215f;
@@ -31,18 +31,20 @@ namespace Explorer
if (ValueType == typeof(Vector2))
{
VectorSize = 2;
- m_toStringMethod = typeof(Vector2).GetMethod("ToString", new Type[0]);
+ //m_toStringMethod = typeof(Vector2).GetMethod("ToString", new Type[0]);
}
else if (ValueType == typeof(Vector3))
{
VectorSize = 3;
- m_toStringMethod = typeof(Vector3).GetMethod("ToString", new Type[0]);
+ //m_toStringMethod = typeof(Vector3).GetMethod("ToString", new Type[0]);
}
else
{
VectorSize = 4;
- m_toStringMethod = typeof(Vector4).GetMethod("ToString", new Type[0]);
+ //m_toStringMethod = typeof(Vector4).GetMethod("ToString", new Type[0]);
}
+
+ base.Init();
}
public override void UpdateValue()
@@ -71,7 +73,7 @@ namespace Explorer
public override void DrawValue(Rect window, float width)
{
- if (CanWrite)
+ if (OwnerCacheObject.CanWrite)
{
if (!IsExpanded)
{
@@ -89,22 +91,22 @@ namespace Explorer
}
}
- GUILayout.Label($"Vector{VectorSize} : {(string)m_toStringMethod.Invoke(Value, new object[0])}", new GUILayoutOption[0]);
+ GUILayout.Label($"Vector{VectorSize} : {(string)ToStringMethod.Invoke(Value, new object[0])}", new GUILayoutOption[0]);
- if (CanWrite && IsExpanded)
+ if (OwnerCacheObject.CanWrite && IsExpanded)
{
GUILayout.EndHorizontal();
var whitespace = CalcWhitespace(window);
// always draw x and y
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
x = GUIUnstrip.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
y = GUIUnstrip.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
@@ -113,7 +115,7 @@ namespace Explorer
if (VectorSize > 2)
{
// draw z
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
z = GUIUnstrip.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
@@ -122,7 +124,7 @@ namespace Explorer
if (VectorSize > 3)
{
// draw w
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
w = GUIUnstrip.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
@@ -130,7 +132,7 @@ namespace Explorer
}
// draw set value button
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUIUnstrip.Space(whitespace);
if (GUILayout.Button("Apply ", new GUILayoutOption[] { GUILayout.Width(155) }))
{
@@ -138,7 +140,7 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
}
}
@@ -161,7 +163,7 @@ namespace Explorer
if (vector != null)
{
Value = vector;
- SetValue();
+ OwnerCacheObject.SetValue();
}
}
}
diff --git a/src/Menu/MainMenu/Pages/WindowPage.cs b/src/UI/Main/BaseMainMenuPage.cs
similarity index 78%
rename from src/Menu/MainMenu/Pages/WindowPage.cs
rename to src/UI/Main/BaseMainMenuPage.cs
index 5a3a344..00bf59d 100644
--- a/src/Menu/MainMenu/Pages/WindowPage.cs
+++ b/src/UI/Main/BaseMainMenuPage.cs
@@ -1,8 +1,8 @@
using UnityEngine;
-namespace Explorer
+namespace Explorer.UI.Main
{
- public abstract class WindowPage
+ public abstract class BaseMainMenuPage
{
public virtual string Name { get; }
diff --git a/src/UI/Main/Console/AutoComplete.cs b/src/UI/Main/Console/AutoComplete.cs
new file mode 100644
index 0000000..9d2e3b3
--- /dev/null
+++ b/src/UI/Main/Console/AutoComplete.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using UnityEngine;
+
+// Thanks to ManlyMarco for this
+
+namespace Explorer.UI.Main
+{
+ public struct AutoComplete
+ {
+ public string Full => Prefix + Addition;
+
+ public readonly string Prefix;
+ public readonly string Addition;
+ public readonly Contexts Context;
+
+ public Color TextColor => Context == Contexts.Namespace
+ ? Color.gray
+ : Color.white;
+
+ public AutoComplete(string addition, string prefix, Contexts type)
+ {
+ Addition = addition;
+ Prefix = prefix;
+ Context = type;
+ }
+
+ public enum Contexts
+ {
+ Namespace,
+ Other
+ }
+ }
+
+ public static class AutoCompleteHelpers
+ {
+ public static HashSet Namespaces => _namespaces ?? GetNamespaces();
+ private static HashSet _namespaces;
+
+ private static HashSet GetNamespaces()
+ {
+ var set = new HashSet(
+ AppDomain.CurrentDomain.GetAssemblies()
+ .SelectMany(GetTypes)
+ .Where(x => x.IsPublic && !string.IsNullOrEmpty(x.Namespace))
+ .Select(x => x.Namespace));
+
+ return _namespaces = set;
+
+ IEnumerable GetTypes(Assembly asm) => asm.TryGetTypes();
+ }
+ }
+}
diff --git a/src/UI/Main/Console/ScriptEvaluator.cs b/src/UI/Main/Console/ScriptEvaluator.cs
new file mode 100644
index 0000000..eb827a6
--- /dev/null
+++ b/src/UI/Main/Console/ScriptEvaluator.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using Mono.CSharp;
+
+// Thanks to ManlyMarco for this
+
+namespace Explorer.UI.Main
+{
+ internal class ScriptEvaluator : Evaluator, IDisposable
+ {
+ private static readonly HashSet StdLib = new HashSet(StringComparer.InvariantCultureIgnoreCase)
+ {
+ "mscorlib", "System.Core", "System", "System.Xml"
+ };
+
+ private readonly TextWriter _logger;
+
+ public ScriptEvaluator(TextWriter logger) : base(BuildContext(logger))
+ {
+ _logger = logger;
+
+ ImportAppdomainAssemblies(ReferenceAssembly);
+ AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
+ }
+
+ public void Dispose()
+ {
+ AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;
+ _logger.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)
+ {
+ var reporter = 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, reporter);
+ }
+
+ private static void ImportAppdomainAssemblies(Action import)
+ {
+ foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ string name = assembly.GetName().Name;
+ if (StdLib.Contains(name))
+ continue;
+ import(assembly);
+ }
+ }
+ }
+}
diff --git a/src/UI/Main/Console/ScriptInteraction.cs b/src/UI/Main/Console/ScriptInteraction.cs
new file mode 100644
index 0000000..5515669
--- /dev/null
+++ b/src/UI/Main/Console/ScriptInteraction.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Explorer.UI.Inspectors;
+using Mono.CSharp;
+using UnityEngine;
+
+namespace Explorer.UI.Main
+{
+ public class ScriptInteraction : InteractiveBase
+ {
+ public static void Log(object message)
+ {
+ ExplorerCore.Log(message);
+ }
+
+ public static object CurrentTarget()
+ {
+ if (!WindowManager.TabView)
+ {
+ ExplorerCore.Log("CurrentTarget() is only a valid method when in Tab View mode!");
+ return null;
+ }
+
+ return WindowManager.Windows.ElementAt(TabViewWindow.Instance.TargetTabID).Target;
+ }
+
+ public static object[] AllTargets()
+ {
+ var list = new List();
+ foreach (var window in WindowManager.Windows)
+ {
+ if (window.Target != null)
+ {
+ list.Add(window.Target);
+ }
+ }
+ return list.ToArray();
+ }
+
+ public static void Inspect(object obj)
+ {
+ WindowManager.InspectObject(obj, out bool _);
+ }
+
+ public static void Inspect(Type type)
+ {
+ WindowManager.InspectStaticReflection(type);
+ }
+
+ public static void Help()
+ {
+ ExplorerCore.Log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
+ ExplorerCore.Log(" C# Console Help ");
+ ExplorerCore.Log("");
+ ExplorerCore.Log("The following helper methods are available:");
+ ExplorerCore.Log("");
+ ExplorerCore.Log("void Log(object message)");
+ ExplorerCore.Log(" prints a message to the console window and debug log");
+ ExplorerCore.Log(" usage: Log(\"hello world\");");
+ ExplorerCore.Log("");
+ ExplorerCore.Log("object CurrentTarget()");
+ ExplorerCore.Log(" returns the target object of the current tab (in tab view mode only)");
+ ExplorerCore.Log(" usage: var target = CurrentTarget();");
+ ExplorerCore.Log("");
+ ExplorerCore.Log("object[] AllTargets()");
+ ExplorerCore.Log(" returns an object[] array containing all currently inspected objects");
+ ExplorerCore.Log(" usage: var targets = AllTargets();");
+ ExplorerCore.Log("");
+ ExplorerCore.Log("void Inspect(object obj)");
+ ExplorerCore.Log(" inspects the provided object in a new window.");
+ ExplorerCore.Log(" usage: Inspect(Camera.main);");
+ ExplorerCore.Log("");
+ ExplorerCore.Log("void Inspect(Type type)");
+ ExplorerCore.Log(" attempts to inspect the provided type with static-only reflection.");
+ ExplorerCore.Log(" usage: Inspect(typeof(Camera));");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/UI/Main/ConsolePage.cs b/src/UI/Main/ConsolePage.cs
new file mode 100644
index 0000000..8d03a38
--- /dev/null
+++ b/src/UI/Main/ConsolePage.cs
@@ -0,0 +1,366 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+using Mono.CSharp;
+using System.Reflection;
+using System.IO;
+#if CPP
+using UnhollowerRuntimeLib;
+#endif
+
+namespace Explorer.UI.Main
+{
+ public class ConsolePage : BaseMainMenuPage
+ {
+ public static ConsolePage Instance { get; private set; }
+
+ public override string Name { get => "C# Console"; }
+
+ private ScriptEvaluator m_evaluator;
+
+ public const string INPUT_CONTROL_NAME = "consoleInput";
+ private string m_input = "";
+ private string m_prevInput = "";
+ private string m_usingInput = "";
+
+ public static List AutoCompletes = new List();
+ public static List UsingDirectives;
+
+ private Vector2 inputAreaScroll;
+ private Vector2 autocompleteScroll;
+ public static TextEditor textEditor;
+ private bool shouldRefocus;
+
+ public static GUIStyle AutocompleteStyle => autocompleteStyle ?? GetCompletionStyle();
+ private static GUIStyle autocompleteStyle;
+
+ public static readonly string[] DefaultUsing = new string[]
+ {
+ "System",
+ "UnityEngine",
+ "System.Linq",
+ "System.Collections",
+ "System.Collections.Generic",
+ "System.Reflection"
+ };
+
+ public override void Init()
+ {
+ Instance = this;
+
+ try
+ {
+ m_input = @"// For a list of helper methods, execute the 'Help();' method.
+// Enable the Console Window with your Mod Loader to see log output.
+
+Help();";
+ ResetConsole();
+
+ foreach (var use in DefaultUsing)
+ {
+ AddUsing(use);
+ }
+ }
+ catch (Exception e)
+ {
+ ExplorerCore.LogWarning($"Error setting up console!\r\nMessage: {e.Message}");
+ MainMenu.SetCurrentPage(0);
+ MainMenu.Pages.Remove(this);
+ }
+ }
+
+ public override void Update() { }
+
+ public string AsmToUsing(string asm, bool richtext = false)
+ {
+ if (richtext)
+ {
+ return $"using {asm};";
+ }
+ return $"using {asm};";
+ }
+
+ public void AddUsing(string asm)
+ {
+ if (!UsingDirectives.Contains(asm))
+ {
+ UsingDirectives.Add(asm);
+ Evaluate(AsmToUsing(asm), true);
+ }
+ }
+
+ public object Evaluate(string str, bool suppressWarning = false)
+ {
+ object ret = VoidType.Value;
+
+ m_evaluator.Compile(str, out var compiled);
+
+ try
+ {
+ if (compiled == null)
+ {
+ throw new Exception("Mono.Csharp Service was unable to compile the code provided.");
+ }
+
+ compiled.Invoke(ref ret);
+ }
+ catch (Exception e)
+ {
+ if (!suppressWarning)
+ {
+ ExplorerCore.LogWarning(e.GetType() + ", " + e.Message);
+ }
+ }
+
+ return ret;
+ }
+
+ public void ResetConsole()
+ {
+ if (m_evaluator != null)
+ {
+ m_evaluator.Dispose();
+ }
+
+ m_evaluator = new ScriptEvaluator(new StringWriter(new StringBuilder())) { InteractiveBaseClass = typeof(ScriptInteraction) };
+
+ UsingDirectives = new List();
+ }
+
+
+ public override void DrawWindow()
+ {
+ GUILayout.Label("C# Console ", new GUILayoutOption[0]);
+
+ GUI.skin.label.alignment = TextAnchor.UpperLeft;
+
+ // SCRIPT INPUT
+
+ GUILayout.Label("Enter code here as though it is a method body:", new GUILayoutOption[0]);
+
+ inputAreaScroll = GUIUnstrip.BeginScrollView(
+ inputAreaScroll,
+ new GUILayoutOption[] { GUILayout.Height(250), GUILayout.ExpandHeight(true) }
+ );
+
+ GUI.SetNextControlName(INPUT_CONTROL_NAME);
+ m_input = GUIUnstrip.TextArea(m_input, new GUILayoutOption[] { GUILayout.ExpandHeight(true) });
+
+ GUIUnstrip.EndScrollView();
+
+ // EXECUTE BUTTON
+
+ if (GUILayout.Button("Execute ", new GUILayoutOption[0]))
+ {
+ try
+ {
+ m_input = m_input.Trim();
+
+ if (!string.IsNullOrEmpty(m_input))
+ {
+ Evaluate(m_input);
+
+ //var result = Evaluate(m_input);
+
+ //if (result != null && !Equals(result, VoidType.Value))
+ //{
+ // ExplorerCore.Log("[Console Output]\r\n" + result.ToString());
+ //}
+ }
+ }
+ catch (Exception e)
+ {
+ ExplorerCore.LogError("Exception compiling!\r\nMessage: " + e.Message + "\r\nStack: " + e.StackTrace);
+ }
+ }
+
+ // SUGGESTIONS
+ if (AutoCompletes.Count > 0)
+ {
+ autocompleteScroll = GUIUnstrip.BeginScrollView(autocompleteScroll, new GUILayoutOption[] { GUILayout.Height(150) });
+
+ var origSkin = GUI.skin.button;
+ GUI.skin.button = AutocompleteStyle;
+
+ foreach (var autocomplete in AutoCompletes)
+ {
+ AutocompleteStyle.normal.textColor = autocomplete.TextColor;
+ if (GUILayout.Button(autocomplete.Full, new GUILayoutOption[] { GUILayout.Width(MainMenu.MainRect.width - 50) }))
+ {
+ UseAutocomplete(autocomplete.Addition);
+ break;
+ }
+ }
+
+ GUI.skin.button = origSkin;
+
+ GUIUnstrip.EndScrollView();
+ }
+
+ if (shouldRefocus)
+ {
+ GUI.FocusControl(INPUT_CONTROL_NAME);
+ shouldRefocus = false;
+ }
+
+ // USING DIRECTIVES
+
+ GUILayout.Label("Using directives: ", new GUILayoutOption[0]);
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label("Add namespace:", new GUILayoutOption[] { GUILayout.Width(105) });
+ m_usingInput = GUIUnstrip.TextField(m_usingInput, new GUILayoutOption[] { GUILayout.Width(150) });
+ if (GUILayout.Button("Add ", new GUILayoutOption[] { GUILayout.Width(120) }))
+ {
+ AddUsing(m_usingInput);
+ }
+ if (GUILayout.Button("Clear All ", new GUILayoutOption[] { GUILayout.Width(120) }))
+ {
+ ResetConsole();
+ }
+ GUILayout.EndHorizontal();
+
+ foreach (var asm in UsingDirectives)
+ {
+ GUILayout.Label(AsmToUsing(asm, true), new GUILayoutOption[0]);
+ }
+
+ CheckAutocomplete();
+ }
+
+ private void CheckAutocomplete()
+ {
+ // Temporary disabling this check in BepInEx Il2Cpp.
+#if BIE
+#if CPP
+#else
+ if (GUI.GetNameOfFocusedControl() != INPUT_CONTROL_NAME)
+ return;
+#endif
+#else
+ if (GUI.GetNameOfFocusedControl() != INPUT_CONTROL_NAME)
+ return;
+#endif
+
+#if CPP
+ textEditor = GUIUtility.GetStateObject(Il2CppType.Of(), GUIUtility.keyboardControl).TryCast();
+#else
+ textEditor = (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl);
+#endif
+
+ var input = m_input;
+
+ if (!string.IsNullOrEmpty(input))
+ {
+ try
+ {
+ var splitChars = new[] { ',', ';', '<', '>', '(', ')', '[', ']', '=', '|', '&' };
+
+ // Credit ManlyMarco
+ // Separate input into parts, grab only the part with cursor in it
+ var cursorIndex = textEditor.cursorIndex;
+ var start = cursorIndex <= 0 ? 0 : input.LastIndexOfAny(splitChars, cursorIndex - 1) + 1;
+ var end = cursorIndex <= 0 ? input.Length : input.IndexOfAny(splitChars, cursorIndex - 1);
+ if (end < 0 || end < start) end = input.Length;
+ input = input.Substring(start, end - start);
+ }
+ catch (ArgumentException) { }
+
+ if (!string.IsNullOrEmpty(input) && input != m_prevInput)
+ {
+ GetAutocompletes(input);
+ }
+ }
+ else
+ {
+ ClearAutocompletes();
+ }
+
+ m_prevInput = input;
+ }
+
+ private void ClearAutocompletes()
+ {
+ if (AutoCompletes.Any())
+ {
+ AutoCompletes.Clear();
+ shouldRefocus = true;
+ }
+ }
+
+ private void UseAutocomplete(string suggestion)
+ {
+ int cursorIndex = textEditor.cursorIndex;
+ m_input = m_input.Insert(cursorIndex, suggestion);
+
+ ClearAutocompletes();
+ shouldRefocus = true;
+ }
+
+ private void GetAutocompletes(string input)
+ {
+ try
+ {
+ //ExplorerCore.Log("Fetching suggestions for input " + input);
+
+ // Credit ManylMarco
+ AutoCompletes.Clear();
+ var completions = m_evaluator.GetCompletions(input, out string prefix);
+ if (completions != null)
+ {
+ if (prefix == null)
+ prefix = input;
+
+ AutoCompletes.AddRange(completions
+ .Where(x => !string.IsNullOrEmpty(x))
+ .Select(x => new AutoComplete(x, prefix, AutoComplete.Contexts.Other))
+ );
+ }
+
+ var trimmed = input.Trim();
+ if (trimmed.StartsWith("using"))
+ trimmed = trimmed.Remove(0, 5).Trim();
+
+ var namespaces = AutoCompleteHelpers.Namespaces
+ .Where(x => x.StartsWith(trimmed) && x.Length > trimmed.Length)
+ .Select(x => new AutoComplete(
+ x.Substring(trimmed.Length),
+ x.Substring(0, trimmed.Length),
+ AutoComplete.Contexts.Namespace));
+
+ AutoCompletes.AddRange(namespaces);
+
+ shouldRefocus = true;
+ }
+ catch (Exception ex)
+ {
+ ExplorerCore.Log("C# Console error:\r\n" + ex);
+ ClearAutocompletes();
+ }
+ }
+
+ // Credit ManlyMarco
+ private static GUIStyle GetCompletionStyle()
+ {
+ return autocompleteStyle = new GUIStyle(GUI.skin.button)
+ {
+ border = new RectOffset(0, 0, 0, 0),
+ margin = new RectOffset(0, 0, 0, 0),
+ padding = new RectOffset(0, 0, 0, 0),
+ hover = { background = Texture2D.whiteTexture, textColor = Color.black },
+ normal = { background = null },
+ focused = { background = Texture2D.whiteTexture, textColor = Color.black },
+ active = { background = Texture2D.whiteTexture, textColor = Color.black },
+ alignment = TextAnchor.MiddleLeft,
+ };
+ }
+
+ private class VoidType
+ {
+ public static readonly VoidType Value = new VoidType();
+ private VoidType() { }
+ }
+ }
+}
diff --git a/src/UI/Main/OptionsPage.cs b/src/UI/Main/OptionsPage.cs
new file mode 100644
index 0000000..e3e28d2
--- /dev/null
+++ b/src/UI/Main/OptionsPage.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.Config;
+using Explorer.CacheObject;
+
+namespace Explorer.UI.Main
+{
+ public class OptionsPage : BaseMainMenuPage
+ {
+ public override string Name => "Options";
+
+ public string toggleKeyInputString = "";
+ public Vector2 defaultSizeInputVector;
+ public int defaultPageLimit;
+ public bool bitwiseSupport;
+ public bool tabView;
+
+ private CacheObjectBase toggleKeyInput;
+ private CacheObjectBase defaultSizeInput;
+ private CacheObjectBase defaultPageLimitInput;
+ private CacheObjectBase bitwiseSupportInput;
+ private CacheObjectBase tabViewInput;
+
+ public override void Init()
+ {
+ toggleKeyInputString = ModConfig.Instance.Main_Menu_Toggle.ToString();
+ toggleKeyInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("toggleKeyInputString"), this);
+
+ defaultSizeInputVector = ModConfig.Instance.Default_Window_Size;
+ defaultSizeInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("defaultSizeInputVector"), this);
+
+ defaultPageLimit = ModConfig.Instance.Default_Page_Limit;
+ defaultPageLimitInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("defaultPageLimit"), this);
+
+ bitwiseSupport = ModConfig.Instance.Bitwise_Support;
+ bitwiseSupportInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("bitwiseSupport"), this);
+
+ tabView = ModConfig.Instance.Tab_View;
+ tabViewInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("tabView"), this);
+ }
+
+ public override void Update() { }
+
+ public override void DrawWindow()
+ {
+ GUI.skin.label.alignment = TextAnchor.MiddleCenter;
+ GUILayout.Label("Options ", new GUILayoutOption[0]);
+ GUI.skin.label.alignment = TextAnchor.MiddleLeft;
+
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[0]);
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label($"Menu Toggle Key:", new GUILayoutOption[] { GUILayout.Width(215f) });
+ toggleKeyInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
+ GUILayout.EndHorizontal();
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label($"Default Window Size:", new GUILayoutOption[] { GUILayout.Width(215f) });
+ defaultSizeInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
+ GUILayout.EndHorizontal();
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label($"Default Items per Page:", new GUILayoutOption[] { GUILayout.Width(215f) });
+ defaultPageLimitInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
+ GUILayout.EndHorizontal();
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label($"Enable Bitwise Editing:", new GUILayoutOption[] { GUILayout.Width(215f) });
+ bitwiseSupportInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
+ GUILayout.EndHorizontal();
+
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label($"Enable Tab View:", new GUILayoutOption[] { GUILayout.Width(215f) });
+ tabViewInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
+ GUILayout.EndHorizontal();
+
+ if (GUILayout.Button("Apply and Save ", new GUILayoutOption[0]))
+ {
+ ApplyAndSave();
+ }
+
+ GUILayout.EndVertical();
+
+ GUIUnstrip.Space(10f);
+
+ GUI.skin.label.alignment = TextAnchor.MiddleCenter;
+ GUILayout.Label("Other ", new GUILayoutOption[0]);
+ GUI.skin.label.alignment = TextAnchor.MiddleLeft;
+
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[0]);
+
+ if (GUILayout.Button("Inspect Test Class", new GUILayoutOption[0]))
+ {
+ WindowManager.InspectObject(Tests.TestClass.Instance, out bool _);
+ }
+
+ GUILayout.EndVertical();
+ }
+
+ private void ApplyAndSave()
+ {
+ if (Enum.Parse(typeof(KeyCode), toggleKeyInputString) is KeyCode key)
+ {
+ ModConfig.Instance.Main_Menu_Toggle = key;
+ }
+ else
+ {
+ ExplorerCore.LogWarning($"Could not parse '{toggleKeyInputString}' to KeyCode!");
+ }
+
+ ModConfig.Instance.Default_Window_Size = defaultSizeInputVector;
+ ModConfig.Instance.Default_Page_Limit = defaultPageLimit;
+ ModConfig.Instance.Bitwise_Support = bitwiseSupport;
+
+ ModConfig.Instance.Tab_View = tabView;
+ WindowManager.TabView = tabView;
+
+ ModConfig.SaveSettings();
+ }
+ }
+}
diff --git a/src/Menu/MainMenu/Pages/ScenePage.cs b/src/UI/Main/ScenePage.cs
similarity index 78%
rename from src/Menu/MainMenu/Pages/ScenePage.cs
rename to src/UI/Main/ScenePage.cs
index 025d2f6..f9a0fdf 100644
--- a/src/Menu/MainMenu/Pages/ScenePage.cs
+++ b/src/UI/Main/ScenePage.cs
@@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
-namespace Explorer
+namespace Explorer.UI.Main
{
- public class ScenePage : WindowPage
+ public class ScenePage : BaseMainMenuPage
{
public static ScenePage Instance;
@@ -23,12 +25,12 @@ namespace Explorer
// gameobject list
private Transform m_currentTransform;
- private readonly List m_objectList = new List();
+ private readonly List m_objectList = new List();
// search bar
private bool m_searching = false;
private string m_searchInput = "";
- private List m_searchResults = new List();
+ private List m_searchResults = new List();
public override void Init()
{
@@ -80,9 +82,9 @@ namespace Explorer
}
}
- public List SearchSceneObjects(string _search)
+ public List SearchSceneObjects(string _search)
{
- var matches = new List();
+ var matches = new List();
foreach (var obj in Resources.FindObjectsOfTypeAll(ReflectionHelpers.GameObjectType))
{
@@ -93,7 +95,7 @@ namespace Explorer
#endif
if (go.name.ToLower().Contains(_search.ToLower()) && go.scene.name == m_currentScene)
{
- matches.Add(new GameObjectCache(go));
+ matches.Add(CacheFactory.GetCacheObject(go));
}
}
@@ -172,7 +174,7 @@ namespace Explorer
for (int i = offset; i < offset + Pages.ItemsPerPage && i < Pages.ItemCount; i++)
{
var child = allTransforms[i];
- m_objectList.Add(new GameObjectCache(child.gameObject));
+ m_objectList.Add(CacheFactory.GetCacheObject(child));
}
}
@@ -199,8 +201,8 @@ namespace Explorer
}
catch (Exception e)
{
- ExplorerCore.Log("Exception getting root scene objects (manual): "
- + e.GetType() + ", " + e.Message + "\r\n"
+ ExplorerCore.Log("Exception getting root scene objects (manual): "
+ + e.GetType() + ", " + e.Message + "\r\n"
+ e.StackTrace);
return new Transform[0];
}
@@ -214,7 +216,7 @@ namespace Explorer
{
DrawHeaderArea();
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
DrawPageButtons();
@@ -240,7 +242,7 @@ namespace Explorer
private void DrawHeaderArea()
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
// Current Scene label
GUILayout.Label("Current Scene:", new GUILayoutOption[] { GUILayout.Width(120) });
@@ -250,7 +252,7 @@ namespace Explorer
GUILayout.EndHorizontal();
// ----- GameObject Search -----
- GUILayout.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
GUILayout.Label("Search Scene: ", new GUILayoutOption[] { GUILayout.Width(100) });
m_searchInput = GUIUnstrip.TextField(m_searchInput, new GUILayoutOption[0]);
@@ -305,7 +307,7 @@ namespace Explorer
private void DrawPageButtons()
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
Pages.DrawLimitInputArea();
@@ -336,7 +338,7 @@ namespace Explorer
{
if (m_currentTransform != null)
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
{
TraverseUp();
@@ -347,8 +349,8 @@ namespace Explorer
new GUILayoutOption[] { GUILayout.Width(MainMenu.MainRect.width - 187f) });
}
- UIHelpers.SmallInspectButton(m_currentTransform);
-
+ Buttons.InspectButton(m_currentTransform);
+
GUILayout.EndHorizontal();
}
else
@@ -372,28 +374,28 @@ namespace Explorer
if (obj == null) continue;
- if (!obj.RefGameObject)
+ try
{
- string label = "null";
+ var go = obj.IValue.Value as GameObject ?? (obj.IValue.Value as Transform)?.gameObject;
- if (obj.RefGameObject != null)
+ if (!go)
{
- label += " (Destroyed)";
- }
+ string label = "null";
- label += " ";
- GUILayout.Label(label, new GUILayoutOption[0]);
- }
- else
- {
- UIHelpers.GOButton_Impl(obj.RefGameObject,
- obj.EnabledColor,
- obj.Label,
- obj.RefGameObject.activeSelf,
- SetTransformTarget,
- true,
- MainMenu.MainRect.width - 170);
+ if (go != null)
+ {
+ label += " (Destroyed)";
+ }
+
+ label += " ";
+ GUILayout.Label(label, new GUILayoutOption[0]);
+ }
+ else
+ {
+ Buttons.GameObjectButton(go, SetTransformTarget, true, MainMenu.MainRect.width - 170f);
+ }
}
+ catch { }
}
}
}
@@ -413,17 +415,11 @@ namespace Explorer
for (int i = offset; i < offset + Pages.ItemsPerPage && i < m_searchResults.Count; i++)
{
- var obj = m_searchResults[i];
+ var obj = m_searchResults[i].IValue.Value as GameObject;
- if (obj.RefGameObject)
+ if (obj)
{
- UIHelpers.GOButton_Impl(obj.RefGameObject,
- obj.EnabledColor,
- obj.Label,
- obj.RefGameObject.activeSelf,
- SetTransformTarget,
- true,
- MainMenu.MainRect.width - 170);
+ Buttons.GameObjectButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
}
else
{
@@ -436,42 +432,5 @@ namespace Explorer
GUILayout.Label("No results found! ", new GUILayoutOption[0]);
}
}
-
- // -------- Mini GameObjectCache class ---------- //
-
- public class GameObjectCache
- {
- public GameObject RefGameObject;
- public string Label;
- public Color EnabledColor;
- public int ChildCount;
-
- public GameObjectCache(GameObject obj)
- {
- RefGameObject = obj;
- ChildCount = obj.transform.childCount;
-
- Label = (ChildCount > 0) ? "[" + obj.transform.childCount + " children] " : "";
- Label += obj.name;
-
- bool enabled = obj.activeSelf;
- int childCount = obj.transform.childCount;
- if (enabled)
- {
- if (childCount > 0)
- {
- EnabledColor = Color.green;
- }
- else
- {
- EnabledColor = UIStyles.LightGreen;
- }
- }
- else
- {
- EnabledColor = Color.red;
- }
- }
- }
}
}
diff --git a/src/Menu/MainMenu/Pages/SearchPage.cs b/src/UI/Main/SearchPage.cs
similarity index 83%
rename from src/Menu/MainMenu/Pages/SearchPage.cs
rename to src/UI/Main/SearchPage.cs
index 0bc3818..5ca227d 100644
--- a/src/Menu/MainMenu/Pages/SearchPage.cs
+++ b/src/UI/Main/SearchPage.cs
@@ -4,14 +4,16 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
+using Explorer.UI.Shared;
+using Explorer.CacheObject;
-namespace Explorer
+namespace Explorer.UI.Main
{
- public class SearchPage : WindowPage
+ public class SearchPage : BaseMainMenuPage
{
public static SearchPage Instance;
- public override string Name { get => "Object Search"; }
+ public override string Name { get => "Search"; }
private string m_searchInput = "";
private string m_typeInput = "";
@@ -41,7 +43,7 @@ namespace Explorer
Custom
}
- public override void Init()
+ public override void Init()
{
Instance = this;
}
@@ -52,11 +54,9 @@ namespace Explorer
Pages.PageOffset = 0;
}
- public override void Update()
- {
- }
+ public override void Update() { }
- private void CacheResults(IEnumerable results)
+ private void CacheResults(IEnumerable results, bool isStaticClasses = false)
{
m_searchResults = new List();
@@ -76,11 +76,12 @@ namespace Explorer
}
#endif
- var cache = CacheFactory.GetTypeAndCacheObject(toCache);
+ var cache = CacheFactory.GetCacheObject(toCache);
+ cache.IsStaticClassSearchResult = isStaticClasses;
m_searchResults.Add(cache);
}
- Pages.ItemCount = m_searchResults.Count;
+ Pages.ItemCount = m_searchResults.Count;
Pages.PageOffset = 0;
}
@@ -89,12 +90,15 @@ namespace Explorer
try
{
// helpers
- GUILayout.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
GUILayout.Label("Helpers ", new GUILayoutOption[] { GUILayout.Width(70) });
if (GUILayout.Button("Find Static Instances", new GUILayoutOption[] { GUILayout.Width(180) }))
{
- //m_searchResults = GetInstanceClassScanner().ToList();
- CacheResults(GetInstanceClassScanner());
+ CacheResults(GetStaticInstances());
+ }
+ if (GUILayout.Button("Find Static Classes", new GUILayoutOption[] { GUILayout.Width(180) }))
+ {
+ CacheResults(GetStaticClasses(), true);
}
GUILayout.EndHorizontal();
@@ -102,7 +106,7 @@ namespace Explorer
SearchBox();
// results
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label("Results " + " (" + m_searchResults.Count + ")", new GUILayoutOption[0]);
@@ -110,7 +114,7 @@ namespace Explorer
int count = m_searchResults.Count;
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
Pages.DrawLimitInputArea();
@@ -165,21 +169,21 @@ namespace Explorer
private void SearchBox()
{
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
// ----- GameObject Search -----
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label("Search ", new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.UpperLeft;
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Name Contains:", new GUILayoutOption[] { GUILayout.Width(100) });
m_searchInput = GUIUnstrip.TextField(m_searchInput, new GUILayoutOption[] { GUILayout.Width(200) });
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Class Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
ClassFilterToggle(TypeFilter.Object, "Object");
@@ -189,16 +193,16 @@ namespace Explorer
GUILayout.EndHorizontal();
if (TypeMode == TypeFilter.Custom)
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.MiddleRight;
- GUILayout.Label("Custom Class:", new GUILayoutOption[] { GUILayout.Width(250) });
+ GUILayout.Label("Custom Class:", new GUILayoutOption[] { GUILayout.Width(250) });
GUI.skin.label.alignment = TextAnchor.UpperLeft;
- m_typeInput = GUIUnstrip.TextField(m_typeInput, new GUILayoutOption[] { GUILayout.Width(250) });
+ m_typeInput = GUIUnstrip.TextField(m_typeInput, new GUILayoutOption[] { GUILayout.Width(250) });
GUILayout.EndHorizontal();
}
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
- GUILayout.Label("Scene Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
+ GUILayout.Label("Scene Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
SceneFilterToggle(SceneFilter.Any, "Any", 60);
SceneFilterToggle(SceneFilter.This, "This Scene", 100);
SceneFilterToggle(SceneFilter.DontDestroy, "DontDestroyOnLoad", 140);
@@ -360,7 +364,7 @@ namespace Explorer
#if CPP
if (obj is Il2CppSystem.Object ilObject)
{
- go = ilObject.TryCast() ?? ilObject.TryCast().gameObject;
+ go = ilObject.TryCast() ?? ilObject.TryCast().gameObject;
}
#else
if (obj is GameObject || obj is Component)
@@ -395,14 +399,14 @@ namespace Explorer
private static bool FilterName(string name)
{
// Don't really want these instances.
- return !name.StartsWith("Mono")
- && !name.StartsWith("System")
- && !name.StartsWith("Il2CppSystem")
+ return !name.StartsWith("Mono")
+ && !name.StartsWith("System")
+ && !name.StartsWith("Il2CppSystem")
&& !name.StartsWith("Iced");
}
// credit: ManlyMarco (RuntimeUnityEditor)
- public static IEnumerable GetInstanceClassScanner()
+ public static IEnumerable GetStaticInstances()
{
var query = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(t => t.TryGetTypes())
@@ -457,5 +461,41 @@ namespace Explorer
}
}
}
+
+ private IEnumerable GetStaticClasses()
+ {
+ var list = new List();
+
+ var input = m_searchInput?.ToLower() ?? "";
+
+ foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ try
+ {
+ foreach (var type in asm.TryGetTypes())
+ {
+ if (!type.IsAbstract || !type.IsSealed)
+ {
+ continue;
+ }
+
+ if (!string.IsNullOrEmpty(input))
+ {
+ var typename = type.FullName.ToLower();
+
+ if (!typename.Contains(input))
+ {
+ continue;
+ }
+ }
+
+ list.Add(type);
+ }
+ }
+ catch { }
+ }
+
+ return list;
+ }
}
}
diff --git a/src/Menu/MainMenu/MainMenu.cs b/src/UI/MainMenu.cs
similarity index 84%
rename from src/Menu/MainMenu/MainMenu.cs
rename to src/UI/MainMenu.cs
index 6158459..25ffd32 100644
--- a/src/Menu/MainMenu/MainMenu.cs
+++ b/src/UI/MainMenu.cs
@@ -3,8 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
+using Explorer.Config;
+using Explorer.UI.Main;
+using Explorer.UI.Shared;
+using Explorer.UI.Inspectors;
-namespace Explorer
+namespace Explorer.UI
{
public class MainMenu
{
@@ -32,7 +36,7 @@ namespace Explorer
public const int MainWindowID = 5000;
public static Rect MainRect = new Rect(5, 5, ModConfig.Instance.Default_Window_Size.x, ModConfig.Instance.Default_Window_Size.y);
- public static readonly List Pages = new List();
+ public static readonly List Pages = new List();
private static int m_currentPage = 0;
public static void SetCurrentPage(int index)
@@ -86,7 +90,7 @@ namespace Explorer
private void MainHeader()
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
for (int i = 0; i < Pages.Count; i++)
{
if (m_currentPage == i)
@@ -101,15 +105,15 @@ namespace Explorer
}
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUI.color = Color.white;
InspectUnderMouse.EnableInspect = GUILayout.Toggle(InspectUnderMouse.EnableInspect, "Inspect Under Mouse (Shift + RMB)", new GUILayoutOption[0]);
- bool mouseState = CursorControl.ForceUnlockMouse;
+ bool mouseState = ForceUnlockCursor.Unlock;
bool setMouse = GUILayout.Toggle(mouseState, "Force Unlock Mouse (Left Alt)", new GUILayoutOption[0]);
- if (setMouse != mouseState) CursorControl.ForceUnlockMouse = setMouse;
+ if (setMouse != mouseState) ForceUnlockCursor.Unlock = setMouse;
- WindowManager.TabView = GUILayout.Toggle(WindowManager.TabView, "Tab View", new GUILayoutOption[0]);
+ //WindowManager.TabView = GUILayout.Toggle(WindowManager.TabView, "Tab View", new GUILayoutOption[0]);
GUILayout.EndHorizontal();
//GUIUnstrip.Space(10);
diff --git a/src/Menu/UIHelpers.cs b/src/UI/Shared/Buttons.cs
similarity index 52%
rename from src/Menu/UIHelpers.cs
rename to src/UI/Shared/Buttons.cs
index a41790f..8d7007d 100644
--- a/src/Menu/UIHelpers.cs
+++ b/src/UI/Shared/Buttons.cs
@@ -1,34 +1,44 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
using UnityEngine;
using Object = UnityEngine.Object;
-namespace Explorer
+namespace Explorer.UI.Shared
{
- public class UIHelpers
+ public class Buttons
{
- // helper for "Instantiate" button on UnityEngine.Objects
public static void InstantiateButton(Object obj, float width = 100)
{
if (GUILayout.Button("Instantiate", new GUILayoutOption[] { GUILayout.Width(width) }))
{
var newobj = Object.Instantiate(obj);
-
WindowManager.InspectObject(newobj, out _);
}
}
- // helper for drawing a styled button for a GameObject or Transform
- public static void GOButton(object _obj, Action specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
+ public static void InspectButton(object obj)
{
- var obj = (_obj as GameObject) ?? (_obj as Transform).gameObject;
+ if (GUILayout.Button("Inspect", new GUILayoutOption[0]))
+ {
+ WindowManager.InspectObject(obj, out bool _);
+ }
+ }
- bool hasChild = obj.transform.childCount > 0;
+ public static void GameObjectButton(object _obj, Action inspectOverride = null, bool showSmallInspect = true, float width = 380)
+ {
+ var go = (_obj as GameObject) ?? (_obj as Transform).gameObject;
- string label = hasChild ? $"[{obj.transform.childCount} children] " : "";
- label += obj.name;
+ if (!go) return;
- bool enabled = obj.activeSelf;
- int childCount = obj.transform.childCount;
+ bool hasChild = go.transform.childCount > 0;
+
+ string label = hasChild ? $"[{go.transform.childCount} children] " : "";
+ label += go.name;
+
+ bool enabled = go.activeSelf;
+ int childCount = go.transform.childCount;
Color color;
if (enabled)
@@ -47,39 +57,26 @@ namespace Explorer
color = Color.red;
}
- GOButton_Impl(_obj, color, label, obj.activeSelf, specialInspectMethod, showSmallInspectBtn, width);
- }
-
- public static void GOButton_Impl(object _obj, Color activeColor, string label, bool enabled, Action specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
- {
- var obj = _obj as GameObject ?? (_obj as Transform).gameObject;
-
- if (!obj)
- {
- GUILayout.Label("null ", new GUILayoutOption[0]);
- return;
- }
-
// ------ toggle active button ------
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUI.skin.button.alignment = TextAnchor.UpperLeft;
- GUI.color = activeColor;
+ GUI.color = color;
enabled = GUILayout.Toggle(enabled, "", new GUILayoutOption[] { GUILayout.Width(18) });
- if (obj.activeSelf != enabled)
+ if (go.activeSelf != enabled)
{
- obj.SetActive(enabled);
+ go.SetActive(enabled);
}
// ------- actual button ---------
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Height(22), GUILayout.Width(width) }))
{
- if (specialInspectMethod != null)
+ if (inspectOverride != null)
{
- specialInspectMethod(obj.transform);
+ inspectOverride(go.transform);
}
else
{
@@ -92,20 +89,12 @@ namespace Explorer
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
GUI.color = Color.white;
- if (showSmallInspectBtn)
+ if (showSmallInspect)
{
- SmallInspectButton(_obj);
+ InspectButton(_obj);
}
GUILayout.EndHorizontal();
}
-
- public static void SmallInspectButton(object obj)
- {
- if (GUILayout.Button("Inspect", new GUILayoutOption[0]))
- {
- WindowManager.InspectObject(obj, out bool _);
- }
- }
}
}
diff --git a/src/CachedObjects/IExpandHeight.cs b/src/UI/Shared/IExpandHeight.cs
similarity index 68%
rename from src/CachedObjects/IExpandHeight.cs
rename to src/UI/Shared/IExpandHeight.cs
index f0cf45a..685dbd5 100644
--- a/src/CachedObjects/IExpandHeight.cs
+++ b/src/UI/Shared/IExpandHeight.cs
@@ -3,6 +3,6 @@
interface IExpandHeight
{
bool IsExpanded { get; set; }
- float WhiteSpace { get; set; }
+ float WhiteSpace { get; set; }
}
}
diff --git a/src/Helpers/PageHelper.cs b/src/UI/Shared/PageHelper.cs
similarity index 93%
rename from src/Helpers/PageHelper.cs
rename to src/UI/Shared/PageHelper.cs
index e7d7250..989cf50 100644
--- a/src/Helpers/PageHelper.cs
+++ b/src/UI/Shared/PageHelper.cs
@@ -1,6 +1,6 @@
using UnityEngine;
-namespace Explorer
+namespace Explorer.UI.Shared
{
public enum Turn
{
@@ -21,9 +21,9 @@ namespace Explorer
CalculateMaxOffset();
}
}
- private int m_itemsPerPage = ModConfig.Instance.Default_Page_Limit;
+ private int m_itemsPerPage = Config.ModConfig.Instance.Default_Page_Limit;
- public int ItemCount
+ public int ItemCount
{
get => m_count;
set
@@ -61,7 +61,7 @@ namespace Explorer
{
if (direction == Turn.Left)
{
- if (PageOffset > 0)
+ if (PageOffset > 0)
{
PageOffset--;
scroll = Vector2.zero;
diff --git a/src/Menu/ResizeDrag.cs b/src/UI/Shared/ResizeDrag.cs
similarity index 93%
rename from src/Menu/ResizeDrag.cs
rename to src/UI/Shared/ResizeDrag.cs
index 5843b50..24a649e 100644
--- a/src/Menu/ResizeDrag.cs
+++ b/src/UI/Shared/ResizeDrag.cs
@@ -4,7 +4,7 @@ using UnhollowerBaseLib;
#endif
using UnityEngine;
-namespace Explorer
+namespace Explorer.UI.Shared
{
public class ResizeDrag
{
@@ -26,7 +26,7 @@ namespace Explorer
try
{
- GUILayout.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
#if ML
@@ -35,8 +35,7 @@ namespace Explorer
GUILayout.Button("<-- Drag to resize -->", new GUILayoutOption[] { GUILayout.Height(15) });
#endif
- //var r = GUILayoutUtility.GetLastRect();
- var r = Internal_LayoutUtility.GetLastRect();
+ var r = GUIUnstrip.GetLastRect();
var mousePos = InputManager.MousePosition;
@@ -62,7 +61,7 @@ namespace Explorer
_rect.yMax = Mathf.Min(Screen.height, _rect.yMax); // modifying yMax affects height, not y
}
}
- catch
+ catch
{
// throw safe Managed exception
throw new Exception("");
@@ -87,7 +86,7 @@ namespace Explorer
}
else
{
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Resize window:", new GUILayoutOption[] { GUILayout.Width(100) });
@@ -117,7 +116,7 @@ namespace Explorer
#else // mono
- GUILayout.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
diff --git a/src/UI/Shared/Syntax.cs b/src/UI/Shared/Syntax.cs
new file mode 100644
index 0000000..ff8de3c
--- /dev/null
+++ b/src/UI/Shared/Syntax.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Explorer.UI.Shared
+{
+ public class Syntax
+ {
+ public const string Field_Static = "#8d8dc6";
+ public const string Field_Instance = "#c266ff";
+
+ public const string Method_Static = "#b55b02";
+ public const string Method_Instance = "#ff8000";
+
+ public const string Prop_Static = "#588075";
+ public const string Prop_Instance = "#55a38e";
+
+ public const string Class_Static = "#3a8d71";
+ public const string Class_Instance = "#2df7b2";
+
+ public const string Local = "#a6e9e9";
+
+ public const string StructGreen = "#92c470";
+ }
+}
diff --git a/src/Menu/UIStyles.cs b/src/UI/Shared/UIStyles.cs
similarity index 84%
rename from src/Menu/UIStyles.cs
rename to src/UI/Shared/UIStyles.cs
index b66e9fa..7959be1 100644
--- a/src/Menu/UIStyles.cs
+++ b/src/UI/Shared/UIStyles.cs
@@ -1,29 +1,10 @@
using UnityEngine;
using Object = UnityEngine.Object;
-namespace Explorer
+namespace Explorer.UI.Shared
{
public class UIStyles
{
- public class Syntax
- {
- public const string Field_Static = "#8d8dc6";
- public const string Field_Instance = "#c266ff";
-
- public const string Method_Static = "#b55b02";
- public const string Method_Instance = "#ff8000";
-
- public const string Prop_Static = "#588075";
- public const string Prop_Instance = "#55a38e";
-
- public const string Class_Static = "#3a8d71";
- public const string Class_Instance = "#2df7b2";
-
- public const string Local = "#a6e9e9";
-
- public const string StructGreen = "#92c470";
- }
-
public static Color LightGreen = new Color(Color.green.r - 0.3f, Color.green.g - 0.3f, Color.green.b - 0.3f);
public static GUISkin WindowSkin
diff --git a/src/Menu/Windows/TabViewWindow.cs b/src/UI/TabViewWindow.cs
similarity index 80%
rename from src/Menu/Windows/TabViewWindow.cs
rename to src/UI/TabViewWindow.cs
index 95a61d4..ec16055 100644
--- a/src/Menu/Windows/TabViewWindow.cs
+++ b/src/UI/TabViewWindow.cs
@@ -1,15 +1,17 @@
-using UnityEngine;
+using System;
+using UnityEngine;
+using Explorer.UI.Shared;
-namespace Explorer
+namespace Explorer.UI
{
- public class TabViewWindow : UIWindow
+ public class TabViewWindow : WindowBase
{
public override string Title => $"Tabs ({WindowManager.Windows.Count})";
public static TabViewWindow Instance => m_instance ?? (m_instance = new TabViewWindow());
private static TabViewWindow m_instance;
- private UIWindow m_targetWindow;
+ private WindowBase m_targetWindow;
public int TargetTabID = 0;
public override bool IsTabViewWindow => true;
@@ -21,7 +23,7 @@ namespace Explorer
public override void Init() { }
- public override void Update()
+ public override void Update()
{
while (TargetTabID >= WindowManager.Windows.Count)
{
@@ -35,7 +37,7 @@ namespace Explorer
if (TargetTabID >= 0)
{
- m_targetWindow = WindowManager.Windows[TargetTabID];
+ m_targetWindow = WindowManager.Windows[TargetTabID];
}
else
{
@@ -61,8 +63,8 @@ namespace Explorer
GUIUnstrip.BeginArea(new Rect(5, 25, m_rect.width - 10, m_rect.height - 35), GUI.skin.box);
- GUILayout.BeginVertical(GUIContent.none, GUI.skin.box, null);
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
int tabPerRow = Mathf.FloorToInt((float)((decimal)m_rect.width / 238));
int rowCount = 0;
@@ -72,7 +74,7 @@ namespace Explorer
{
rowCount = 0;
GUILayout.EndHorizontal();
- GUILayout.BeginHorizontal(new GUILayoutOption[0]);
+ GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
}
rowCount++;
@@ -97,15 +99,18 @@ namespace Explorer
m_targetWindow.WindowFunction(m_targetWindow.windowID);
- try
- {
- m_rect = ResizeDrag.ResizeWindow(m_rect, windowID);
- }
- catch { }
+ m_rect = ResizeDrag.ResizeWindow(m_rect, windowID);
GUIUnstrip.EndArea();
}
- catch { }
+ catch (Exception e)
+ {
+ if (!e.Message.Contains("in a group with only"))
+ {
+ ExplorerCore.Log("Exception drawing Tab View window: " + e.GetType() + ", " + e.Message);
+ ExplorerCore.Log(e.StackTrace);
+ }
+ }
}
}
}
diff --git a/src/Menu/Windows/UIWindow.cs b/src/UI/WindowBase.cs
similarity index 69%
rename from src/Menu/Windows/UIWindow.cs
rename to src/UI/WindowBase.cs
index d387e83..b42136b 100644
--- a/src/Menu/Windows/UIWindow.cs
+++ b/src/UI/WindowBase.cs
@@ -1,16 +1,18 @@
using System;
using UnityEngine;
+using Explorer.Config;
+using Explorer.UI.Inspectors;
-namespace Explorer
+namespace Explorer.UI
{
- public abstract class UIWindow
+ public abstract class WindowBase
{
public abstract string Title { get; }
public object Target;
public int windowID;
- public Rect m_rect = new Rect(0,0, ModConfig.Instance.Default_Window_Size.x,ModConfig.Instance.Default_Window_Size.y);
+ public Rect m_rect = new Rect(0, 0, ModConfig.Instance.Default_Window_Size.x, ModConfig.Instance.Default_Window_Size.y);
public Vector2 scroll = Vector2.zero;
@@ -20,7 +22,7 @@ namespace Explorer
public abstract void WindowFunction(int windowID);
public abstract void Update();
- public static UIWindow CreateWindow(object target) where T : UIWindow
+ public static WindowBase CreateWindow(object target) where T : WindowBase
{
var window = Activator.CreateInstance();
@@ -35,6 +37,22 @@ namespace Explorer
return window;
}
+ public static StaticInspector CreateWindowStatic(Type type)
+ {
+ var window = new StaticInspector
+ {
+ TargetType = type,
+ windowID = WindowManager.NextWindowID(),
+ m_rect = WindowManager.GetNewWindowRect()
+ };
+
+ WindowManager.Windows.Add(window);
+
+ window.Init();
+
+ return window;
+ }
+
public void DestroyWindow()
{
WindowManager.DestroyWindow(this);
diff --git a/src/Menu/Windows/WindowManager.cs b/src/UI/WindowManager.cs
similarity index 80%
rename from src/Menu/Windows/WindowManager.cs
rename to src/UI/WindowManager.cs
index 58194eb..c07627c 100644
--- a/src/Menu/Windows/WindowManager.cs
+++ b/src/UI/WindowManager.cs
@@ -1,90 +1,40 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using UnityEngine;
+using Explorer.UI.Inspectors;
-namespace Explorer
+namespace Explorer.UI
{
public class WindowManager
{
public static WindowManager Instance;
- public static bool TabView = true;
+ public static bool TabView = Config.ModConfig.Instance.Tab_View;
- public static List Windows = new List();
+ public static List Windows = new List();
public static int CurrentWindowID { get; set; } = 500000;
private static Rect m_lastWindowRect;
- private static readonly List m_windowsToDestroy = new List();
+ private static readonly List m_windowsToDestroy = new List();
public WindowManager()
{
Instance = this;
}
- public static void DestroyWindow(UIWindow window)
+ public static void DestroyWindow(WindowBase window)
{
m_windowsToDestroy.Add(window);
}
- public void Update()
- {
- if (m_windowsToDestroy.Count > 0)
- {
- foreach (var window in m_windowsToDestroy)
- {
- if (Windows.Contains(window))
- {
- Windows.Remove(window);
- }
- }
-
- m_windowsToDestroy.Clear();
- }
-
- if (TabView)
- {
- TabViewWindow.Instance.Update();
- }
- else
- {
- for (int i = 0; i < Windows.Count; i++)
- {
- var window = Windows[i];
- if (window != null)
- {
- window.Update();
- }
- }
- }
- }
-
- public void OnGUI()
- {
- if (TabView)
- {
- if (Windows.Count > 0)
- {
- TabViewWindow.Instance.OnGUI();
- }
- }
- else
- {
- foreach (var window in Windows)
- {
- window.OnGUI();
- }
- }
- }
-
- // ========= Public Helpers =========
-
- public static UIWindow InspectObject(object obj, out bool createdNew, bool forceReflection = false)
+ public static WindowBase InspectObject(object obj, out bool createdNew, bool forceReflection = false)
{
createdNew = false;
- if (InputManager.GetKey(KeyCode.LeftShift))
- {
- forceReflection = true;
- }
+ //if (InputManager.GetKey(KeyCode.LeftShift))
+ //{
+ // forceReflection = true;
+ //}
#if CPP
Il2CppSystem.Object iObj = null;
@@ -136,7 +86,7 @@ namespace Explorer
}
}
- private static void FocusWindow(UIWindow window)
+ private static void FocusWindow(WindowBase window)
{
if (!TabView)
{
@@ -149,23 +99,29 @@ namespace Explorer
}
}
- private static UIWindow InspectGameObject(GameObject obj)
+ private static WindowBase InspectGameObject(GameObject obj)
{
- var new_window = UIWindow.CreateWindow(obj);
+ var new_window = WindowBase.CreateWindow(obj);
FocusWindow(new_window);
return new_window;
}
- private static UIWindow InspectReflection(object obj)
+ private static WindowBase InspectReflection(object obj)
{
- var new_window = UIWindow.CreateWindow(obj);
+ var new_window = WindowBase.CreateWindow(obj);
FocusWindow(new_window);
return new_window;
}
- // === Misc Helpers ===
+ public static StaticInspector InspectStaticReflection(Type type)
+ {
+ var new_window = WindowBase.CreateWindowStatic(type);
+ FocusWindow(new_window);
+
+ return new_window;
+ }
public static bool IsMouseInWindow
{
@@ -222,5 +178,57 @@ namespace Explorer
return rect;
}
+
+ // ============= instance methods ===============
+
+ public void Update()
+ {
+ if (m_windowsToDestroy.Count > 0)
+ {
+ foreach (var window in m_windowsToDestroy)
+ {
+ if (Windows.Contains(window))
+ {
+ Windows.Remove(window);
+ }
+ }
+
+ m_windowsToDestroy.Clear();
+ }
+
+ if (TabView)
+ {
+ TabViewWindow.Instance.Update();
+ }
+ else
+ {
+ for (int i = 0; i < Windows.Count; i++)
+ {
+ var window = Windows[i];
+ if (window != null)
+ {
+ window.Update();
+ }
+ }
+ }
+ }
+
+ public void OnGUI()
+ {
+ if (TabView)
+ {
+ if (Windows.Count > 0)
+ {
+ TabViewWindow.Instance.OnGUI();
+ }
+ }
+ else
+ {
+ foreach (var window in Windows)
+ {
+ window.OnGUI();
+ }
+ }
+ }
}
}
diff --git a/src/UnstripFixes/GUIUnstrip.cs b/src/UnstripFixes/GUIUnstrip.cs
index 9f4407f..d34accc 100644
--- a/src/UnstripFixes/GUIUnstrip.cs
+++ b/src/UnstripFixes/GUIUnstrip.cs
@@ -4,14 +4,52 @@ using System.Reflection;
using UnityEngine;
#if CPP
using Explorer.UnstripInternals;
-using UnityEngineInternal;
-using UnhollowerRuntimeLib;
#endif
namespace Explorer
{
public class GUIUnstrip
{
+ public static void BeginHorizontal(params GUILayoutOption[] options)
+ => BeginHorizontal(GUIContent.none, GUIStyle.none, options);
+
+ public static void BeginHorizontal(GUIStyle style, params GUILayoutOption[] options)
+ => BeginHorizontal(GUIContent.none, style, options);
+
+ public static void BeginHorizontal(GUIContent content, GUIStyle style, params GUILayoutOption[] options)
+ {
+#if CPP
+ Internal.BeginLayoutDirection(false, content, style, options);
+#else
+ GUILayout.BeginHorizontal(content, style, options);
+#endif
+ }
+
+ public static void BeginVertical(params GUILayoutOption[] options)
+ => BeginVertical(GUIContent.none, GUIStyle.none, options);
+
+ public static void BeginVertical(GUIStyle style, params GUILayoutOption[] options)
+ => BeginVertical(GUIContent.none, style, options);
+
+ public static void BeginVertical(GUIContent content, GUIStyle style, params GUILayoutOption[] options)
+ {
+#if CPP
+ Internal.BeginLayoutDirection(true, content, style, options);
+#else
+ GUILayout.BeginVertical(content, style, options);
+#endif
+ }
+
+
+ public static Rect GetLastRect()
+ {
+#if CPP
+ return Internal_LayoutUtility.GetLastRect();
+#else
+ return GUILayoutUtility.GetLastRect();
+#endif
+ }
+
public static string TextField(string text, GUILayoutOption[] options)
{
#if CPP
diff --git a/src/UnstripFixes/Internal.cs b/src/UnstripFixes/Internal.cs
index cf4db8a..c7759ba 100644
--- a/src/UnstripFixes/Internal.cs
+++ b/src/UnstripFixes/Internal.cs
@@ -107,6 +107,14 @@ namespace Explorer.UnstripInternals
#region GUILayout Methods
+ public static void BeginLayoutDirection(bool vertical, GUIContent content, GUIStyle style, GUILayoutOption[] options)
+ {
+ var g = GUILayoutUtility.BeginLayoutGroup(style, options, Il2CppType.Of());
+ g.isVertical = vertical;
+ if (style != GUIStyle.none || content != GUIContent.none)
+ GUI.Box(g.rect, content, style);
+ }
+
public static string TextField(string text, GUILayoutOption[] options)
{
text = text ?? "";
diff --git a/src/UnstripFixes/Internal_LayoutUtility.cs b/src/UnstripFixes/Internal_LayoutUtility.cs
index f7d4583..b491449 100644
--- a/src/UnstripFixes/Internal_LayoutUtility.cs
+++ b/src/UnstripFixes/Internal_LayoutUtility.cs
@@ -1,8 +1,7 @@
#if CPP
using UnityEngine;
-using Explorer.UnstripInternals;
-namespace Explorer
+namespace Explorer.UnstripInternals
{
public class Internal_LayoutUtility
{
diff --git a/src/UnstripFixes/Internal_ScrollViewState.cs b/src/UnstripFixes/Internal_ScrollViewState.cs
index c1b84b9..64af6fb 100644
--- a/src/UnstripFixes/Internal_ScrollViewState.cs
+++ b/src/UnstripFixes/Internal_ScrollViewState.cs
@@ -3,7 +3,7 @@ using System;
using System.Collections.Generic;
using UnityEngine;
-namespace Explorer
+namespace Explorer.UnstripInternals
{
public class Internal_ScrollViewState
{
diff --git a/src/UnstripFixes/Internal_SliderHandler.cs b/src/UnstripFixes/Internal_SliderHandler.cs
index 9b57f31..1a458e8 100644
--- a/src/UnstripFixes/Internal_SliderHandler.cs
+++ b/src/UnstripFixes/Internal_SliderHandler.cs
@@ -5,7 +5,7 @@ using UnityEngine;
using Explorer.UnstripInternals;
using Il2CppSystem.Reflection;
-namespace Explorer
+namespace Explorer.UnstripInternals
{
public struct Internal_SliderHandler
{
diff --git a/src/UnstripFixes/Internal_SliderState.cs b/src/UnstripFixes/Internal_SliderState.cs
index 83326a3..4934e4d 100644
--- a/src/UnstripFixes/Internal_SliderState.cs
+++ b/src/UnstripFixes/Internal_SliderState.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
-namespace Explorer
+namespace Explorer.UnstripInternals
{
public class Internal_SliderState
{