mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-23 00:52:31 +08:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
9a059c1056 | |||
ffb6cad8c2 | |||
d0a4863139 | |||
bb8837d58c | |||
a236b272c1 | |||
18de1eaf1c | |||
b1264c6912 | |||
9836566e55 | |||
d20461fa0e | |||
72ec34090d | |||
883a8705c3 |
13
README.md
13
README.md
@ -14,10 +14,9 @@
|
||||
<img src="https://img.shields.io/github/downloads/sinai-dev/CppExplorer/total.svg" />
|
||||
</p>
|
||||
|
||||
### Known issue
|
||||
Some games are experiencing `MissingMethodException`s or exceptions about failed unstripping, which prevent the CppExplorer menu from showing properly or at all. This is a bug with [Il2CppAssemblyUnhollower](https://github.com/knah/Il2CppAssemblyUnhollower) and there isn't much I can do about it myself.
|
||||
|
||||
If you're familiar with C# and Unity, one possibility for now is making a fork of this repo and manually fixing all the broken methods to ones which aren't broken (if possible). There may be another overload of the same method which wasn't stripped or was unstripped successfully, which you can use instead.
|
||||
### Known issues
|
||||
* CppExplorer may experience a `MissingMethodException` when trying to use certain UnityEngine methods. If you experience this, please open an issue and I will do my best to fix it.
|
||||
* Scrolling with mouse wheel in the CppExplorer menu may not work on all games at the moment.
|
||||
|
||||
## Features
|
||||
* Scene hierarchy explorer
|
||||
@ -45,7 +44,7 @@ Requires [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) to be ins
|
||||
* 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 <b>Inspect</b> it to send it to an Inspector Window.
|
||||
|
||||
[](https://i.imgur.com/2b0q0jL.png)
|
||||
[](https://i.imgur.com/BzTOCvp.png)
|
||||
|
||||
### Inspectors
|
||||
|
||||
@ -60,7 +59,7 @@ CppExplorer has two main inspector modes: <b>GameObject Inspector</b>, and <b>Re
|
||||
* 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.
|
||||
|
||||
[](https://i.imgur.com/JTxqlx4.png)
|
||||
[](https://i.imgur.com/DiDvl0Q.png)
|
||||
|
||||
### Reflection Inspector
|
||||
|
||||
@ -68,7 +67,7 @@ CppExplorer has two main inspector modes: <b>GameObject Inspector</b>, and <b>Re
|
||||
* 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.
|
||||
|
||||
[](https://i.imgur.com/iq92m0l.png)
|
||||
[](https://i.imgur.com/Pq127XD.png)
|
||||
|
||||
### Object Search
|
||||
|
||||
|
@ -137,6 +137,22 @@ namespace Explorer
|
||||
{
|
||||
holder = new CacheEnum();
|
||||
}
|
||||
else if (valueType == typeof(Vector2) || valueType == typeof(Vector3) || valueType == typeof(Vector4))
|
||||
{
|
||||
holder = new CacheVector();
|
||||
}
|
||||
else if (valueType == typeof(Quaternion))
|
||||
{
|
||||
holder = new CacheQuaternion();
|
||||
}
|
||||
else if (valueType == typeof(Color))
|
||||
{
|
||||
holder = new CacheColor();
|
||||
}
|
||||
else if (valueType == typeof(Rect))
|
||||
{
|
||||
holder = new CacheRect();
|
||||
}
|
||||
else if (ReflectionHelpers.IsArray(valueType) || ReflectionHelpers.IsList(valueType))
|
||||
{
|
||||
holder = new CacheList();
|
||||
|
87
src/CachedObjects/Struct/CacheColor.cs
Normal file
87
src/CachedObjects/Struct/CacheColor.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class CacheColor : CacheObjectBase
|
||||
{
|
||||
private string r = "0";
|
||||
private string g = "0";
|
||||
private string b = "0";
|
||||
private string a = "0";
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
var color = (Color)Value;
|
||||
|
||||
r = color.r.ToString();
|
||||
g = color.g.ToString();
|
||||
b = color.b.ToString();
|
||||
a = color.a.ToString();
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
GUILayout.Label($"<color=yellow>Color</color>: {((Color)Value).ToString()}", null);
|
||||
|
||||
if (CanWrite)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
var whitespace = window.width - width - 90;
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("R:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
r = GUILayout.TextField(r, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("G:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
g = GUILayout.TextField(g, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("B:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
b = GUILayout.TextField(b, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("A:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
a = GUILayout.TextField(a, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// draw set value button
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||
{
|
||||
SetValueFromInput();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValueFromInput()
|
||||
{
|
||||
if (float.TryParse(r, out float fR)
|
||||
&& float.TryParse(g, out float fG)
|
||||
&& float.TryParse(b, out float fB)
|
||||
&& float.TryParse(a, out float fA))
|
||||
{
|
||||
Value = new Color(fR, fB, fG, fA);
|
||||
SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ namespace Explorer
|
||||
{
|
||||
public class CachePrimitive : CacheObjectBase
|
||||
{
|
||||
public enum PrimitiveTypes
|
||||
public enum Types
|
||||
{
|
||||
Bool,
|
||||
Double,
|
||||
@ -20,20 +20,9 @@ namespace Explorer
|
||||
|
||||
private string m_valueToString;
|
||||
|
||||
public PrimitiveTypes PrimitiveType;
|
||||
|
||||
public MethodInfo ParseMethod
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_parseMethod == null)
|
||||
{
|
||||
m_parseMethod = Value.GetType().GetMethod("Parse", new Type[] { typeof(string) });
|
||||
}
|
||||
return m_parseMethod;
|
||||
}
|
||||
}
|
||||
public Types PrimitiveType;
|
||||
|
||||
public MethodInfo ParseMethod => m_parseMethod ?? (m_parseMethod = Value.GetType().GetMethod("Parse", new Type[] { typeof(string) }));
|
||||
private MethodInfo m_parseMethod;
|
||||
|
||||
public override void Init()
|
||||
@ -41,58 +30,39 @@ namespace Explorer
|
||||
if (Value == null)
|
||||
{
|
||||
// this must mean it is a string. No other primitive type should be nullable.
|
||||
PrimitiveType = PrimitiveTypes.String;
|
||||
PrimitiveType = Types.String;
|
||||
return;
|
||||
}
|
||||
|
||||
m_valueToString = Value.ToString();
|
||||
var type = Value.GetType();
|
||||
|
||||
var type = Value.GetType();
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
PrimitiveType = PrimitiveTypes.Bool;
|
||||
PrimitiveType = Types.Bool;
|
||||
}
|
||||
else if (type == typeof(double))
|
||||
{
|
||||
PrimitiveType = PrimitiveTypes.Double;
|
||||
PrimitiveType = Types.Double;
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
PrimitiveType = PrimitiveTypes.Float;
|
||||
}
|
||||
else if (IsInteger(type))
|
||||
{
|
||||
PrimitiveType = PrimitiveTypes.Int;
|
||||
PrimitiveType = Types.Float;
|
||||
}
|
||||
else if (type == typeof(char))
|
||||
{
|
||||
PrimitiveType = PrimitiveTypes.Char;
|
||||
PrimitiveType = Types.Char;
|
||||
}
|
||||
else if (typeof(int).IsAssignableFrom(type))
|
||||
{
|
||||
PrimitiveType = Types.Int;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimitiveType = PrimitiveTypes.String;
|
||||
PrimitiveType = Types.String;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsInteger(Type type)
|
||||
{
|
||||
// For our purposes, all types of int can be treated the same, including IntPtr.
|
||||
return _integerTypes.Contains(type);
|
||||
}
|
||||
|
||||
private static readonly HashSet<Type> _integerTypes = new HashSet<Type>
|
||||
{
|
||||
typeof(int),
|
||||
typeof(uint),
|
||||
typeof(short),
|
||||
typeof(ushort),
|
||||
typeof(long),
|
||||
typeof(ulong),
|
||||
typeof(byte),
|
||||
typeof(sbyte),
|
||||
typeof(IntPtr)
|
||||
};
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
@ -102,11 +72,10 @@ namespace Explorer
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (PrimitiveType == PrimitiveTypes.Bool)
|
||||
if (PrimitiveType == Types.Bool)
|
||||
{
|
||||
var b = (bool)Value;
|
||||
var color = $"<color={(b ? "lime>" : "red>")}";
|
||||
var label = $"{color}{b}</color>";
|
||||
var label = $"<color={(b ? "lime" : "red")}>{b}</color>";
|
||||
|
||||
if (CanWrite)
|
||||
{
|
||||
@ -150,7 +119,7 @@ namespace Explorer
|
||||
}
|
||||
}
|
||||
|
||||
public void SetValueFromInput(string value)
|
||||
public void SetValueFromInput(string valueString)
|
||||
{
|
||||
if (MemInfo == null)
|
||||
{
|
||||
@ -158,16 +127,15 @@ namespace Explorer
|
||||
return;
|
||||
}
|
||||
|
||||
if (PrimitiveType == PrimitiveTypes.String)
|
||||
if (PrimitiveType == Types.String)
|
||||
{
|
||||
Value = value;
|
||||
Value = valueString;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var val = ParseMethod.Invoke(null, new object[] { value });
|
||||
Value = val;
|
||||
Value = ParseMethod.Invoke(null, new object[] { valueString });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
78
src/CachedObjects/Struct/CacheQuaternion.cs
Normal file
78
src/CachedObjects/Struct/CacheQuaternion.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class CacheQuaternion : CacheObjectBase
|
||||
{
|
||||
private string x = "0";
|
||||
private string y = "0";
|
||||
private string z = "0";
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
var euler = ((Quaternion)Value).eulerAngles;
|
||||
|
||||
x = euler.x.ToString();
|
||||
y = euler.y.ToString();
|
||||
z = euler.z.ToString();
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
GUILayout.Label($"<color=yellow>Quaternion</color>: {((Quaternion)Value).eulerAngles.ToString()}", null);
|
||||
|
||||
if (CanWrite)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
var whitespace = window.width - width - 90;
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// draw set value button
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||
{
|
||||
SetValueFromInput();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValueFromInput()
|
||||
{
|
||||
if (float.TryParse(x, out float fX)
|
||||
&& float.TryParse(y, out float fY)
|
||||
&& float.TryParse(z, out float fZ))
|
||||
{
|
||||
Value = Quaternion.Euler(new Vector3(fX, fY, fZ));
|
||||
SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
87
src/CachedObjects/Struct/CacheRect.cs
Normal file
87
src/CachedObjects/Struct/CacheRect.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class CacheRect : CacheObjectBase
|
||||
{
|
||||
private string x = "0";
|
||||
private string y = "0";
|
||||
private string w = "0";
|
||||
private string h = "0";
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
var rect = (Rect)Value;
|
||||
|
||||
x = rect.x.ToString();
|
||||
y = rect.y.ToString();
|
||||
w = rect.width.ToString();
|
||||
h = rect.height.ToString();
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
GUILayout.Label($"<color=yellow>Rect</color>: {((Rect)Value).ToString()}", null);
|
||||
|
||||
if (CanWrite)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
var whitespace = window.width - width - 90;
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("H:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
h = GUILayout.TextField(h, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// draw set value button
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||
{
|
||||
SetValueFromInput();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValueFromInput()
|
||||
{
|
||||
if (float.TryParse(x, out float fX)
|
||||
&& float.TryParse(y, out float fY)
|
||||
&& float.TryParse(w, out float fW)
|
||||
&& float.TryParse(h, out float fH))
|
||||
{
|
||||
Value = new Rect(fX, fY, fW, fH);
|
||||
SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
142
src/CachedObjects/Struct/CacheVector.cs
Normal file
142
src/CachedObjects/Struct/CacheVector.cs
Normal file
@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public class CacheVector : CacheObjectBase
|
||||
{
|
||||
public int VectorSize = 2;
|
||||
|
||||
private string x = "0";
|
||||
private string y = "0";
|
||||
private string z = "0";
|
||||
private string w = "0";
|
||||
|
||||
private MethodInfo m_toStringMethod;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
if (Value is Vector2)
|
||||
{
|
||||
VectorSize = 2;
|
||||
}
|
||||
else if (Value is Vector3)
|
||||
{
|
||||
VectorSize = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSize = 4;
|
||||
}
|
||||
|
||||
m_toStringMethod = Value.GetType().GetMethod("ToString", new Type[0]);
|
||||
}
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
if (Value is Vector2 vec2)
|
||||
{
|
||||
x = vec2.x.ToString();
|
||||
y = vec2.y.ToString();
|
||||
}
|
||||
else if (Value is Vector3 vec3)
|
||||
{
|
||||
x = vec3.x.ToString();
|
||||
y = vec3.y.ToString();
|
||||
z = vec3.z.ToString();
|
||||
}
|
||||
else if (Value is Vector4 vec4)
|
||||
{
|
||||
x = vec4.x.ToString();
|
||||
y = vec4.y.ToString();
|
||||
z = vec4.z.ToString();
|
||||
w = vec4.w.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
GUILayout.Label($"<color=yellow>Vector{VectorSize}</color>: {(string)m_toStringMethod.Invoke(Value, new object[0])}", null);
|
||||
|
||||
if (CanWrite)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
var whitespace = window.width - width - 90;
|
||||
|
||||
// always draw x and y
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (VectorSize > 2)
|
||||
{
|
||||
// draw z
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
if (VectorSize > 3)
|
||||
{
|
||||
// draw w
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
// draw set value button
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Space(whitespace);
|
||||
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||
{
|
||||
SetValueFromInput();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValueFromInput()
|
||||
{
|
||||
if (float.TryParse(x, out float fX)
|
||||
&& float.TryParse(y, out float fY)
|
||||
&& float.TryParse(z, out float fZ)
|
||||
&& float.TryParse(w, out float fW))
|
||||
{
|
||||
object vector = null;
|
||||
|
||||
switch (VectorSize)
|
||||
{
|
||||
case 2: vector = new Vector2(fX, fY); break;
|
||||
case 3: vector = new Vector3(fX, fY, fZ); break;
|
||||
case 4: vector = new Vector4(fX, fY, fZ, fW); break;
|
||||
}
|
||||
|
||||
if (vector != null)
|
||||
{
|
||||
Value = vector;
|
||||
SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ namespace Explorer
|
||||
public class CppExplorer : MelonMod
|
||||
{
|
||||
public const string GUID = "com.sinai.cppexplorer";
|
||||
public const string VERSION = "1.5.4";
|
||||
public const string VERSION = "1.5.7";
|
||||
public const string AUTHOR = "Sinai";
|
||||
|
||||
public const string NAME = "CppExplorer"
|
||||
|
@ -120,17 +120,21 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CachedObjects\CacheDictionary.cs" />
|
||||
<Compile Include="CachedObjects\CacheEnum.cs" />
|
||||
<Compile Include="CachedObjects\CacheGameObject.cs" />
|
||||
<Compile Include="CachedObjects\CacheList.cs" />
|
||||
<Compile Include="CachedObjects\CachePrimitive.cs" />
|
||||
<Compile Include="CachedObjects\CacheOther.cs" />
|
||||
<Compile Include="CachedObjects\CacheMethod.cs" />
|
||||
<Compile Include="CachedObjects\Struct\CacheColor.cs" />
|
||||
<Compile Include="CachedObjects\Object\CacheDictionary.cs" />
|
||||
<Compile Include="CachedObjects\Struct\CacheEnum.cs" />
|
||||
<Compile Include="CachedObjects\Object\CacheGameObject.cs" />
|
||||
<Compile Include="CachedObjects\Object\CacheList.cs" />
|
||||
<Compile Include="CachedObjects\Struct\CachePrimitive.cs" />
|
||||
<Compile Include="CachedObjects\Other\CacheOther.cs" />
|
||||
<Compile Include="CachedObjects\Other\CacheMethod.cs" />
|
||||
<Compile Include="CachedObjects\Struct\CacheQuaternion.cs" />
|
||||
<Compile Include="CachedObjects\Struct\CacheVector.cs" />
|
||||
<Compile Include="CachedObjects\Struct\CacheRect.cs" />
|
||||
<Compile Include="CppExplorer.cs" />
|
||||
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
||||
<Compile Include="Unstripping\GUIUnstrip.cs" />
|
||||
<Compile Include="Unstripping\ScrollViewStateUnstrip.cs" />
|
||||
<Compile Include="UnstripFixes\GUIUnstrip.cs" />
|
||||
<Compile Include="UnstripFixes\ScrollViewStateUnstrip.cs" />
|
||||
<Compile Include="Extensions\UnityExtensions.cs" />
|
||||
<Compile Include="Helpers\PageHelper.cs" />
|
||||
<Compile Include="Helpers\ReflectionHelpers.cs" />
|
||||
@ -138,8 +142,8 @@
|
||||
<Compile Include="Helpers\UnityHelpers.cs" />
|
||||
<Compile Include="MainMenu\InspectUnderMouse.cs" />
|
||||
<Compile Include="CachedObjects\CacheObjectBase.cs" />
|
||||
<Compile Include="Unstripping\SliderHandlerUnstrip.cs" />
|
||||
<Compile Include="Unstripping\UnstripExtensions.cs" />
|
||||
<Compile Include="UnstripFixes\SliderHandlerUnstrip.cs" />
|
||||
<Compile Include="UnstripFixes\UnstripExtensions.cs" />
|
||||
<Compile Include="Windows\ResizeDrag.cs" />
|
||||
<Compile Include="Windows\TabViewWindow.cs" />
|
||||
<Compile Include="Windows\UIWindow.cs" />
|
||||
|
@ -14,7 +14,7 @@ namespace Explorer
|
||||
{
|
||||
public class ConsolePage : WindowPage
|
||||
{
|
||||
public override string Name { get => "C# Console"; set => base.Name = value; }
|
||||
public override string Name { get => "C# Console"; }
|
||||
|
||||
private ScriptEvaluator _evaluator;
|
||||
private readonly StringBuilder _sb = new StringBuilder();
|
||||
|
@ -12,19 +12,22 @@ namespace Explorer
|
||||
{
|
||||
public static ScenePage Instance;
|
||||
|
||||
public override string Name { get => "Scene Explorer"; set => base.Name = value; }
|
||||
public override string Name { get => "Scene Explorer"; }
|
||||
|
||||
public PageHelper Pages = new PageHelper();
|
||||
|
||||
private float m_timeOfLastUpdate = -1f;
|
||||
private const int PASSIVE_UPDATE_INTERVAL = 1;
|
||||
|
||||
// ----- Holders for GUI elements ----- //
|
||||
private static bool m_getRootObjectsFailed;
|
||||
|
||||
private string m_currentScene = "";
|
||||
// ----- Holders for GUI elements ----- //
|
||||
|
||||
private static string m_currentScene = "";
|
||||
|
||||
// gameobject list
|
||||
private Transform m_currentTransform;
|
||||
private List<GameObjectCache> m_objectList = new List<GameObjectCache>();
|
||||
private readonly List<GameObjectCache> m_objectList = new List<GameObjectCache>();
|
||||
|
||||
// search bar
|
||||
private bool m_searching = false;
|
||||
@ -44,59 +47,6 @@ namespace Explorer
|
||||
SetTransformTarget(null);
|
||||
}
|
||||
|
||||
//public void CheckOffset(ref int offset, int childCount)
|
||||
//{
|
||||
// if (offset >= childCount)
|
||||
// {
|
||||
// offset = 0;
|
||||
// m_pageOffset = 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (m_searching) return;
|
||||
|
||||
if (Time.time - m_timeOfLastUpdate < 1f) return;
|
||||
m_timeOfLastUpdate = Time.time;
|
||||
|
||||
m_objectList = new List<GameObjectCache>();
|
||||
|
||||
var allTransforms = new List<Transform>();
|
||||
|
||||
// get current list of all transforms (either scene root or our current transform children)
|
||||
if (m_currentTransform)
|
||||
{
|
||||
for (int i = 0; i < m_currentTransform.childCount; i++)
|
||||
{
|
||||
allTransforms.Add(m_currentTransform.GetChild(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var scene = SceneManager.GetSceneByName(m_currentScene);
|
||||
var rootObjects = scene.GetRootGameObjects();
|
||||
|
||||
foreach (var obj in rootObjects)
|
||||
{
|
||||
allTransforms.Add(obj.transform);
|
||||
}
|
||||
}
|
||||
|
||||
Pages.ItemCount = allTransforms.Count;
|
||||
|
||||
int offset = Pages.CalculateOffsetIndex();
|
||||
|
||||
// sort by childcount
|
||||
allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||
|
||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < Pages.ItemCount; i++)
|
||||
{
|
||||
var child = allTransforms[i];
|
||||
m_objectList.Add(new GameObjectCache(child.gameObject));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTransformTarget(Transform t)
|
||||
{
|
||||
m_currentTransform = t;
|
||||
@ -104,8 +54,7 @@ namespace Explorer
|
||||
if (m_searching)
|
||||
CancelSearch();
|
||||
|
||||
m_timeOfLastUpdate = -1f;
|
||||
Update();
|
||||
Update_Impl(true);
|
||||
}
|
||||
|
||||
public void TraverseUp()
|
||||
@ -130,23 +79,118 @@ namespace Explorer
|
||||
public void CancelSearch()
|
||||
{
|
||||
m_searching = false;
|
||||
|
||||
if (m_getRootObjectsFailed && !m_currentTransform)
|
||||
{
|
||||
GetRootObjectsManual_Impl();
|
||||
}
|
||||
}
|
||||
|
||||
public List<GameObjectCache> SearchSceneObjects(string _search)
|
||||
{
|
||||
var matches = new List<GameObjectCache>();
|
||||
|
||||
foreach (var obj in Resources.FindObjectsOfTypeAll<GameObject>())
|
||||
foreach (var obj in Resources.FindObjectsOfTypeAll(ReflectionHelpers.GameObjectType))
|
||||
{
|
||||
if (obj.name.ToLower().Contains(_search.ToLower()) && obj.scene.name == m_currentScene)
|
||||
var go = obj.TryCast<GameObject>();
|
||||
if (go.name.ToLower().Contains(_search.ToLower()) && go.scene.name == m_currentScene)
|
||||
{
|
||||
matches.Add(new GameObjectCache(obj));
|
||||
matches.Add(new GameObjectCache(go));
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (m_searching) return;
|
||||
|
||||
if (Time.time - m_timeOfLastUpdate < PASSIVE_UPDATE_INTERVAL) return;
|
||||
m_timeOfLastUpdate = Time.time;
|
||||
|
||||
Update_Impl();
|
||||
}
|
||||
|
||||
private void Update_Impl(bool manual = false)
|
||||
{
|
||||
List<Transform> allTransforms = new List<Transform>();
|
||||
|
||||
// get current list of all transforms (either scene root or our current transform children)
|
||||
if (m_currentTransform)
|
||||
{
|
||||
for (int i = 0; i < m_currentTransform.childCount; i++)
|
||||
{
|
||||
allTransforms.Add(m_currentTransform.GetChild(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!manual && m_getRootObjectsFailed) return;
|
||||
|
||||
if (!manual)
|
||||
{
|
||||
try
|
||||
{
|
||||
var scene = SceneManager.GetSceneByName(m_currentScene);
|
||||
|
||||
allTransforms.AddRange(scene.GetRootGameObjects()
|
||||
.Select(it => it.transform));
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_getRootObjectsFailed = true;
|
||||
allTransforms.AddRange(GetRootObjectsManual_Impl());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
allTransforms.AddRange(GetRootObjectsManual_Impl());
|
||||
}
|
||||
}
|
||||
|
||||
Pages.ItemCount = allTransforms.Count;
|
||||
|
||||
int offset = Pages.CalculateOffsetIndex();
|
||||
|
||||
// sort by childcount
|
||||
allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||
|
||||
m_objectList.Clear();
|
||||
|
||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < Pages.ItemCount; i++)
|
||||
{
|
||||
var child = allTransforms[i];
|
||||
m_objectList.Add(new GameObjectCache(child.gameObject));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Transform> GetRootObjectsManual_Impl()
|
||||
{
|
||||
try
|
||||
{
|
||||
var array = Resources.FindObjectsOfTypeAll(ReflectionHelpers.TransformType);
|
||||
|
||||
var list = new List<Transform>();
|
||||
foreach (var obj in array)
|
||||
{
|
||||
var transform = obj.TryCast<Transform>();
|
||||
if (transform.parent == null && transform.gameObject.scene.name == m_currentScene)
|
||||
{
|
||||
list.Add(transform);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.Log("Exception getting root scene objects (manual): "
|
||||
+ e.GetType() + ", " + e.Message + "\r\n"
|
||||
+ e.StackTrace);
|
||||
return new Transform[0];
|
||||
}
|
||||
}
|
||||
|
||||
// --------- GUI Draw Function --------- //
|
||||
|
||||
public override void DrawWindow()
|
||||
@ -246,8 +290,7 @@ namespace Explorer
|
||||
{
|
||||
Pages.TurnPage(Turn.Left, ref this.scroll);
|
||||
|
||||
m_timeOfLastUpdate = -1f;
|
||||
Update();
|
||||
Update_Impl(true);
|
||||
}
|
||||
|
||||
Pages.CurrentPageLabel();
|
||||
@ -256,8 +299,7 @@ namespace Explorer
|
||||
{
|
||||
Pages.TurnPage(Turn.Right, ref this.scroll);
|
||||
|
||||
m_timeOfLastUpdate = -1f;
|
||||
Update();
|
||||
Update_Impl(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,12 +329,24 @@ namespace Explorer
|
||||
else
|
||||
{
|
||||
GUILayout.Label("Scene Root GameObjects:", null);
|
||||
|
||||
if (m_getRootObjectsFailed)
|
||||
{
|
||||
if (GUILayout.Button("Update Root Object List (auto-update failed!)", null))
|
||||
{
|
||||
Update_Impl(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_objectList.Count > 0)
|
||||
{
|
||||
foreach (var obj in m_objectList)
|
||||
for (int i = 0; i < m_objectList.Count; i++)
|
||||
{
|
||||
var obj = m_objectList[i];
|
||||
|
||||
if (obj == null) continue;
|
||||
|
||||
if (!obj.RefGameObject)
|
||||
{
|
||||
string label = "<color=red><i>null";
|
||||
|
@ -13,7 +13,7 @@ namespace Explorer
|
||||
{
|
||||
public static SearchPage Instance;
|
||||
|
||||
public override string Name { get => "Object Search"; set => base.Name = value; }
|
||||
public override string Name { get => "Object Search"; }
|
||||
|
||||
private string m_searchInput = "";
|
||||
private string m_typeInput = "";
|
||||
@ -318,7 +318,8 @@ namespace Explorer
|
||||
continue;
|
||||
}
|
||||
|
||||
if (searchType == ReflectionHelpers.ComponentType && ReflectionHelpers.TransformType.IsAssignableFrom(obj.GetIl2CppType()))
|
||||
if (searchType.FullName == ReflectionHelpers.ComponentType.FullName
|
||||
&& ReflectionHelpers.TransformType.IsAssignableFrom(obj.GetIl2CppType()))
|
||||
{
|
||||
// Transforms shouldn't really be counted as Components, skip them.
|
||||
// They're more akin to GameObjects.
|
||||
|
@ -9,7 +9,7 @@ namespace Explorer
|
||||
{
|
||||
public abstract class WindowPage
|
||||
{
|
||||
public virtual string Name { get; set; }
|
||||
public virtual string Name { get; }
|
||||
|
||||
public Vector2 scroll = Vector2.zero;
|
||||
|
||||
|
@ -13,16 +13,6 @@ using Harmony;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
// This is a manual unstrip of UnityEngine.GUI and UnityEngine.GUILayout methods.
|
||||
// This code is provided "as-is".
|
||||
// Taken from dnSpy output using Unity 2018.4.20.
|
||||
|
||||
// "Unity", Unity logos, and other Unity trademarks are trademarks or
|
||||
// registered trademarks of Unity Technologies or its affiliates in the
|
||||
// U.S. and elsewhere.
|
||||
// https://unity3d.com/legal/terms-of-service
|
||||
// https://unity3d.com/legal/terms-of-service/software
|
||||
|
||||
public class GUIUnstrip
|
||||
{
|
||||
public static int s_ScrollControlId;
|
||||
@ -43,9 +33,6 @@ namespace Explorer
|
||||
}
|
||||
|
||||
// ======= public methods ======= //
|
||||
|
||||
// Fix for GUILayoutUtility.GetLastRect().
|
||||
// Calls UnstripExtensions.GetLastRectUnstripped.
|
||||
|
||||
public static Rect GetLastRect()
|
||||
{
|
||||
@ -62,28 +49,25 @@ namespace Explorer
|
||||
return last;
|
||||
}
|
||||
|
||||
// Fix for GUILayout.Scroller and GUILayout.ScrollerRepeatButton, just calling fixed implementations.
|
||||
|
||||
public static float Scroller(Rect position, float value, float size, float leftValue, float rightValue, GUIStyle slider, GUIStyle thumb, GUIStyle leftButton, GUIStyle rightButton, bool horiz)
|
||||
=> Scroller_Impl(position, value, size, leftValue, rightValue, slider, thumb, leftButton, rightButton, horiz);
|
||||
|
||||
public static bool ScrollerRepeatButton(int scrollerID, Rect rect, GUIStyle style)
|
||||
=> ScrollerRepeatButton_Impl(scrollerID, rect, style);
|
||||
|
||||
// Simple unstrips for HorizontalScrollbar and VerticalScrollbar, they just call the Scroller unstrip.
|
||||
|
||||
public static float HorizontalScrollbar(Rect position, float value, float size, float leftValue, float rightValue, GUIStyle style)
|
||||
{
|
||||
return Scroller(position, value, size, leftValue, rightValue, style, GUI.skin.GetStyle(style.name + "thumb"), GUI.skin.GetStyle(style.name + "leftbutton"), GUI.skin.GetStyle(style.name + "rightbutton"), true);
|
||||
return Scroller_Impl(position, value, size, leftValue, rightValue, style,
|
||||
GUI.skin.GetStyle(style.name + "thumb"),
|
||||
GUI.skin.GetStyle(style.name + "leftbutton"),
|
||||
GUI.skin.GetStyle(style.name + "rightbutton"),
|
||||
true);
|
||||
}
|
||||
|
||||
public static float VerticalScrollbar(Rect position, float value, float size, float topValue, float bottomValue, GUIStyle style)
|
||||
{
|
||||
return Scroller(position, value, size, topValue, bottomValue, style, GUI.skin.GetStyle(style.name + "thumb"), GUI.skin.GetStyle(style.name + "upbutton"), GUI.skin.GetStyle(style.name + "downbutton"), false);
|
||||
return Scroller_Impl(position, value, size, topValue, bottomValue, style,
|
||||
GUI.skin.GetStyle(style.name + "thumb"),
|
||||
GUI.skin.GetStyle(style.name + "upbutton"),
|
||||
GUI.skin.GetStyle(style.name + "downbutton"),
|
||||
false);
|
||||
}
|
||||
|
||||
// Fix for BeginScrollView.
|
||||
// Uses several manually unstripped methods.
|
||||
|
||||
public static Vector2 BeginScrollView(Vector2 scroll, params GUILayoutOption[] options)
|
||||
{
|
||||
@ -101,16 +85,16 @@ namespace Explorer
|
||||
}
|
||||
}
|
||||
|
||||
// Try manual unstripping implementation.
|
||||
// Try manual implementation.
|
||||
if (!ManualUnstripFailed)
|
||||
{
|
||||
try
|
||||
{
|
||||
return BeginScrollView_Impl(scroll, false, false, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, GUI.skin.scrollView, options);
|
||||
return BeginScrollView_ImplLayout(scroll, false, false, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, GUI.skin.scrollView, options);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MelonLogger.Log("Exception on GUIUnstrip.BeginScrollView_Impl: " + e.GetType() + ", " + e.Message + "\r\n" + e.StackTrace);
|
||||
MelonLogger.Log("Exception on GUIUnstrip.BeginScrollView_ImplLayout: " + e.GetType() + ", " + e.Message + "\r\n" + e.StackTrace);
|
||||
|
||||
ManualUnstripFailed = true;
|
||||
return scroll;
|
||||
@ -139,18 +123,13 @@ namespace Explorer
|
||||
|
||||
// ======= private methods ======= //
|
||||
|
||||
// Actual unstrip of GUILayout.BeginScrollView()
|
||||
|
||||
private static Vector2 BeginScrollView_Impl(Vector2 scrollPosition, bool alwaysShowHorizontal, bool alwaysShowVertical, GUIStyle horizontalScrollbar,
|
||||
GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options)
|
||||
private static Vector2 BeginScrollView_ImplLayout(Vector2 scrollPosition, bool alwaysShowHorizontal, bool alwaysShowVertical,
|
||||
GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options)
|
||||
{
|
||||
GUIUtility.CheckOnGUI();
|
||||
|
||||
var guiscrollGroup = (GUIScrollGroup)GUILayoutUtility.BeginLayoutGroup(
|
||||
background,
|
||||
null,
|
||||
Il2CppType.Of<GUIScrollGroup>()
|
||||
).Il2CppCast(typeof(GUIScrollGroup));
|
||||
var guiscrollGroup = GUILayoutUtility.BeginLayoutGroup(background, null, Il2CppType.Of<GUIScrollGroup>())
|
||||
.TryCast<GUIScrollGroup>();
|
||||
|
||||
EventType type = Event.current.type;
|
||||
if (type == EventType.Layout)
|
||||
@ -177,16 +156,14 @@ namespace Explorer
|
||||
);
|
||||
}
|
||||
|
||||
// Actual unstrip of GUI.BeginScrollView() -- note: not GUILayout.
|
||||
|
||||
private static Vector2 BeginScrollView_Impl(Rect position, Vector2 scrollPosition, Rect viewRect, bool alwaysShowHorizontal, bool alwaysShowVertical,
|
||||
GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background)
|
||||
private static Vector2 BeginScrollView_Impl(Rect position, Vector2 scrollPosition, Rect viewRect, bool alwaysShowHorizontal,
|
||||
bool alwaysShowVertical, GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background)
|
||||
{
|
||||
GUIUtility.CheckOnGUI();
|
||||
|
||||
int controlID = GUIUtility.GetControlID(GUI.s_ScrollviewHash, FocusType.Passive);
|
||||
|
||||
var scrollViewState = (ScrollViewState)GUIUtility.GetStateObject(Il2CppType.Of<ScrollViewState>(), controlID).Il2CppCast(typeof(ScrollViewState));
|
||||
var scrollViewState = GUIUtility.GetStateObject(Il2CppType.Of<ScrollViewState>(), controlID).TryCast<ScrollViewState>();
|
||||
|
||||
var scrollExt = ScrollViewStateUnstrip.FromPointer(scrollViewState.Pointer);
|
||||
|
||||
@ -210,7 +187,7 @@ namespace Explorer
|
||||
|
||||
ScrollStack.Push(scrollViewState);
|
||||
|
||||
Rect screenRect = new Rect(position);
|
||||
Rect screenRect = new Rect(position.x, position.y, position.width, position.height);
|
||||
EventType type = Event.current.type;
|
||||
if (type != EventType.Layout)
|
||||
{
|
||||
@ -302,24 +279,19 @@ namespace Explorer
|
||||
return scrollPosition;
|
||||
}
|
||||
|
||||
// Actual unstrip of GUI.EndScrollView()
|
||||
|
||||
private static void EndScrollView_Impl(bool handleScrollWheel)
|
||||
{
|
||||
GUIUtility.CheckOnGUI();
|
||||
|
||||
if (ScrollStack.Count <= 0) return;
|
||||
|
||||
//ScrollViewState scrollViewState = (ScrollViewState)GUI.s_ScrollViewStates.Peek();
|
||||
var state = (ScrollViewState)ScrollStack.Peek().Il2CppCast(typeof(ScrollViewState));
|
||||
//ScrollViewExtensions.Dict.TryGetValue(state.Pointer, out ScrollViewExtensions scrollExt);
|
||||
var state = ScrollStack.Peek().TryCast<ScrollViewState>();
|
||||
var scrollExt = ScrollViewStateUnstrip.FromPointer(state.Pointer);
|
||||
|
||||
if (scrollExt == null) throw new Exception("Could not get scrollExt!");
|
||||
|
||||
GUIClip.Pop();
|
||||
|
||||
//GUI.s_ScrollViewStates.Pop();
|
||||
ScrollStack.Pop();
|
||||
|
||||
var position = scrollExt.position;
|
||||
@ -339,15 +311,12 @@ namespace Explorer
|
||||
pos.y = 0f;
|
||||
}
|
||||
|
||||
// state.apply = true;
|
||||
scrollExt.apply = true;
|
||||
|
||||
Event.current.Use();
|
||||
}
|
||||
}
|
||||
|
||||
// Actual unstrip of GUI.Scroller
|
||||
|
||||
private static float Scroller_Impl(Rect position, float value, float size, float leftValue, float rightValue, GUIStyle slider, GUIStyle thumb, GUIStyle leftButton, GUIStyle rightButton, bool horiz)
|
||||
{
|
||||
GUIUtility.CheckOnGUI();
|
||||
@ -368,7 +337,6 @@ namespace Explorer
|
||||
rect2 = new Rect(position.x, position.yMax - rightButton.fixedHeight, position.width, rightButton.fixedHeight);
|
||||
}
|
||||
|
||||
//value = GUI.Slider(position2, value, size, leftValue, rightValue, slider, thumb, horiz, controlID);
|
||||
value = Slider(position2, value, size, leftValue, rightValue, slider, thumb, horiz, controlID);
|
||||
|
||||
bool flag = Event.current.type == EventType.MouseUp;
|
||||
@ -382,8 +350,7 @@ namespace Explorer
|
||||
}
|
||||
if (flag && Event.current.type == EventType.Used)
|
||||
{
|
||||
//GUI.s_ScrollControlId = 0;
|
||||
GUIUnstrip.s_ScrollControlId = 0;
|
||||
s_ScrollControlId = 0;
|
||||
}
|
||||
if (leftValue < rightValue)
|
||||
{
|
||||
@ -396,11 +363,8 @@ namespace Explorer
|
||||
return value;
|
||||
}
|
||||
|
||||
// Actual unstrip of GUI.Slider
|
||||
|
||||
public static float Slider(Rect position, float value, float size, float start, float end, GUIStyle slider, GUIStyle thumb, bool horiz, int id)
|
||||
{
|
||||
//GUIUtility.CheckOnGUI();
|
||||
if (id == 0)
|
||||
{
|
||||
id = GUIUtility.GetControlID(GUI.s_SliderHash, FocusType.Passive, position);
|
||||
@ -409,18 +373,13 @@ namespace Explorer
|
||||
return sliderHandler.Handle();
|
||||
}
|
||||
|
||||
// Actual unstrip of GUI.ScrollerRepeatButton
|
||||
|
||||
private static bool ScrollerRepeatButton_Impl(int scrollerID, Rect rect, GUIStyle style)
|
||||
{
|
||||
bool result = false;
|
||||
if (GUI.DoRepeatButton(rect, GUIContent.none, style, FocusType.Passive))
|
||||
{
|
||||
//bool flag = GUI.s_ScrollControlId != scrollerID;
|
||||
//GUI.s_ScrollControlId = scrollerID;
|
||||
|
||||
bool flag = GUIUnstrip.s_ScrollControlId != scrollerID;
|
||||
GUIUnstrip.s_ScrollControlId = scrollerID;
|
||||
bool flag = s_ScrollControlId != scrollerID;
|
||||
s_ScrollControlId = scrollerID;
|
||||
|
||||
if (flag)
|
||||
{
|
@ -8,17 +8,7 @@ using MelonLoader;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
// This is a manual unstrip of UnityEngine.ScrollViewState.
|
||||
// This code is provided "as-is".
|
||||
// Taken from dnSpy output using Unity 2018.4.20.
|
||||
|
||||
// "Unity", Unity logos, and other Unity trademarks are trademarks or
|
||||
// registered trademarks of Unity Technologies or its affiliates in the
|
||||
// U.S. and elsewhere.
|
||||
// https://unity3d.com/legal/terms-of-service
|
||||
// https://unity3d.com/legal/terms-of-service/software
|
||||
|
||||
{
|
||||
public class ScrollViewStateUnstrip
|
||||
{
|
||||
public Rect position;
|
@ -8,16 +8,6 @@ using UnhollowerRuntimeLib;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
// This is a manual unstrip of UnityEngine.SliderHandler.
|
||||
// This code is provided "as-is".
|
||||
// Taken from dnSpy output using Unity 2018.4.20.
|
||||
|
||||
// "Unity", Unity logos, and other Unity trademarks are trademarks or
|
||||
// registered trademarks of Unity Technologies or its affiliates in the
|
||||
// U.S. and elsewhere.
|
||||
// https://unity3d.com/legal/terms-of-service
|
||||
// https://unity3d.com/legal/terms-of-service/software
|
||||
|
||||
public struct SliderHandlerUnstrip
|
||||
{
|
||||
private readonly Rect position;
|
||||
@ -282,7 +272,7 @@ namespace Explorer
|
||||
|
||||
private SliderState SliderState()
|
||||
{
|
||||
return (SliderState)GUIUtility.GetStateObject(Il2CppType.Of<SliderState>(), this.id).Il2CppCast(typeof(SliderState));
|
||||
return (SliderState)GUIUtility.GetStateObject(Il2CppType.Of<SliderState>(), this.id).TryCast<SliderState>();
|
||||
}
|
||||
|
||||
private Rect ThumbRect()
|
27
src/UnstripFixes/UnstripExtensions.cs
Normal file
27
src/UnstripFixes/UnstripExtensions.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
public static class UnstripExtensions
|
||||
{
|
||||
public static Rect GetLastUnstripped(this GUILayoutGroup group)
|
||||
{
|
||||
Rect result;
|
||||
if (group.m_Cursor > 0 && group.m_Cursor <= group.entries.Count)
|
||||
{
|
||||
GUILayoutEntry guilayoutEntry = group.entries[group.m_Cursor - 1];
|
||||
result = guilayoutEntry.rect;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = GUILayoutEntry.kDummyRect;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer
|
||||
{
|
||||
// "Unity", Unity logos, and other Unity trademarks are trademarks or
|
||||
// registered trademarks of Unity Technologies or its affiliates in the
|
||||
// U.S. and elsewhere.
|
||||
// https://unity3d.com/legal/terms-of-service
|
||||
// https://unity3d.com/legal/terms-of-service/software
|
||||
|
||||
public static class UnstripExtensions
|
||||
{
|
||||
// This is a manual unstrip of GUILayoutGroup.GetLast().
|
||||
// I'm using it as an Extension because it's easier this way.
|
||||
|
||||
public static Rect GetLastUnstripped(this GUILayoutGroup group)
|
||||
{
|
||||
Rect result;
|
||||
if (group.m_Cursor == 0)
|
||||
{
|
||||
Debug.LogError("You cannot call GetLast immediately after beginning a group.");
|
||||
result = GUILayoutEntry.kDummyRect;
|
||||
}
|
||||
else if (group.m_Cursor <= group.entries.Count)
|
||||
{
|
||||
GUILayoutEntry guilayoutEntry = group.entries[group.m_Cursor - 1];
|
||||
result = guilayoutEntry.rect;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError(string.Concat(new object[]
|
||||
{
|
||||
"Getting control ",
|
||||
group.m_Cursor,
|
||||
"'s position in a group with only ",
|
||||
group.entries.Count,
|
||||
" controls when doing ",
|
||||
Event.current.type
|
||||
}));
|
||||
result = GUILayoutEntry.kDummyRect;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -29,9 +29,17 @@ namespace Explorer
|
||||
private Vector2 m_compScroll = Vector2.zero;
|
||||
private PageHelper CompPages = new PageHelper();
|
||||
|
||||
private readonly Vector3[] m_cachedInput = new Vector3[3];
|
||||
private float m_translateAmount = 0.3f;
|
||||
private float m_rotateAmount = 50f;
|
||||
private float m_scaleAmount = 0.1f;
|
||||
private bool m_freeze;
|
||||
private Vector3 m_frozenPosition;
|
||||
private Quaternion m_frozenRotation;
|
||||
private Vector3 m_frozenScale;
|
||||
private bool m_autoApplyTransform;
|
||||
private bool m_autoUpdateTransform;
|
||||
private bool m_localContext;
|
||||
|
||||
private readonly List<Component> m_cachedDestroyList = new List<Component>();
|
||||
//private string m_addComponentInput = "";
|
||||
@ -73,12 +81,29 @@ namespace Explorer
|
||||
|
||||
m_name = m_object.name;
|
||||
m_scene = string.IsNullOrEmpty(m_object.scene.name)
|
||||
? "None"
|
||||
? "None (Asset/Resource)"
|
||||
: m_object.scene.name;
|
||||
|
||||
CacheTransformValues();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private void CacheTransformValues()
|
||||
{
|
||||
if (m_localContext)
|
||||
{
|
||||
m_cachedInput[0] = m_object.transform.localPosition;
|
||||
m_cachedInput[1] = m_object.transform.localEulerAngles;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cachedInput[0] = m_object.transform.position;
|
||||
m_cachedInput[1] = m_object.transform.eulerAngles;
|
||||
}
|
||||
m_cachedInput[2] = m_object.transform.localScale;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
try
|
||||
@ -88,28 +113,37 @@ namespace Explorer
|
||||
throw new Exception("Object is null!");
|
||||
}
|
||||
|
||||
var list = new List<Transform>();
|
||||
if (m_freeze)
|
||||
{
|
||||
if (m_localContext)
|
||||
{
|
||||
m_object.transform.localPosition = m_frozenPosition;
|
||||
m_object.transform.localRotation = m_frozenRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_object.transform.position = m_frozenPosition;
|
||||
m_object.transform.rotation = m_frozenRotation;
|
||||
}
|
||||
m_object.transform.localScale = m_frozenScale;
|
||||
}
|
||||
|
||||
// update child objects
|
||||
var childList = new List<Transform>();
|
||||
for (int i = 0; i < m_object.transform.childCount; i++)
|
||||
{
|
||||
list.Add(m_object.transform.GetChild(i));
|
||||
childList.Add(m_object.transform.GetChild(i));
|
||||
}
|
||||
list.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||
m_children = list.ToArray();
|
||||
childList.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||
m_children = childList.ToArray();
|
||||
|
||||
ChildPages.ItemCount = m_children.Length;
|
||||
|
||||
var list2 = new List<Component>();
|
||||
foreach (var comp in m_object.GetComponents(ReflectionHelpers.ComponentType))
|
||||
{
|
||||
var ilType = comp.GetIl2CppType();
|
||||
if (ilType == ReflectionHelpers.TransformType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// update components
|
||||
var compList = new Il2CppSystem.Collections.Generic.List<Component>();
|
||||
m_object.GetComponentsInternal(ReflectionHelpers.ComponentType, true, false, true, false, compList);
|
||||
|
||||
list2.Add(comp);
|
||||
}
|
||||
m_components = list2.ToArray();
|
||||
m_components = compList.ToArray();
|
||||
|
||||
CompPages.ItemCount = m_components.Length;
|
||||
}
|
||||
@ -412,6 +446,16 @@ namespace Explorer
|
||||
m_object.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
}
|
||||
|
||||
var lbl = m_freeze ? "<color=lime>Unfreeze</color>" : "<color=orange>Freeze Pos/Rot</color>";
|
||||
if (GUILayout.Button(lbl, new GUILayoutOption[] { GUILayout.Width(110) }))
|
||||
{
|
||||
m_freeze = !m_freeze;
|
||||
if (m_freeze)
|
||||
{
|
||||
UpdateFreeze();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.BeginHorizontal(null);
|
||||
|
||||
@ -436,10 +480,52 @@ namespace Explorer
|
||||
|
||||
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||
|
||||
var t = m_object.transform;
|
||||
TranslateControl(t, TranslateType.Position, ref m_translateAmount, false);
|
||||
TranslateControl(t, TranslateType.Rotation, ref m_rotateAmount, true);
|
||||
TranslateControl(t, 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(null);
|
||||
if (GUILayout.Button("<color=lime>Apply to Transform</color>", null) || m_autoApplyTransform)
|
||||
{
|
||||
if (m_localContext)
|
||||
{
|
||||
m_object.transform.localPosition = m_cachedInput[0];
|
||||
m_object.transform.localEulerAngles = m_cachedInput[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_object.transform.position = m_cachedInput[0];
|
||||
m_object.transform.eulerAngles = m_cachedInput[1];
|
||||
}
|
||||
m_object.transform.localScale = m_cachedInput[2];
|
||||
|
||||
if (m_freeze)
|
||||
{
|
||||
UpdateFreeze();
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("<color=lime>Update from Transform</color>", null) || m_autoUpdateTransform)
|
||||
{
|
||||
CacheTransformValues();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
BoolToggle(ref m_autoApplyTransform, "Auto-apply to Transform?");
|
||||
BoolToggle(ref m_autoUpdateTransform, "Auto-update from transform?");
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
bool b = m_localContext;
|
||||
b = GUILayout.Toggle(b, "<color=" + (b ? "lime" : "red") + ">Use local transform values?</color>", null);
|
||||
if (b != m_localContext)
|
||||
{
|
||||
m_localContext = b;
|
||||
CacheTransformValues();
|
||||
if (m_freeze)
|
||||
{
|
||||
UpdateFreeze();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
|
||||
@ -453,6 +539,30 @@ namespace Explorer
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void UpdateFreeze()
|
||||
{
|
||||
if (m_localContext)
|
||||
{
|
||||
m_frozenPosition = m_object.transform.localPosition;
|
||||
m_frozenRotation = m_object.transform.localRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frozenPosition = m_object.transform.position;
|
||||
m_frozenRotation = m_object.transform.rotation;
|
||||
}
|
||||
m_frozenScale = m_object.transform.localScale;
|
||||
}
|
||||
|
||||
private void BoolToggle(ref bool value, string message)
|
||||
{
|
||||
string lbl = "<color=";
|
||||
lbl += value ? "lime" : "red";
|
||||
lbl += $">{message}</color>";
|
||||
|
||||
value = GUILayout.Toggle(value, lbl, null);
|
||||
}
|
||||
|
||||
public enum TranslateType
|
||||
{
|
||||
Position,
|
||||
@ -460,50 +570,55 @@ namespace Explorer
|
||||
Scale
|
||||
}
|
||||
|
||||
private void TranslateControl(Transform transform, TranslateType mode, ref float amount, bool multByTime)
|
||||
private Vector3 TranslateControl(TranslateType mode, ref float amount, bool multByTime)
|
||||
{
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUILayout.Label("<color=cyan><b>" + mode + "</b></color>:", new GUILayoutOption[] { GUILayout.Width(65) });
|
||||
GUILayout.Label($"<color=cyan><b>{(m_localContext ? "Local " : "")}{mode}</b></color>:",
|
||||
new GUILayoutOption[] { GUILayout.Width(m_localContext ? 110 : 65) });
|
||||
|
||||
Vector3 vector = Vector3.zero;
|
||||
var transform = m_object.transform;
|
||||
switch (mode)
|
||||
{
|
||||
case TranslateType.Position: vector = transform.localPosition; break;
|
||||
case TranslateType.Rotation: vector = transform.localRotation.eulerAngles; break;
|
||||
case TranslateType.Scale: vector = transform.localScale; break;
|
||||
case TranslateType.Position:
|
||||
var pos = m_localContext ? transform.localPosition : transform.position;
|
||||
GUILayout.Label(pos.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
break;
|
||||
case TranslateType.Rotation:
|
||||
var rot = m_localContext ? transform.localEulerAngles : transform.eulerAngles;
|
||||
GUILayout.Label(rot.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
break;
|
||||
case TranslateType.Scale:
|
||||
GUILayout.Label(transform.localScale.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
break;
|
||||
}
|
||||
GUILayout.Label(vector.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
Vector3 input = m_cachedInput[(int)mode];
|
||||
|
||||
GUILayout.BeginHorizontal(null);
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
|
||||
GUILayout.Label("<color=cyan>X:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||
PlusMinusFloat(ref vector.x, amount, multByTime);
|
||||
PlusMinusFloat(ref input.x, amount, multByTime);
|
||||
|
||||
GUILayout.Label("<color=cyan>Y:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||
PlusMinusFloat(ref vector.y, amount, multByTime);
|
||||
PlusMinusFloat(ref input.y, amount, multByTime);
|
||||
|
||||
GUILayout.Label("<color=cyan>Z:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||
PlusMinusFloat(ref vector.z, amount, multByTime);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case TranslateType.Position: transform.localPosition = vector; break;
|
||||
case TranslateType.Rotation: transform.localRotation = Quaternion.Euler(vector); break;
|
||||
case TranslateType.Scale: transform.localScale = vector; break;
|
||||
}
|
||||
PlusMinusFloat(ref input.z, amount, multByTime);
|
||||
|
||||
GUILayout.Label("+/-:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
var input = amount.ToString("F3");
|
||||
input = GUILayout.TextField(input, new GUILayoutOption[] { GUILayout.Width(40) });
|
||||
if (float.TryParse(input, out float f))
|
||||
var amountInput = amount.ToString("F3");
|
||||
amountInput = GUILayout.TextField(amountInput, new GUILayoutOption[] { GUILayout.Width(60) });
|
||||
if (float.TryParse(amountInput, out float f))
|
||||
{
|
||||
amount = f;
|
||||
}
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private void PlusMinusFloat(ref float f, float amount, bool multByTime)
|
||||
@ -523,7 +638,5 @@ namespace Explorer
|
||||
f += multByTime ? amount * Time.deltaTime : amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ namespace Explorer
|
||||
}
|
||||
|
||||
public override void Init() { }
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
while (TargetTabID >= WindowManager.Windows.Count)
|
||||
|
@ -109,7 +109,7 @@ namespace Explorer
|
||||
|
||||
if (!equals && iObj is Il2CppSystem.Object iCurrent && window.Target is Il2CppSystem.Object iTarget)
|
||||
{
|
||||
if (iCurrent.GetIl2CppType() != iTarget.GetIl2CppType())
|
||||
if (iCurrent.GetIl2CppType().FullName != iTarget.GetIl2CppType().FullName)
|
||||
{
|
||||
if (iCurrent is Transform transform)
|
||||
{
|
||||
|
Reference in New Issue
Block a user