mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-23 00:52:31 +08:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
9a059c1056 | |||
ffb6cad8c2 | |||
d0a4863139 | |||
bb8837d58c | |||
a236b272c1 | |||
18de1eaf1c | |||
b1264c6912 | |||
9836566e55 | |||
d20461fa0e | |||
72ec34090d | |||
883a8705c3 | |||
6adaaf5500 | |||
5de771389e | |||
51cfbe524e | |||
217b93ef4f | |||
42156e1160 |
17
README.md
17
README.md
@ -14,10 +14,9 @@
|
|||||||
<img src="https://img.shields.io/github/downloads/sinai-dev/CppExplorer/total.svg" />
|
<img src="https://img.shields.io/github/downloads/sinai-dev/CppExplorer/total.svg" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
### Known issue
|
### Known issues
|
||||||
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.
|
* 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.
|
||||||
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.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Scene hierarchy explorer
|
* Scene hierarchy explorer
|
||||||
@ -45,20 +44,22 @@ Requires [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) to be ins
|
|||||||
* A simple menu which allows you to traverse the Transform heirarchy of the scene.
|
* 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.
|
* 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
|
### Inspectors
|
||||||
|
|
||||||
CppExplorer has two main inspector modes: <b>GameObject Inspector</b>, and <b>Reflection Inspector</b>.
|
CppExplorer has two main inspector modes: <b>GameObject Inspector</b>, and <b>Reflection Inspector</b>.
|
||||||
|
|
||||||
<b>Tip:</b> when in Tab View, GameObjects are denoted by a [G] prefix, and Reflection objects are denoted by a [R] prefix.
|
<b>Tips:</b>
|
||||||
|
* When in Tab View, GameObjects are denoted by a [G] prefix, and Reflection objects are denoted by a [R] prefix.
|
||||||
|
* Hold <b>Left Shift</b> when you click the Inspect button to force Reflection mode for GameObjects and Transforms.
|
||||||
|
|
||||||
### GameObject Inspector
|
### GameObject Inspector
|
||||||
|
|
||||||
* Allows you to see the children and components on a GameObject.
|
* 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.
|
* 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
|
### Reflection Inspector
|
||||||
|
|
||||||
@ -66,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.
|
* 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.
|
* 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
|
### Object Search
|
||||||
|
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MelonLoader;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Explorer
|
|
||||||
{
|
|
||||||
public class CacheGameObject : CacheObjectBase
|
|
||||||
{
|
|
||||||
private GameObject GameObj
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (m_gameObject == null)
|
|
||||||
{
|
|
||||||
if (Value is Il2CppSystem.Object ilObj)
|
|
||||||
{
|
|
||||||
var ilType = ilObj.GetIl2CppType();
|
|
||||||
|
|
||||||
if (ilType == ReflectionHelpers.GameObjectType || ilType == ReflectionHelpers.TransformType)
|
|
||||||
{
|
|
||||||
m_gameObject = ilObj.TryCast<GameObject>() ?? ilObj.TryCast<Transform>()?.gameObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_gameObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private GameObject m_gameObject;
|
|
||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
|
||||||
{
|
|
||||||
UIHelpers.GameobjButton(GameObj, null, false, width);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateValue()
|
|
||||||
{
|
|
||||||
base.UpdateValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -137,6 +137,22 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
holder = new CacheEnum();
|
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))
|
else if (ReflectionHelpers.IsArray(valueType) || ReflectionHelpers.IsList(valueType))
|
||||||
{
|
{
|
||||||
holder = new CacheList();
|
holder = new CacheList();
|
||||||
|
23
src/CachedObjects/Object/CacheGameObject.cs
Normal file
23
src/CachedObjects/Object/CacheGameObject.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MelonLoader;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,7 @@ namespace Explorer
|
|||||||
public class CacheList : CacheObjectBase
|
public class CacheList : CacheObjectBase
|
||||||
{
|
{
|
||||||
public bool IsExpanded { get; set; }
|
public bool IsExpanded { get; set; }
|
||||||
public int ArrayOffset { get; set; }
|
public PageHelper Pages = new PageHelper();
|
||||||
public int ArrayLimit { get; set; } = 20;
|
|
||||||
|
|
||||||
public float WhiteSpace = 215f;
|
public float WhiteSpace = 215f;
|
||||||
public float ButtonWidthOffset = 290f;
|
public float ButtonWidthOffset = 290f;
|
||||||
@ -230,18 +229,6 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
list.Add(null);
|
list.Add(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//var type = ReflectionHelpers.GetActualType(obj);
|
|
||||||
|
|
||||||
//if (obj is Il2CppSystem.Object iObj)
|
|
||||||
//{
|
|
||||||
// obj = iObj.Il2CppCast(type);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//var cached = GetCacheObject(obj, null, null, type);
|
|
||||||
//cached.UpdateValue();
|
|
||||||
|
|
||||||
//list.Add(cached);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cachedEntries = list.ToArray();
|
m_cachedEntries = list.ToArray();
|
||||||
@ -286,51 +273,47 @@ namespace Explorer
|
|||||||
|
|
||||||
if (IsExpanded)
|
if (IsExpanded)
|
||||||
{
|
{
|
||||||
float whitespace = WhiteSpace;
|
float whitespace = WhiteSpace;
|
||||||
|
|
||||||
if (whitespace > 0)
|
if (whitespace > 0)
|
||||||
{
|
{
|
||||||
ClampLabelWidth(window, ref whitespace);
|
ClampLabelWidth(window, ref whitespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count > ArrayLimit)
|
Pages.ItemCount = count;
|
||||||
|
|
||||||
|
if (count > Pages.ItemsPerPage)
|
||||||
{
|
{
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
GUILayout.Space(whitespace);
|
GUILayout.Space(whitespace);
|
||||||
|
|
||||||
|
Pages.CurrentPageLabel();
|
||||||
|
|
||||||
int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)ArrayLimit)) - 1;
|
|
||||||
GUILayout.Label($"Page {ArrayOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
|
||||||
// prev/next page buttons
|
// prev/next page buttons
|
||||||
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(60) }))
|
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||||
{
|
{
|
||||||
if (ArrayOffset > 0) ArrayOffset--;
|
Pages.TurnPage(Turn.Left);
|
||||||
}
|
}
|
||||||
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(60) }))
|
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||||
{
|
{
|
||||||
if (ArrayOffset < maxOffset) ArrayOffset++;
|
Pages.TurnPage(Turn.Right);
|
||||||
}
|
|
||||||
GUILayout.Label("Limit: ", new GUILayoutOption[] { GUILayout.Width(50) });
|
|
||||||
var limit = this.ArrayLimit.ToString();
|
|
||||||
limit = GUILayout.TextField(limit, new GUILayoutOption[] { GUILayout.Width(50) });
|
|
||||||
if (limit != ArrayLimit.ToString() && int.TryParse(limit, out int i))
|
|
||||||
{
|
|
||||||
ArrayLimit = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pages.DrawLimitInputArea();
|
||||||
|
|
||||||
GUILayout.Space(5);
|
GUILayout.Space(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = ArrayOffset * ArrayLimit;
|
//int offset = ArrayOffset * ArrayLimit;
|
||||||
|
//if (offset >= count)
|
||||||
|
//{
|
||||||
|
// offset = 0;
|
||||||
|
// ArrayOffset = 0;
|
||||||
|
//}
|
||||||
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
if (offset >= count)
|
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
||||||
{
|
|
||||||
offset = 0;
|
|
||||||
ArrayOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = offset; i < offset + ArrayLimit && i < count; i++)
|
|
||||||
{
|
{
|
||||||
var entry = m_cachedEntries[i];
|
var entry = m_cachedEntries[i];
|
||||||
|
|
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 class CachePrimitive : CacheObjectBase
|
||||||
{
|
{
|
||||||
public enum PrimitiveTypes
|
public enum Types
|
||||||
{
|
{
|
||||||
Bool,
|
Bool,
|
||||||
Double,
|
Double,
|
||||||
@ -20,20 +20,9 @@ namespace Explorer
|
|||||||
|
|
||||||
private string m_valueToString;
|
private string m_valueToString;
|
||||||
|
|
||||||
public PrimitiveTypes PrimitiveType;
|
public Types PrimitiveType;
|
||||||
|
|
||||||
public MethodInfo ParseMethod
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (m_parseMethod == null)
|
|
||||||
{
|
|
||||||
m_parseMethod = Value.GetType().GetMethod("Parse", new Type[] { typeof(string) });
|
|
||||||
}
|
|
||||||
return m_parseMethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public MethodInfo ParseMethod => m_parseMethod ?? (m_parseMethod = Value.GetType().GetMethod("Parse", new Type[] { typeof(string) }));
|
||||||
private MethodInfo m_parseMethod;
|
private MethodInfo m_parseMethod;
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
@ -41,58 +30,39 @@ namespace Explorer
|
|||||||
if (Value == null)
|
if (Value == null)
|
||||||
{
|
{
|
||||||
// this must mean it is a string. No other primitive type should be nullable.
|
// this must mean it is a string. No other primitive type should be nullable.
|
||||||
PrimitiveType = PrimitiveTypes.String;
|
PrimitiveType = Types.String;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_valueToString = Value.ToString();
|
m_valueToString = Value.ToString();
|
||||||
var type = Value.GetType();
|
|
||||||
|
|
||||||
|
var type = Value.GetType();
|
||||||
if (type == typeof(bool))
|
if (type == typeof(bool))
|
||||||
{
|
{
|
||||||
PrimitiveType = PrimitiveTypes.Bool;
|
PrimitiveType = Types.Bool;
|
||||||
}
|
}
|
||||||
else if (type == typeof(double))
|
else if (type == typeof(double))
|
||||||
{
|
{
|
||||||
PrimitiveType = PrimitiveTypes.Double;
|
PrimitiveType = Types.Double;
|
||||||
}
|
}
|
||||||
else if (type == typeof(float))
|
else if (type == typeof(float))
|
||||||
{
|
{
|
||||||
PrimitiveType = PrimitiveTypes.Float;
|
PrimitiveType = Types.Float;
|
||||||
}
|
|
||||||
else if (IsInteger(type))
|
|
||||||
{
|
|
||||||
PrimitiveType = PrimitiveTypes.Int;
|
|
||||||
}
|
}
|
||||||
else if (type == typeof(char))
|
else if (type == typeof(char))
|
||||||
{
|
{
|
||||||
PrimitiveType = PrimitiveTypes.Char;
|
PrimitiveType = Types.Char;
|
||||||
|
}
|
||||||
|
else if (typeof(int).IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
PrimitiveType = Types.Int;
|
||||||
}
|
}
|
||||||
else
|
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()
|
public override void UpdateValue()
|
||||||
{
|
{
|
||||||
base.UpdateValue();
|
base.UpdateValue();
|
||||||
@ -102,11 +72,10 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
if (PrimitiveType == PrimitiveTypes.Bool)
|
if (PrimitiveType == Types.Bool)
|
||||||
{
|
{
|
||||||
var b = (bool)Value;
|
var b = (bool)Value;
|
||||||
var color = $"<color={(b ? "lime>" : "red>")}";
|
var label = $"<color={(b ? "lime" : "red")}>{b}</color>";
|
||||||
var label = $"{color}{b}</color>";
|
|
||||||
|
|
||||||
if (CanWrite)
|
if (CanWrite)
|
||||||
{
|
{
|
||||||
@ -150,7 +119,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetValueFromInput(string value)
|
public void SetValueFromInput(string valueString)
|
||||||
{
|
{
|
||||||
if (MemInfo == null)
|
if (MemInfo == null)
|
||||||
{
|
{
|
||||||
@ -158,16 +127,15 @@ namespace Explorer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PrimitiveType == PrimitiveTypes.String)
|
if (PrimitiveType == Types.String)
|
||||||
{
|
{
|
||||||
Value = value;
|
Value = valueString;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var val = ParseMethod.Invoke(null, new object[] { value });
|
Value = ParseMethod.Invoke(null, new object[] { valueString });
|
||||||
Value = val;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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 class CppExplorer : MelonMod
|
||||||
{
|
{
|
||||||
public const string GUID = "com.sinai.cppexplorer";
|
public const string GUID = "com.sinai.cppexplorer";
|
||||||
public const string VERSION = "1.5.1";
|
public const string VERSION = "1.5.7";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
|
|
||||||
public const string NAME = "CppExplorer"
|
public const string NAME = "CppExplorer"
|
||||||
@ -99,6 +99,8 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void OnGUI()
|
public override void OnGUI()
|
||||||
{
|
{
|
||||||
|
if (!ShowMenu) return;
|
||||||
|
|
||||||
MainMenu.Instance.OnGUI();
|
MainMenu.Instance.OnGUI();
|
||||||
WindowManager.Instance.OnGUI();
|
WindowManager.Instance.OnGUI();
|
||||||
InspectUnderMouse.OnGUI();
|
InspectUnderMouse.OnGUI();
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
<DebugSymbols>false</DebugSymbols>
|
<DebugSymbols>false</DebugSymbols>
|
||||||
<DebugType>none</DebugType>
|
<DebugType>none</DebugType>
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>..\Release\</OutputPath>
|
<OutputPath>..\Release\2019\</OutputPath>
|
||||||
<DefineConstants>DEBUG</DefineConstants>
|
<DefineConstants>Release_2019</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<DebugSymbols>false</DebugSymbols>
|
<DebugSymbols>false</DebugSymbols>
|
||||||
<DebugType>none</DebugType>
|
<DebugType>none</DebugType>
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>..\Release\</OutputPath>
|
<OutputPath>..\Release\2018\</OutputPath>
|
||||||
<DefineConstants>Release_Unity2018</DefineConstants>
|
<DefineConstants>Release_Unity2018</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="mcs">
|
<Reference Include="mcs">
|
||||||
<HintPath>..\lib\mcs.dll</HintPath>
|
<HintPath>..\lib\mcs.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="MelonLoader.ModHandler">
|
<Reference Include="MelonLoader.ModHandler">
|
||||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\MelonLoader.ModHandler.dll</HintPath>
|
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\MelonLoader.ModHandler.dll</HintPath>
|
||||||
@ -60,9 +60,7 @@
|
|||||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerBaseLib.dll</HintPath>
|
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerBaseLib.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
||||||
<!-- Unity 2019 build (InputLegacyModule.dll) -->
|
<!-- Unity 2019 build (InputLegacyModule.dll) -->
|
||||||
|
|
||||||
<Reference Include="UnityEngine" Condition="'$(Configuration)'=='Debug'">
|
<Reference Include="UnityEngine" Condition="'$(Configuration)'=='Debug'">
|
||||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.dll</HintPath>
|
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
@ -91,9 +89,7 @@
|
|||||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.UI.dll</HintPath>
|
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.UI.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
||||||
<!-- Unity 2018 build (InputModule.dll) -->
|
<!-- Unity 2018 build (InputModule.dll) -->
|
||||||
|
|
||||||
<Reference Include="UnityEngine" Condition="'$(Configuration)'=='Release_Unity2018'">
|
<Reference Include="UnityEngine" Condition="'$(Configuration)'=='Release_Unity2018'">
|
||||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.dll</HintPath>
|
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
@ -122,24 +118,32 @@
|
|||||||
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.UI.dll</HintPath>
|
<HintPath>..\..\..\Steam\steamapps\common\VRChat\MelonLoader\Managed\UnityEngine.UI.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="CachedObjects\CacheDictionary.cs" />
|
<Compile Include="CachedObjects\Struct\CacheColor.cs" />
|
||||||
<Compile Include="CachedObjects\CacheEnum.cs" />
|
<Compile Include="CachedObjects\Object\CacheDictionary.cs" />
|
||||||
<Compile Include="CachedObjects\CacheGameObject.cs" />
|
<Compile Include="CachedObjects\Struct\CacheEnum.cs" />
|
||||||
<Compile Include="CachedObjects\CacheList.cs" />
|
<Compile Include="CachedObjects\Object\CacheGameObject.cs" />
|
||||||
<Compile Include="CachedObjects\CachePrimitive.cs" />
|
<Compile Include="CachedObjects\Object\CacheList.cs" />
|
||||||
<Compile Include="CachedObjects\CacheOther.cs" />
|
<Compile Include="CachedObjects\Struct\CachePrimitive.cs" />
|
||||||
<Compile Include="CachedObjects\CacheMethod.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="CppExplorer.cs" />
|
||||||
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
||||||
|
<Compile Include="UnstripFixes\GUIUnstrip.cs" />
|
||||||
|
<Compile Include="UnstripFixes\ScrollViewStateUnstrip.cs" />
|
||||||
<Compile Include="Extensions\UnityExtensions.cs" />
|
<Compile Include="Extensions\UnityExtensions.cs" />
|
||||||
|
<Compile Include="Helpers\PageHelper.cs" />
|
||||||
<Compile Include="Helpers\ReflectionHelpers.cs" />
|
<Compile Include="Helpers\ReflectionHelpers.cs" />
|
||||||
<Compile Include="Helpers\UIHelpers.cs" />
|
<Compile Include="Helpers\UIHelpers.cs" />
|
||||||
<Compile Include="Helpers\UnityHelpers.cs" />
|
<Compile Include="Helpers\UnityHelpers.cs" />
|
||||||
<Compile Include="MainMenu\InspectUnderMouse.cs" />
|
<Compile Include="MainMenu\InspectUnderMouse.cs" />
|
||||||
<Compile Include="CachedObjects\CacheObjectBase.cs" />
|
<Compile Include="CachedObjects\CacheObjectBase.cs" />
|
||||||
|
<Compile Include="UnstripFixes\SliderHandlerUnstrip.cs" />
|
||||||
|
<Compile Include="UnstripFixes\UnstripExtensions.cs" />
|
||||||
<Compile Include="Windows\ResizeDrag.cs" />
|
<Compile Include="Windows\ResizeDrag.cs" />
|
||||||
<Compile Include="Windows\TabViewWindow.cs" />
|
<Compile Include="Windows\TabViewWindow.cs" />
|
||||||
<Compile Include="Windows\UIWindow.cs" />
|
<Compile Include="Windows\UIWindow.cs" />
|
||||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using UnhollowerBaseLib;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
|
98
src/Helpers/PageHelper.cs
Normal file
98
src/Helpers/PageHelper.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public enum Turn
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Right
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PageHelper
|
||||||
|
{
|
||||||
|
public int PageOffset { get; set; }
|
||||||
|
public int ItemsPerPage { get; set; } = 20;
|
||||||
|
public int ItemCount
|
||||||
|
{
|
||||||
|
get => m_count;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_count = value;
|
||||||
|
CalculateMaxOffset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private int m_count;
|
||||||
|
|
||||||
|
public int MaxPageOffset { get; private set; } = -1;
|
||||||
|
|
||||||
|
private int CalculateMaxOffset()
|
||||||
|
{
|
||||||
|
return MaxPageOffset = (int)Mathf.Ceil((float)(ItemCount / (decimal)ItemsPerPage)) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CurrentPageLabel()
|
||||||
|
{
|
||||||
|
var orig = GUI.skin.label.alignment;
|
||||||
|
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||||
|
|
||||||
|
GUILayout.Label($"Page {PageOffset + 1}/{MaxPageOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
||||||
|
|
||||||
|
GUI.skin.label.alignment = orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TurnPage(Turn direction)
|
||||||
|
{
|
||||||
|
var _ = Vector2.zero;
|
||||||
|
TurnPage(direction, ref _);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TurnPage(Turn direction, ref Vector2 scroll)
|
||||||
|
{
|
||||||
|
if (direction == Turn.Left)
|
||||||
|
{
|
||||||
|
if (PageOffset > 0)
|
||||||
|
{
|
||||||
|
PageOffset--;
|
||||||
|
scroll = Vector2.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (PageOffset < MaxPageOffset)
|
||||||
|
{
|
||||||
|
PageOffset++;
|
||||||
|
scroll = Vector2.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CalculateOffsetIndex()
|
||||||
|
{
|
||||||
|
int offset = PageOffset * ItemsPerPage;
|
||||||
|
|
||||||
|
if (offset >= ItemCount)
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
PageOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawLimitInputArea()
|
||||||
|
{
|
||||||
|
GUILayout.Label("Limit: ", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||||
|
var limit = this.ItemsPerPage.ToString();
|
||||||
|
limit = GUILayout.TextField(limit, new GUILayoutOption[] { GUILayout.Width(50) });
|
||||||
|
if (limit != ItemsPerPage.ToString() && int.TryParse(limit, out int i))
|
||||||
|
{
|
||||||
|
ItemsPerPage = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnhollowerRuntimeLib;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
@ -22,11 +24,13 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// helper for drawing a styled button for a GameObject or Transform
|
// helper for drawing a styled button for a GameObject or Transform
|
||||||
public static void GameobjButton(GameObject obj, Action<Transform> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
|
public static void GOButton(object _obj, Action<Transform> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
|
||||||
{
|
{
|
||||||
bool children = obj.transform.childCount > 0;
|
var obj = (_obj as GameObject) ?? (_obj as Transform).gameObject;
|
||||||
|
|
||||||
string label = children ? "[" + obj.transform.childCount + " children] " : "";
|
bool hasChild = obj.transform.childCount > 0;
|
||||||
|
|
||||||
|
string label = hasChild ? $"[{obj.transform.childCount} children] " : "";
|
||||||
label += obj.name;
|
label += obj.name;
|
||||||
|
|
||||||
bool enabled = obj.activeSelf;
|
bool enabled = obj.activeSelf;
|
||||||
@ -49,11 +53,13 @@ namespace Explorer
|
|||||||
color = Color.red;
|
color = Color.red;
|
||||||
}
|
}
|
||||||
|
|
||||||
FastGameobjButton(obj, color, label, obj.activeSelf, specialInspectMethod, showSmallInspectBtn, width);
|
GOButton_Impl(_obj, color, label, obj.activeSelf, specialInspectMethod, showSmallInspectBtn, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void FastGameobjButton(GameObject obj, Color activeColor, string label, bool enabled, Action<Transform> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
|
public static void GOButton_Impl(object _obj, Color activeColor, string label, bool enabled, Action<Transform> specialInspectMethod = null, bool showSmallInspectBtn = true, float width = 380)
|
||||||
{
|
{
|
||||||
|
var obj = _obj as GameObject ?? (_obj as Transform).gameObject;
|
||||||
|
|
||||||
if (!obj)
|
if (!obj)
|
||||||
{
|
{
|
||||||
GUILayout.Label("<i><color=red>null</color></i>", null);
|
GUILayout.Label("<i><color=red>null</color></i>", null);
|
||||||
@ -83,7 +89,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WindowManager.InspectObject(obj, out bool _);
|
WindowManager.InspectObject(_obj, out bool _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +100,7 @@ namespace Explorer
|
|||||||
|
|
||||||
if (showSmallInspectBtn)
|
if (showSmallInspectBtn)
|
||||||
{
|
{
|
||||||
SmallInspectButton(obj);
|
SmallInspectButton(_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
@ -51,15 +51,12 @@ namespace Explorer
|
|||||||
|
|
||||||
public void OnGUI()
|
public void OnGUI()
|
||||||
{
|
{
|
||||||
if (CppExplorer.ShowMenu)
|
var origSkin = GUI.skin;
|
||||||
{
|
GUI.skin = UIStyles.WindowSkin;
|
||||||
var origSkin = GUI.skin;
|
|
||||||
GUI.skin = UIStyles.WindowSkin;
|
|
||||||
|
|
||||||
MainRect = GUI.Window(MainWindowID, MainRect, (GUI.WindowFunction)MainWindow, CppExplorer.NAME);
|
MainRect = GUI.Window(MainWindowID, MainRect, (GUI.WindowFunction)MainWindow, CppExplorer.NAME);
|
||||||
|
|
||||||
GUI.skin = origSkin;
|
GUI.skin = origSkin;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MainWindow(int id)
|
private void MainWindow(int id)
|
||||||
@ -77,9 +74,12 @@ namespace Explorer
|
|||||||
MainHeader();
|
MainHeader();
|
||||||
|
|
||||||
var page = Pages[m_currentPage];
|
var page = Pages[m_currentPage];
|
||||||
page.scroll = GUILayout.BeginScrollView(page.scroll, GUI.skin.scrollView);
|
|
||||||
|
page.scroll = GUIUnstrip.BeginScrollView(page.scroll);
|
||||||
|
|
||||||
page.DrawWindow();
|
page.DrawWindow();
|
||||||
GUILayout.EndScrollView();
|
|
||||||
|
GUIUnstrip.EndScrollView();
|
||||||
|
|
||||||
MainRect = ResizeDrag.ResizeWindow(MainRect, MainWindowID);
|
MainRect = ResizeDrag.ResizeWindow(MainRect, MainWindowID);
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public class ConsolePage : WindowPage
|
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 ScriptEvaluator _evaluator;
|
||||||
private readonly StringBuilder _sb = new StringBuilder();
|
private readonly StringBuilder _sb = new StringBuilder();
|
||||||
|
@ -12,21 +12,22 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public static ScenePage Instance;
|
public static ScenePage Instance;
|
||||||
|
|
||||||
public override string Name { get => "Scene Explorer"; set => base.Name = value; }
|
public override string Name { get => "Scene Explorer"; }
|
||||||
|
|
||||||
private int m_pageOffset = 0;
|
public PageHelper Pages = new PageHelper();
|
||||||
private int m_limit = 20;
|
|
||||||
private int m_currentTotalCount = 0;
|
|
||||||
|
|
||||||
private float m_timeOfLastUpdate = -1f;
|
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
|
// gameobject list
|
||||||
private Transform m_currentTransform;
|
private Transform m_currentTransform;
|
||||||
private List<GameObjectCache> m_objectList = new List<GameObjectCache>();
|
private readonly List<GameObjectCache> m_objectList = new List<GameObjectCache>();
|
||||||
|
|
||||||
// search bar
|
// search bar
|
||||||
private bool m_searching = false;
|
private bool m_searching = false;
|
||||||
@ -46,61 +47,6 @@ namespace Explorer
|
|||||||
SetTransformTarget(null);
|
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>();
|
|
||||||
int offset = m_pageOffset * m_limit;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_currentTotalCount = allTransforms.Count;
|
|
||||||
|
|
||||||
// make sure offset doesn't exceed count
|
|
||||||
CheckOffset(ref offset, m_currentTotalCount);
|
|
||||||
|
|
||||||
// sort by childcount
|
|
||||||
allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
|
||||||
|
|
||||||
for (int i = offset; i < offset + m_limit && i < m_currentTotalCount; i++)
|
|
||||||
{
|
|
||||||
var child = allTransforms[i];
|
|
||||||
m_objectList.Add(new GameObjectCache(child.gameObject));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTransformTarget(Transform t)
|
public void SetTransformTarget(Transform t)
|
||||||
{
|
{
|
||||||
m_currentTransform = t;
|
m_currentTransform = t;
|
||||||
@ -108,8 +54,7 @@ namespace Explorer
|
|||||||
if (m_searching)
|
if (m_searching)
|
||||||
CancelSearch();
|
CancelSearch();
|
||||||
|
|
||||||
m_timeOfLastUpdate = -1f;
|
Update_Impl(true);
|
||||||
Update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TraverseUp()
|
public void TraverseUp()
|
||||||
@ -128,29 +73,124 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
m_searchResults = SearchSceneObjects(m_searchInput);
|
m_searchResults = SearchSceneObjects(m_searchInput);
|
||||||
m_searching = true;
|
m_searching = true;
|
||||||
m_currentTotalCount = m_searchResults.Count;
|
Pages.ItemCount = m_searchResults.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelSearch()
|
public void CancelSearch()
|
||||||
{
|
{
|
||||||
m_searching = false;
|
m_searching = false;
|
||||||
|
|
||||||
|
if (m_getRootObjectsFailed && !m_currentTransform)
|
||||||
|
{
|
||||||
|
GetRootObjectsManual_Impl();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GameObjectCache> SearchSceneObjects(string _search)
|
public List<GameObjectCache> SearchSceneObjects(string _search)
|
||||||
{
|
{
|
||||||
var matches = new List<GameObjectCache>();
|
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;
|
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 --------- //
|
// --------- GUI Draw Function --------- //
|
||||||
|
|
||||||
public override void DrawWindow()
|
public override void DrawWindow()
|
||||||
@ -242,34 +282,24 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
GUILayout.Label("Limit per page: ", new GUILayoutOption[] { GUILayout.Width(100) });
|
Pages.DrawLimitInputArea();
|
||||||
var limit = m_limit.ToString();
|
|
||||||
limit = GUILayout.TextField(limit, new GUILayoutOption[] { GUILayout.Width(30) });
|
|
||||||
if (int.TryParse(limit, out int lim))
|
|
||||||
{
|
|
||||||
m_limit = lim;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prev/next page buttons
|
if (Pages.ItemCount > Pages.ItemsPerPage)
|
||||||
if (m_currentTotalCount > m_limit)
|
|
||||||
{
|
{
|
||||||
int count = m_currentTotalCount;
|
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)m_limit)) - 1;
|
|
||||||
if (GUILayout.Button("< Prev", null))
|
|
||||||
{
|
{
|
||||||
if (m_pageOffset > 0) m_pageOffset--;
|
Pages.TurnPage(Turn.Left, ref this.scroll);
|
||||||
m_timeOfLastUpdate = -1f;
|
|
||||||
Update();
|
Update_Impl(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
Pages.CurrentPageLabel();
|
||||||
GUILayout.Label($"Page {m_pageOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
|
||||||
|
|
||||||
if (GUILayout.Button("Next >", null))
|
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
{
|
{
|
||||||
if (m_pageOffset < maxOffset) m_pageOffset++;
|
Pages.TurnPage(Turn.Right, ref this.scroll);
|
||||||
m_timeOfLastUpdate = -1f;
|
|
||||||
Update();
|
Update_Impl(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,12 +329,24 @@ namespace Explorer
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Label("Scene Root GameObjects:", null);
|
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)
|
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)
|
if (!obj.RefGameObject)
|
||||||
{
|
{
|
||||||
string label = "<color=red><i>null";
|
string label = "<color=red><i>null";
|
||||||
@ -319,7 +361,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UIHelpers.FastGameobjButton(obj.RefGameObject,
|
UIHelpers.GOButton_Impl(obj.RefGameObject,
|
||||||
obj.EnabledColor,
|
obj.EnabledColor,
|
||||||
obj.Label,
|
obj.Label,
|
||||||
obj.RefGameObject.activeSelf,
|
obj.RefGameObject.activeSelf,
|
||||||
@ -342,21 +384,15 @@ namespace Explorer
|
|||||||
|
|
||||||
if (m_searchResults.Count > 0)
|
if (m_searchResults.Count > 0)
|
||||||
{
|
{
|
||||||
int offset = m_pageOffset * m_limit;
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
if (offset >= m_searchResults.Count)
|
for (int i = offset; i < offset + Pages.ItemsPerPage && i < m_searchResults.Count; i++)
|
||||||
{
|
|
||||||
offset = 0;
|
|
||||||
m_pageOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = offset; i < offset + m_limit && i < m_searchResults.Count; i++)
|
|
||||||
{
|
{
|
||||||
var obj = m_searchResults[i];
|
var obj = m_searchResults[i];
|
||||||
|
|
||||||
if (obj.RefGameObject)
|
if (obj.RefGameObject)
|
||||||
{
|
{
|
||||||
UIHelpers.FastGameobjButton(obj.RefGameObject,
|
UIHelpers.GOButton_Impl(obj.RefGameObject,
|
||||||
obj.EnabledColor,
|
obj.EnabledColor,
|
||||||
obj.Label,
|
obj.Label,
|
||||||
obj.RefGameObject.activeSelf,
|
obj.RefGameObject.activeSelf,
|
||||||
|
@ -5,11 +5,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
using UnhollowerRuntimeLib;
|
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using UnhollowerBaseLib;
|
|
||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
@ -17,15 +13,15 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public static SearchPage Instance;
|
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_searchInput = "";
|
||||||
private string m_typeInput = "";
|
private string m_typeInput = "";
|
||||||
private int m_limit = 20;
|
|
||||||
private int m_pageOffset = 0;
|
|
||||||
//private List<object> m_searchResults = new List<object>();
|
|
||||||
private Vector2 resultsScroll = Vector2.zero;
|
private Vector2 resultsScroll = Vector2.zero;
|
||||||
|
|
||||||
|
public PageHelper Pages = new PageHelper();
|
||||||
|
|
||||||
private List<CacheObjectBase> m_searchResults = new List<CacheObjectBase>();
|
private List<CacheObjectBase> m_searchResults = new List<CacheObjectBase>();
|
||||||
|
|
||||||
public SceneFilter SceneMode = SceneFilter.Any;
|
public SceneFilter SceneMode = SceneFilter.Any;
|
||||||
@ -55,7 +51,7 @@ namespace Explorer
|
|||||||
public void OnSceneChange()
|
public void OnSceneChange()
|
||||||
{
|
{
|
||||||
m_searchResults.Clear();
|
m_searchResults.Clear();
|
||||||
m_pageOffset = 0;
|
Pages.PageOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
@ -78,6 +74,9 @@ namespace Explorer
|
|||||||
var cache = CacheObjectBase.GetCacheObject(toCache);
|
var cache = CacheObjectBase.GetCacheObject(toCache);
|
||||||
m_searchResults.Add(cache);
|
m_searchResults.Add(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pages.ItemCount = m_searchResults.Count;
|
||||||
|
Pages.PageOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawWindow()
|
public override void DrawWindow()
|
||||||
@ -90,8 +89,7 @@ namespace Explorer
|
|||||||
if (GUILayout.Button("Find Static Instances", new GUILayoutOption[] { GUILayout.Width(180) }))
|
if (GUILayout.Button("Find Static Instances", new GUILayoutOption[] { GUILayout.Width(180) }))
|
||||||
{
|
{
|
||||||
//m_searchResults = GetInstanceClassScanner().ToList();
|
//m_searchResults = GetInstanceClassScanner().ToList();
|
||||||
CacheResults(GetInstanceClassScanner());
|
CacheResults(GetInstanceClassScanner());
|
||||||
m_pageOffset = 0;
|
|
||||||
}
|
}
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
@ -107,35 +105,43 @@ namespace Explorer
|
|||||||
|
|
||||||
int count = m_searchResults.Count;
|
int count = m_searchResults.Count;
|
||||||
|
|
||||||
if (count > this.m_limit)
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
|
Pages.DrawLimitInputArea();
|
||||||
|
|
||||||
|
if (count > Pages.ItemsPerPage)
|
||||||
{
|
{
|
||||||
// prev/next page buttons
|
// prev/next page buttons
|
||||||
GUILayout.BeginHorizontal(null);
|
|
||||||
int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)m_limit)) - 1;
|
|
||||||
if (GUILayout.Button("< Prev", null))
|
|
||||||
{
|
|
||||||
if (m_pageOffset > 0) m_pageOffset--;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.Label($"Page {m_pageOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
if (Pages.ItemCount > Pages.ItemsPerPage)
|
||||||
|
|
||||||
if (GUILayout.Button("Next >", null))
|
|
||||||
{
|
{
|
||||||
if (m_pageOffset < maxOffset) m_pageOffset++;
|
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
|
{
|
||||||
|
Pages.TurnPage(Turn.Left, ref this.resultsScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pages.CurrentPageLabel();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
|
{
|
||||||
|
Pages.TurnPage(Turn.Right, ref this.resultsScroll);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resultsScroll = GUILayout.BeginScrollView(resultsScroll, GUI.skin.scrollView);
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
resultsScroll = GUIUnstrip.BeginScrollView(resultsScroll);
|
||||||
|
|
||||||
var _temprect = new Rect(MainMenu.MainRect.x, MainMenu.MainRect.y, MainMenu.MainRect.width + 160, MainMenu.MainRect.height);
|
var _temprect = new Rect(MainMenu.MainRect.x, MainMenu.MainRect.y, MainMenu.MainRect.width + 160, MainMenu.MainRect.height);
|
||||||
|
|
||||||
if (m_searchResults.Count > 0)
|
if (m_searchResults.Count > 0)
|
||||||
{
|
{
|
||||||
int offset = m_pageOffset * this.m_limit;
|
//int offset = m_pageOffset * this.m_limit;
|
||||||
if (offset >= count) m_pageOffset = 0;
|
//if (offset >= count) m_pageOffset = 0;
|
||||||
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
for (int i = offset; i < offset + m_limit && i < count; i++)
|
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
||||||
{
|
{
|
||||||
m_searchResults[i].Draw(MainMenu.MainRect, 0f);
|
m_searchResults[i].Draw(MainMenu.MainRect, 0f);
|
||||||
//m_searchResults[i].DrawValue(MainMenu.MainRect);
|
//m_searchResults[i].DrawValue(MainMenu.MainRect);
|
||||||
@ -146,7 +152,7 @@ namespace Explorer
|
|||||||
GUILayout.Label("<color=red><i>No results found!</i></color>", null);
|
GUILayout.Label("<color=red><i>No results found!</i></color>", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.EndScrollView();
|
GUIUnstrip.EndScrollView();
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -169,15 +175,15 @@ namespace Explorer
|
|||||||
GUILayout.Label("Name Contains:", new GUILayoutOption[] { GUILayout.Width(100) });
|
GUILayout.Label("Name Contains:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||||
m_searchInput = GUILayout.TextField(m_searchInput, new GUILayoutOption[] { GUILayout.Width(200) });
|
m_searchInput = GUILayout.TextField(m_searchInput, new GUILayoutOption[] { GUILayout.Width(200) });
|
||||||
|
|
||||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
//GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||||
GUILayout.Label("Results per page:", new GUILayoutOption[] { GUILayout.Width(120) });
|
//GUILayout.Label("Results per page:", new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
var resultinput = m_limit.ToString();
|
//var resultinput = m_limit.ToString();
|
||||||
resultinput = GUILayout.TextField(resultinput, new GUILayoutOption[] { GUILayout.Width(55) });
|
//resultinput = GUILayout.TextField(resultinput, new GUILayoutOption[] { GUILayout.Width(55) });
|
||||||
if (int.TryParse(resultinput, out int _i) && _i > 0)
|
//if (int.TryParse(resultinput, out int _i) && _i > 0)
|
||||||
{
|
//{
|
||||||
m_limit = _i;
|
// m_limit = _i;
|
||||||
}
|
//}
|
||||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
//GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
|
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
@ -256,7 +262,7 @@ namespace Explorer
|
|||||||
|
|
||||||
private void Search()
|
private void Search()
|
||||||
{
|
{
|
||||||
m_pageOffset = 0;
|
Pages.PageOffset = 0;
|
||||||
CacheResults(FindAllObjectsOfType(m_searchInput, m_typeInput));
|
CacheResults(FindAllObjectsOfType(m_searchInput, m_typeInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +318,8 @@ namespace Explorer
|
|||||||
continue;
|
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.
|
// Transforms shouldn't really be counted as Components, skip them.
|
||||||
// They're more akin to GameObjects.
|
// They're more akin to GameObjects.
|
||||||
|
@ -9,7 +9,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public abstract class WindowPage
|
public abstract class WindowPage
|
||||||
{
|
{
|
||||||
public virtual string Name { get; set; }
|
public virtual string Name { get; }
|
||||||
|
|
||||||
public Vector2 scroll = Vector2.zero;
|
public Vector2 scroll = Vector2.zero;
|
||||||
|
|
||||||
|
402
src/UnstripFixes/GUIUnstrip.cs
Normal file
402
src/UnstripFixes/GUIUnstrip.cs
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnhollowerBaseLib;
|
||||||
|
using UnhollowerRuntimeLib;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngineInternal;
|
||||||
|
using Harmony;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public class GUIUnstrip
|
||||||
|
{
|
||||||
|
public static int s_ScrollControlId;
|
||||||
|
|
||||||
|
public static bool ScrollFailed = false;
|
||||||
|
public static bool ManualUnstripFailed = false;
|
||||||
|
|
||||||
|
private static GenericStack ScrollStack
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
#if Release_2019
|
||||||
|
return GUI.scrollViewStates;
|
||||||
|
#else
|
||||||
|
return GUI.s_ScrollViewStates;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======= public methods ======= //
|
||||||
|
|
||||||
|
public static Rect GetLastRect()
|
||||||
|
{
|
||||||
|
EventType type = Event.current.type;
|
||||||
|
Rect last;
|
||||||
|
if (type != EventType.Layout && type != EventType.Used)
|
||||||
|
{
|
||||||
|
last = GUILayoutUtility.current.topLevel.GetLastUnstripped();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last = GUILayoutUtility.kDummyRect;
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float HorizontalScrollbar(Rect position, float value, float size, float leftValue, float rightValue, GUIStyle style)
|
||||||
|
{
|
||||||
|
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_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.
|
||||||
|
|
||||||
|
public static Vector2 BeginScrollView(Vector2 scroll, params GUILayoutOption[] options)
|
||||||
|
{
|
||||||
|
// First, just try normal way, may not have been stripped or was unstripped successfully.
|
||||||
|
if (!ScrollFailed)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return GUILayout.BeginScrollView(scroll, options);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
ScrollFailed = true;
|
||||||
|
return scroll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try manual implementation.
|
||||||
|
if (!ManualUnstripFailed)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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_ImplLayout: " + e.GetType() + ", " + e.Message + "\r\n" + e.StackTrace);
|
||||||
|
|
||||||
|
ManualUnstripFailed = true;
|
||||||
|
return scroll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sorry! No scrolling for you.
|
||||||
|
return scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EndScrollView(bool handleScrollWheel = true)
|
||||||
|
{
|
||||||
|
// Only end the scroll view for the relevant BeginScrollView option, if any.
|
||||||
|
|
||||||
|
if (!ScrollFailed)
|
||||||
|
{
|
||||||
|
GUILayout.EndScrollView();
|
||||||
|
}
|
||||||
|
else if (!ManualUnstripFailed)
|
||||||
|
{
|
||||||
|
GUILayoutUtility.EndLayoutGroup();
|
||||||
|
|
||||||
|
EndScrollView_Impl(handleScrollWheel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======= private methods ======= //
|
||||||
|
|
||||||
|
private static Vector2 BeginScrollView_ImplLayout(Vector2 scrollPosition, bool alwaysShowHorizontal, bool alwaysShowVertical,
|
||||||
|
GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options)
|
||||||
|
{
|
||||||
|
GUIUtility.CheckOnGUI();
|
||||||
|
|
||||||
|
var guiscrollGroup = GUILayoutUtility.BeginLayoutGroup(background, null, Il2CppType.Of<GUIScrollGroup>())
|
||||||
|
.TryCast<GUIScrollGroup>();
|
||||||
|
|
||||||
|
EventType type = Event.current.type;
|
||||||
|
if (type == EventType.Layout)
|
||||||
|
{
|
||||||
|
guiscrollGroup.resetCoords = true;
|
||||||
|
guiscrollGroup.isVertical = true;
|
||||||
|
guiscrollGroup.stretchWidth = 1;
|
||||||
|
guiscrollGroup.stretchHeight = 1;
|
||||||
|
guiscrollGroup.verticalScrollbar = verticalScrollbar;
|
||||||
|
guiscrollGroup.horizontalScrollbar = horizontalScrollbar;
|
||||||
|
guiscrollGroup.needsVerticalScrollbar = alwaysShowVertical;
|
||||||
|
guiscrollGroup.needsHorizontalScrollbar = alwaysShowHorizontal;
|
||||||
|
guiscrollGroup.ApplyOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BeginScrollView_Impl(guiscrollGroup.rect,
|
||||||
|
scrollPosition,
|
||||||
|
new Rect(0f, 0f, guiscrollGroup.clientWidth, guiscrollGroup.clientHeight),
|
||||||
|
alwaysShowHorizontal,
|
||||||
|
alwaysShowVertical,
|
||||||
|
horizontalScrollbar,
|
||||||
|
verticalScrollbar,
|
||||||
|
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 = GUIUtility.GetStateObject(Il2CppType.Of<ScrollViewState>(), controlID).TryCast<ScrollViewState>();
|
||||||
|
|
||||||
|
var scrollExt = ScrollViewStateUnstrip.FromPointer(scrollViewState.Pointer);
|
||||||
|
|
||||||
|
if (scrollExt == null) throw new Exception($"Could not get scrollExt for pointer '{scrollViewState.Pointer}'!");
|
||||||
|
|
||||||
|
bool apply = scrollExt.apply;
|
||||||
|
if (apply)
|
||||||
|
{
|
||||||
|
scrollPosition = scrollExt.scrollPosition;
|
||||||
|
scrollExt.apply = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollExt.position = position;
|
||||||
|
|
||||||
|
scrollExt.scrollPosition = scrollPosition;
|
||||||
|
scrollExt.visibleRect = scrollExt.viewRect = viewRect;
|
||||||
|
|
||||||
|
var rect = scrollExt.visibleRect;
|
||||||
|
rect.width = position.width;
|
||||||
|
rect.height = position.height;
|
||||||
|
|
||||||
|
ScrollStack.Push(scrollViewState);
|
||||||
|
|
||||||
|
Rect screenRect = new Rect(position.x, position.y, position.width, position.height);
|
||||||
|
EventType type = Event.current.type;
|
||||||
|
if (type != EventType.Layout)
|
||||||
|
{
|
||||||
|
if (type != EventType.Used)
|
||||||
|
{
|
||||||
|
bool flag = alwaysShowVertical;
|
||||||
|
bool flag2 = alwaysShowHorizontal;
|
||||||
|
if (flag2 || viewRect.width > screenRect.width)
|
||||||
|
{
|
||||||
|
rect.height = position.height - horizontalScrollbar.fixedHeight + (float)horizontalScrollbar.margin.top;
|
||||||
|
|
||||||
|
screenRect.height -= horizontalScrollbar.fixedHeight + (float)horizontalScrollbar.margin.top;
|
||||||
|
flag2 = true;
|
||||||
|
}
|
||||||
|
if (flag || viewRect.height > screenRect.height)
|
||||||
|
{
|
||||||
|
rect.width = position.width - verticalScrollbar.fixedWidth + (float)verticalScrollbar.margin.left;
|
||||||
|
|
||||||
|
screenRect.width -= verticalScrollbar.fixedWidth + (float)verticalScrollbar.margin.left;
|
||||||
|
flag = true;
|
||||||
|
if (!flag2 && viewRect.width > screenRect.width)
|
||||||
|
{
|
||||||
|
rect.height = position.height - horizontalScrollbar.fixedHeight + (float)horizontalScrollbar.margin.top;
|
||||||
|
screenRect.height -= horizontalScrollbar.fixedHeight + (float)horizontalScrollbar.margin.top;
|
||||||
|
flag2 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Event.current.type == EventType.Repaint && background != GUIStyle.none)
|
||||||
|
{
|
||||||
|
background.Draw(position, position.Contains(Event.current.mousePosition), false, flag2 && flag, false);
|
||||||
|
}
|
||||||
|
if (flag2 && horizontalScrollbar != GUIStyle.none)
|
||||||
|
{
|
||||||
|
scrollPosition.x = HorizontalScrollbar(
|
||||||
|
new Rect(
|
||||||
|
position.x,
|
||||||
|
position.yMax - horizontalScrollbar.fixedHeight,
|
||||||
|
screenRect.width,
|
||||||
|
horizontalScrollbar.fixedHeight),
|
||||||
|
scrollPosition.x,
|
||||||
|
Mathf.Min(screenRect.width, viewRect.width),
|
||||||
|
0f,
|
||||||
|
viewRect.width,
|
||||||
|
horizontalScrollbar
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUIUtility.GetControlID(GUI.s_SliderHash, FocusType.Passive);
|
||||||
|
GUIUtility.GetControlID(GUI.s_RepeatButtonHash, FocusType.Passive);
|
||||||
|
GUIUtility.GetControlID(GUI.s_RepeatButtonHash, FocusType.Passive);
|
||||||
|
scrollPosition.x = ((horizontalScrollbar == GUIStyle.none) ? Mathf.Clamp(scrollPosition.x, 0f, Mathf.Max(viewRect.width - position.width, 0f)) : 0f);
|
||||||
|
}
|
||||||
|
if (flag && verticalScrollbar != GUIStyle.none)
|
||||||
|
{
|
||||||
|
scrollPosition.y = VerticalScrollbar(
|
||||||
|
new Rect(
|
||||||
|
screenRect.xMax + (float)verticalScrollbar.margin.left,
|
||||||
|
screenRect.y,
|
||||||
|
verticalScrollbar.fixedWidth,
|
||||||
|
screenRect.height),
|
||||||
|
scrollPosition.y,
|
||||||
|
Mathf.Min(screenRect.height, viewRect.height),
|
||||||
|
0f,
|
||||||
|
viewRect.height,
|
||||||
|
verticalScrollbar
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUIUtility.GetControlID(GUI.s_SliderHash, FocusType.Passive);
|
||||||
|
GUIUtility.GetControlID(GUI.s_RepeatButtonHash, FocusType.Passive);
|
||||||
|
GUIUtility.GetControlID(GUI.s_RepeatButtonHash, FocusType.Passive);
|
||||||
|
scrollPosition.y = ((verticalScrollbar == GUIStyle.none) ? Mathf.Clamp(scrollPosition.y, 0f, Mathf.Max(viewRect.height - position.height, 0f)) : 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUIUtility.GetControlID(GUI.s_SliderHash, FocusType.Passive);
|
||||||
|
GUIUtility.GetControlID(GUI.s_RepeatButtonHash, FocusType.Passive);
|
||||||
|
GUIUtility.GetControlID(GUI.s_RepeatButtonHash, FocusType.Passive);
|
||||||
|
GUIUtility.GetControlID(GUI.s_SliderHash, FocusType.Passive);
|
||||||
|
GUIUtility.GetControlID(GUI.s_RepeatButtonHash, FocusType.Passive);
|
||||||
|
GUIUtility.GetControlID(GUI.s_RepeatButtonHash, FocusType.Passive);
|
||||||
|
}
|
||||||
|
GUIClip.Push(screenRect, new Vector2(Mathf.Round(-scrollPosition.x - viewRect.x), Mathf.Round(-scrollPosition.y - viewRect.y)), Vector2.zero, false);
|
||||||
|
|
||||||
|
return scrollPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EndScrollView_Impl(bool handleScrollWheel)
|
||||||
|
{
|
||||||
|
GUIUtility.CheckOnGUI();
|
||||||
|
|
||||||
|
if (ScrollStack.Count <= 0) return;
|
||||||
|
|
||||||
|
var state = ScrollStack.Peek().TryCast<ScrollViewState>();
|
||||||
|
var scrollExt = ScrollViewStateUnstrip.FromPointer(state.Pointer);
|
||||||
|
|
||||||
|
if (scrollExt == null) throw new Exception("Could not get scrollExt!");
|
||||||
|
|
||||||
|
GUIClip.Pop();
|
||||||
|
|
||||||
|
ScrollStack.Pop();
|
||||||
|
|
||||||
|
var position = scrollExt.position;
|
||||||
|
|
||||||
|
if (handleScrollWheel && Event.current.type == EventType.ScrollWheel && position.Contains(Event.current.mousePosition))
|
||||||
|
{
|
||||||
|
var pos = scrollExt.scrollPosition;
|
||||||
|
pos.x = Mathf.Clamp(scrollExt.scrollPosition.x + Event.current.delta.x * 20f, 0f, scrollExt.viewRect.width - scrollExt.visibleRect.width);
|
||||||
|
pos.y = Mathf.Clamp(scrollExt.scrollPosition.y + Event.current.delta.y * 20f, 0f, scrollExt.viewRect.height - scrollExt.visibleRect.height);
|
||||||
|
|
||||||
|
if (scrollExt.scrollPosition.x < 0f)
|
||||||
|
{
|
||||||
|
pos.x = 0f;
|
||||||
|
}
|
||||||
|
if (pos.y < 0f)
|
||||||
|
{
|
||||||
|
pos.y = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollExt.apply = true;
|
||||||
|
|
||||||
|
Event.current.Use();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
int controlID = GUIUtility.GetControlID(GUI.s_SliderHash, FocusType.Passive, position);
|
||||||
|
Rect position2;
|
||||||
|
Rect rect;
|
||||||
|
Rect rect2;
|
||||||
|
if (horiz)
|
||||||
|
{
|
||||||
|
position2 = new Rect(position.x + leftButton.fixedWidth, position.y, position.width - leftButton.fixedWidth - rightButton.fixedWidth, position.height);
|
||||||
|
rect = new Rect(position.x, position.y, leftButton.fixedWidth, position.height);
|
||||||
|
rect2 = new Rect(position.xMax - rightButton.fixedWidth, position.y, rightButton.fixedWidth, position.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position2 = new Rect(position.x, position.y + leftButton.fixedHeight, position.width, position.height - leftButton.fixedHeight - rightButton.fixedHeight);
|
||||||
|
rect = new Rect(position.x, position.y, position.width, leftButton.fixedHeight);
|
||||||
|
rect2 = new Rect(position.x, position.yMax - rightButton.fixedHeight, position.width, rightButton.fixedHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
value = Slider(position2, value, size, leftValue, rightValue, slider, thumb, horiz, controlID);
|
||||||
|
|
||||||
|
bool flag = Event.current.type == EventType.MouseUp;
|
||||||
|
if (ScrollerRepeatButton_Impl(controlID, rect, leftButton))
|
||||||
|
{
|
||||||
|
value -= 10f * ((leftValue >= rightValue) ? -1f : 1f);
|
||||||
|
}
|
||||||
|
if (ScrollerRepeatButton_Impl(controlID, rect2, rightButton))
|
||||||
|
{
|
||||||
|
value += 10f * ((leftValue >= rightValue) ? -1f : 1f);
|
||||||
|
}
|
||||||
|
if (flag && Event.current.type == EventType.Used)
|
||||||
|
{
|
||||||
|
s_ScrollControlId = 0;
|
||||||
|
}
|
||||||
|
if (leftValue < rightValue)
|
||||||
|
{
|
||||||
|
value = Mathf.Clamp(value, leftValue, rightValue - size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = Mathf.Clamp(value, rightValue, leftValue - size);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float Slider(Rect position, float value, float size, float start, float end, GUIStyle slider, GUIStyle thumb, bool horiz, int id)
|
||||||
|
{
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
id = GUIUtility.GetControlID(GUI.s_SliderHash, FocusType.Passive, position);
|
||||||
|
}
|
||||||
|
var sliderHandler = new SliderHandlerUnstrip(position, value, size, start, end, slider, thumb, horiz, id);
|
||||||
|
return sliderHandler.Handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = s_ScrollControlId != scrollerID;
|
||||||
|
s_ScrollControlId = scrollerID;
|
||||||
|
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
GUI.nextScrollStepTime = Il2CppSystem.DateTime.Now.AddMilliseconds(250.0);
|
||||||
|
}
|
||||||
|
else if (Il2CppSystem.DateTime.Now >= GUI.nextScrollStepTime)
|
||||||
|
{
|
||||||
|
result = true;
|
||||||
|
GUI.nextScrollStepTime = Il2CppSystem.DateTime.Now.AddMilliseconds(30.0);
|
||||||
|
}
|
||||||
|
if (Event.current.type == EventType.Repaint)
|
||||||
|
{
|
||||||
|
GUI.InternalRepaintEditorWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
src/UnstripFixes/ScrollViewStateUnstrip.cs
Normal file
32
src/UnstripFixes/ScrollViewStateUnstrip.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Harmony;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public class ScrollViewStateUnstrip
|
||||||
|
{
|
||||||
|
public Rect position;
|
||||||
|
public Rect visibleRect;
|
||||||
|
public Rect viewRect;
|
||||||
|
public Vector2 scrollPosition;
|
||||||
|
public bool apply;
|
||||||
|
|
||||||
|
public static Dictionary<IntPtr, ScrollViewStateUnstrip> Dict = new Dictionary<IntPtr, ScrollViewStateUnstrip>();
|
||||||
|
|
||||||
|
public static ScrollViewStateUnstrip FromPointer(IntPtr ptr)
|
||||||
|
{
|
||||||
|
if (!Dict.ContainsKey(ptr))
|
||||||
|
{
|
||||||
|
Dict.Add(ptr, new ScrollViewStateUnstrip());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Dict[ptr];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
371
src/UnstripFixes/SliderHandlerUnstrip.cs
Normal file
371
src/UnstripFixes/SliderHandlerUnstrip.cs
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnhollowerRuntimeLib;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public struct SliderHandlerUnstrip
|
||||||
|
{
|
||||||
|
private readonly Rect position;
|
||||||
|
private readonly float currentValue;
|
||||||
|
private readonly float size;
|
||||||
|
private readonly float start;
|
||||||
|
private readonly float end;
|
||||||
|
private readonly GUIStyle slider;
|
||||||
|
private readonly GUIStyle thumb;
|
||||||
|
private readonly bool horiz;
|
||||||
|
private readonly int id;
|
||||||
|
|
||||||
|
public SliderHandlerUnstrip(Rect position, float currentValue, float size, float start, float end, GUIStyle slider, GUIStyle thumb, bool horiz, int id)
|
||||||
|
{
|
||||||
|
this.position = position;
|
||||||
|
this.currentValue = currentValue;
|
||||||
|
this.size = size;
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.slider = slider;
|
||||||
|
this.thumb = thumb;
|
||||||
|
this.horiz = horiz;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Handle()
|
||||||
|
{
|
||||||
|
float result;
|
||||||
|
if (this.slider == null || this.thumb == null)
|
||||||
|
{
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (this.CurrentEventType())
|
||||||
|
{
|
||||||
|
case EventType.MouseDown:
|
||||||
|
return this.OnMouseDown();
|
||||||
|
case EventType.MouseUp:
|
||||||
|
return this.OnMouseUp();
|
||||||
|
case EventType.MouseDrag:
|
||||||
|
return this.OnMouseDrag();
|
||||||
|
case EventType.Repaint:
|
||||||
|
return this.OnRepaint();
|
||||||
|
}
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float OnMouseDown()
|
||||||
|
{
|
||||||
|
float result;
|
||||||
|
if (!this.position.Contains(this.CurrentEvent().mousePosition) || this.IsEmptySlider())
|
||||||
|
{
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.scrollTroughSide = 0;
|
||||||
|
GUIUtility.hotControl = this.id;
|
||||||
|
this.CurrentEvent().Use();
|
||||||
|
if (this.ThumbSelectionRect().Contains(this.CurrentEvent().mousePosition))
|
||||||
|
{
|
||||||
|
this.StartDraggingWithValue(this.ClampedCurrentValue());
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.changed = true;
|
||||||
|
if (this.SupportsPageMovements())
|
||||||
|
{
|
||||||
|
this.SliderState().isDragging = false;
|
||||||
|
GUI.nextScrollStepTime = SystemClock.now.AddMilliseconds(250.0);
|
||||||
|
GUI.scrollTroughSide = this.CurrentScrollTroughSide();
|
||||||
|
result = this.PageMovementValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float num = this.ValueForCurrentMousePosition();
|
||||||
|
this.StartDraggingWithValue(num);
|
||||||
|
result = this.Clamp(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float OnMouseDrag()
|
||||||
|
{
|
||||||
|
float result;
|
||||||
|
if (GUIUtility.hotControl != this.id)
|
||||||
|
{
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SliderState sliderState = this.SliderState();
|
||||||
|
if (!sliderState.isDragging)
|
||||||
|
{
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.changed = true;
|
||||||
|
this.CurrentEvent().Use();
|
||||||
|
float num = this.MousePosition() - sliderState.dragStartPos;
|
||||||
|
float value = sliderState.dragStartValue + num / this.ValuesPerPixel();
|
||||||
|
result = this.Clamp(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float OnMouseUp()
|
||||||
|
{
|
||||||
|
if (GUIUtility.hotControl == this.id)
|
||||||
|
{
|
||||||
|
this.CurrentEvent().Use();
|
||||||
|
GUIUtility.hotControl = 0;
|
||||||
|
}
|
||||||
|
return this.currentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float OnRepaint()
|
||||||
|
{
|
||||||
|
this.slider.Draw(this.position, GUIContent.none, this.id);
|
||||||
|
if (!this.IsEmptySlider() && this.currentValue >= this.MinValue() && this.currentValue <= this.MaxValue())
|
||||||
|
{
|
||||||
|
this.thumb.Draw(this.ThumbRect(), GUIContent.none, this.id);
|
||||||
|
}
|
||||||
|
float result;
|
||||||
|
if (GUIUtility.hotControl != this.id || !this.position.Contains(this.CurrentEvent().mousePosition) || this.IsEmptySlider())
|
||||||
|
{
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
else if (this.ThumbRect().Contains(this.CurrentEvent().mousePosition))
|
||||||
|
{
|
||||||
|
if (GUI.scrollTroughSide != 0)
|
||||||
|
{
|
||||||
|
GUIUtility.hotControl = 0;
|
||||||
|
}
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.InternalRepaintEditorWindow();
|
||||||
|
if (SystemClock.now < GUI.nextScrollStepTime)
|
||||||
|
{
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
else if (this.CurrentScrollTroughSide() != GUI.scrollTroughSide)
|
||||||
|
{
|
||||||
|
result = this.currentValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.nextScrollStepTime = SystemClock.now.AddMilliseconds(30.0);
|
||||||
|
if (this.SupportsPageMovements())
|
||||||
|
{
|
||||||
|
this.SliderState().isDragging = false;
|
||||||
|
GUI.changed = true;
|
||||||
|
result = this.PageMovementValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = this.ClampedCurrentValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EventType CurrentEventType()
|
||||||
|
{
|
||||||
|
return this.CurrentEvent().GetTypeForControl(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int CurrentScrollTroughSide()
|
||||||
|
{
|
||||||
|
float num = (!this.horiz) ? this.CurrentEvent().mousePosition.y : this.CurrentEvent().mousePosition.x;
|
||||||
|
float num2 = (!this.horiz) ? this.ThumbRect().y : this.ThumbRect().x;
|
||||||
|
return (num <= num2) ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsEmptySlider()
|
||||||
|
{
|
||||||
|
return this.start == this.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SupportsPageMovements()
|
||||||
|
{
|
||||||
|
return this.size != 0f && GUI.usePageScrollbars;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float PageMovementValue()
|
||||||
|
{
|
||||||
|
float num = this.currentValue;
|
||||||
|
int num2 = (this.start <= this.end) ? 1 : -1;
|
||||||
|
if (this.MousePosition() > this.PageUpMovementBound())
|
||||||
|
{
|
||||||
|
num += this.size * (float)num2 * 0.9f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
num -= this.size * (float)num2 * 0.9f;
|
||||||
|
}
|
||||||
|
return this.Clamp(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float PageUpMovementBound()
|
||||||
|
{
|
||||||
|
float result;
|
||||||
|
if (this.horiz)
|
||||||
|
{
|
||||||
|
result = this.ThumbRect().xMax - this.position.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = this.ThumbRect().yMax - this.position.y;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Event CurrentEvent()
|
||||||
|
{
|
||||||
|
return Event.current;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float ValueForCurrentMousePosition()
|
||||||
|
{
|
||||||
|
float result;
|
||||||
|
if (this.horiz)
|
||||||
|
{
|
||||||
|
result = (this.MousePosition() - this.ThumbRect().width * 0.5f) / this.ValuesPerPixel() + this.start - this.size * 0.5f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = (this.MousePosition() - this.ThumbRect().height * 0.5f) / this.ValuesPerPixel() + this.start - this.size * 0.5f;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float Clamp(float value)
|
||||||
|
{
|
||||||
|
return Mathf.Clamp(value, this.MinValue(), this.MaxValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rect ThumbSelectionRect()
|
||||||
|
{
|
||||||
|
return this.ThumbRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartDraggingWithValue(float dragStartValue)
|
||||||
|
{
|
||||||
|
SliderState sliderState = this.SliderState();
|
||||||
|
sliderState.dragStartPos = this.MousePosition();
|
||||||
|
sliderState.dragStartValue = dragStartValue;
|
||||||
|
sliderState.isDragging = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SliderState SliderState()
|
||||||
|
{
|
||||||
|
return (SliderState)GUIUtility.GetStateObject(Il2CppType.Of<SliderState>(), this.id).TryCast<SliderState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rect ThumbRect()
|
||||||
|
{
|
||||||
|
return (!this.horiz) ? this.VerticalThumbRect() : this.HorizontalThumbRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rect VerticalThumbRect()
|
||||||
|
{
|
||||||
|
float num = this.ValuesPerPixel();
|
||||||
|
Rect result;
|
||||||
|
if (this.start < this.end)
|
||||||
|
{
|
||||||
|
result = new Rect(this.position.x + (float)this.slider.padding.left, (this.ClampedCurrentValue() - this.start) * num + this.position.y + (float)this.slider.padding.top, this.position.width - (float)this.slider.padding.horizontal, this.size * num + this.ThumbSize());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = new Rect(this.position.x + (float)this.slider.padding.left, (this.ClampedCurrentValue() + this.size - this.start) * num + this.position.y + (float)this.slider.padding.top, this.position.width - (float)this.slider.padding.horizontal, this.size * -num + this.ThumbSize());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rect HorizontalThumbRect()
|
||||||
|
{
|
||||||
|
float num = this.ValuesPerPixel();
|
||||||
|
Rect result;
|
||||||
|
if (this.start < this.end)
|
||||||
|
{
|
||||||
|
result = new Rect((this.ClampedCurrentValue() - this.start) * num + this.position.x + (float)this.slider.padding.left, this.position.y + (float)this.slider.padding.top, this.size * num + this.ThumbSize(), this.position.height - (float)this.slider.padding.vertical);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = new Rect((this.ClampedCurrentValue() + this.size - this.start) * num + this.position.x + (float)this.slider.padding.left, this.position.y, this.size * -num + this.ThumbSize(), this.position.height);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float ClampedCurrentValue()
|
||||||
|
{
|
||||||
|
return this.Clamp(this.currentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float MousePosition()
|
||||||
|
{
|
||||||
|
float result;
|
||||||
|
if (this.horiz)
|
||||||
|
{
|
||||||
|
result = this.CurrentEvent().mousePosition.x - this.position.x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = this.CurrentEvent().mousePosition.y - this.position.y;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float ValuesPerPixel()
|
||||||
|
{
|
||||||
|
float result;
|
||||||
|
if (this.horiz)
|
||||||
|
{
|
||||||
|
result = (this.position.width - (float)this.slider.padding.horizontal - this.ThumbSize()) / (this.end - this.start);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = (this.position.height - (float)this.slider.padding.vertical - this.ThumbSize()) / (this.end - this.start);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float ThumbSize()
|
||||||
|
{
|
||||||
|
float result;
|
||||||
|
if (this.horiz)
|
||||||
|
{
|
||||||
|
result = ((this.thumb.fixedWidth == 0f) ? ((float)this.thumb.padding.horizontal) : this.thumb.fixedWidth);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = ((this.thumb.fixedHeight == 0f) ? ((float)this.thumb.padding.vertical) : this.thumb.fixedHeight);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float MaxValue()
|
||||||
|
{
|
||||||
|
return Mathf.Max(this.start, this.end) - this.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float MinValue()
|
||||||
|
{
|
||||||
|
return Mathf.Min(this.start, this.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,15 +21,25 @@ namespace Explorer
|
|||||||
private string m_name;
|
private string m_name;
|
||||||
private string m_scene;
|
private string m_scene;
|
||||||
|
|
||||||
private Vector2 m_transformScroll = Vector2.zero;
|
|
||||||
private Transform[] m_children;
|
private Transform[] m_children;
|
||||||
|
private Vector2 m_transformScroll = Vector2.zero;
|
||||||
|
private PageHelper ChildPages = new PageHelper();
|
||||||
|
|
||||||
private Component[] m_components;
|
private Component[] m_components;
|
||||||
|
|
||||||
private Vector2 m_compScroll = Vector2.zero;
|
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_translateAmount = 0.3f;
|
||||||
private float m_rotateAmount = 50f;
|
private float m_rotateAmount = 50f;
|
||||||
private float m_scaleAmount = 0.1f;
|
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 readonly List<Component> m_cachedDestroyList = new List<Component>();
|
||||||
//private string m_addComponentInput = "";
|
//private string m_addComponentInput = "";
|
||||||
@ -71,15 +81,27 @@ namespace Explorer
|
|||||||
|
|
||||||
m_name = m_object.name;
|
m_name = m_object.name;
|
||||||
m_scene = string.IsNullOrEmpty(m_object.scene.name)
|
m_scene = string.IsNullOrEmpty(m_object.scene.name)
|
||||||
? "None"
|
? "None (Asset/Resource)"
|
||||||
: m_object.scene.name;
|
: m_object.scene.name;
|
||||||
|
|
||||||
var list = new List<Transform>();
|
CacheTransformValues();
|
||||||
for (int i = 0; i < m_object.transform.childCount; i++)
|
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheTransformValues()
|
||||||
|
{
|
||||||
|
if (m_localContext)
|
||||||
{
|
{
|
||||||
list.Add(m_object.transform.GetChild(i));
|
m_cachedInput[0] = m_object.transform.localPosition;
|
||||||
|
m_cachedInput[1] = m_object.transform.localEulerAngles;
|
||||||
}
|
}
|
||||||
m_children = list.ToArray();
|
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()
|
public override void Update()
|
||||||
@ -91,12 +113,39 @@ namespace Explorer
|
|||||||
throw new Exception("Object is null!");
|
throw new Exception("Object is null!");
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<Component>();
|
if (m_freeze)
|
||||||
foreach (var comp in m_object.GetComponents(ReflectionHelpers.ComponentType))
|
|
||||||
{
|
{
|
||||||
list.Add(comp);
|
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;
|
||||||
}
|
}
|
||||||
m_components = list.ToArray();
|
|
||||||
|
// update child objects
|
||||||
|
var childList = new List<Transform>();
|
||||||
|
for (int i = 0; i < m_object.transform.childCount; i++)
|
||||||
|
{
|
||||||
|
childList.Add(m_object.transform.GetChild(i));
|
||||||
|
}
|
||||||
|
childList.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||||
|
m_children = childList.ToArray();
|
||||||
|
|
||||||
|
ChildPages.ItemCount = m_children.Length;
|
||||||
|
|
||||||
|
// update components
|
||||||
|
var compList = new Il2CppSystem.Collections.Generic.List<Component>();
|
||||||
|
m_object.GetComponentsInternal(ReflectionHelpers.ComponentType, true, false, true, false, compList);
|
||||||
|
|
||||||
|
m_components = compList.ToArray();
|
||||||
|
|
||||||
|
CompPages.ItemCount = m_components.Length;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -106,7 +155,7 @@ namespace Explorer
|
|||||||
|
|
||||||
private void DestroyOnException(Exception e)
|
private void DestroyOnException(Exception e)
|
||||||
{
|
{
|
||||||
MelonLogger.Log($"{e.GetType()}, {e.Message}");
|
MelonLogger.Log($"Exception drawing GameObject Window: {e.GetType()}, {e.Message}");
|
||||||
DestroyWindow();
|
DestroyWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,18 +203,22 @@ namespace Explorer
|
|||||||
GUILayout.BeginArea(new Rect(5, 25, rect.width - 10, rect.height - 35), GUI.skin.box);
|
GUILayout.BeginArea(new Rect(5, 25, rect.width - 10, rect.height - 35), GUI.skin.box);
|
||||||
}
|
}
|
||||||
|
|
||||||
scroll = GUILayout.BeginScrollView(scroll, GUI.skin.scrollView);
|
scroll = GUIUnstrip.BeginScrollView(scroll);
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Label("Scene: <color=cyan>" + (m_scene == "" ? "n/a" : m_scene) + "</color>", null);
|
GUILayout.Label("Scene: <color=cyan>" + (m_scene == "" ? "n/a" : m_scene) + "</color>", null);
|
||||||
if (m_scene == UnityHelpers.ActiveSceneName)
|
if (m_scene == UnityHelpers.ActiveSceneName)
|
||||||
{
|
{
|
||||||
if (GUILayout.Button("<color=#00FF00>< View in Scene Explorer</color>", new GUILayoutOption[] { GUILayout.Width(230) }))
|
if (GUILayout.Button("<color=#00FF00>Send to Scene View</color>", new GUILayoutOption[] { GUILayout.Width(150) }))
|
||||||
{
|
{
|
||||||
ScenePage.Instance.SetTransformTarget(m_object.transform);
|
ScenePage.Instance.SetTransformTarget(m_object.transform);
|
||||||
MainMenu.SetCurrentPage(0);
|
MainMenu.SetCurrentPage(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (GUILayout.Button("Reflection Inspect", new GUILayoutOption[] { GUILayout.Width(150) }))
|
||||||
|
{
|
||||||
|
WindowManager.InspectObject(Target, out _, true);
|
||||||
|
}
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
@ -201,7 +254,7 @@ namespace Explorer
|
|||||||
|
|
||||||
GameObjectControls();
|
GameObjectControls();
|
||||||
|
|
||||||
GUILayout.EndScrollView();
|
GUIUnstrip.EndScrollView();
|
||||||
|
|
||||||
if (!WindowManager.TabView)
|
if (!WindowManager.TabView)
|
||||||
{
|
{
|
||||||
@ -218,29 +271,47 @@ namespace Explorer
|
|||||||
|
|
||||||
private void TransformList(Rect m_rect)
|
private void TransformList(Rect m_rect)
|
||||||
{
|
{
|
||||||
GUILayout.BeginVertical(GUI.skin.box, null); // new GUILayoutOption[] { GUILayout.Height(250) });
|
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||||
m_transformScroll = GUILayout.BeginScrollView(m_transformScroll, GUI.skin.scrollView);
|
m_transformScroll = GUIUnstrip.BeginScrollView(m_transformScroll);
|
||||||
|
|
||||||
|
GUILayout.Label("<b><size=15>Children</size></b>", null);
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
ChildPages.DrawLimitInputArea();
|
||||||
|
|
||||||
|
if (ChildPages.ItemCount > ChildPages.ItemsPerPage)
|
||||||
|
{
|
||||||
|
ChildPages.CurrentPageLabel();
|
||||||
|
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
|
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
|
{
|
||||||
|
ChildPages.TurnPage(Turn.Left, ref this.m_transformScroll);
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
|
{
|
||||||
|
ChildPages.TurnPage(Turn.Right, ref this.m_transformScroll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
GUILayout.Label("<b>Children:</b>", null);
|
|
||||||
if (m_children != null && m_children.Length > 0)
|
if (m_children != null && m_children.Length > 0)
|
||||||
{
|
{
|
||||||
foreach (var obj in m_children.Where(x => x.childCount > 0))
|
int start = ChildPages.CalculateOffsetIndex();
|
||||||
|
|
||||||
|
for (int j = start; (j < start + ChildPages.ItemsPerPage && j < ChildPages.ItemCount); j++)
|
||||||
{
|
{
|
||||||
|
var obj = m_children[j];
|
||||||
|
|
||||||
if (!obj)
|
if (!obj)
|
||||||
{
|
{
|
||||||
GUILayout.Label("null", null);
|
GUILayout.Label("null", null);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
UIHelpers.GameobjButton(obj.gameObject, InspectGameObject, false, m_rect.width / 2 - 60);
|
|
||||||
}
|
UIHelpers.GOButton(obj.gameObject, InspectGameObject, false, m_rect.width / 2 - 80);
|
||||||
foreach (var obj in m_children.Where(x => x.childCount == 0))
|
|
||||||
{
|
|
||||||
if (!obj)
|
|
||||||
{
|
|
||||||
GUILayout.Label("null", null);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
UIHelpers.GameobjButton(obj.gameObject, InspectGameObject, false, m_rect.width / 2 - 60);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -248,17 +319,37 @@ namespace Explorer
|
|||||||
GUILayout.Label("<i>None</i>", null);
|
GUILayout.Label("<i>None</i>", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.EndScrollView();
|
GUIUnstrip.EndScrollView();
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ComponentList(Rect m_rect)
|
private void ComponentList(Rect m_rect)
|
||||||
{
|
{
|
||||||
GUILayout.BeginVertical(GUI.skin.box, null); // new GUILayoutOption[] { GUILayout.Height(250) });
|
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||||
m_compScroll = GUILayout.BeginScrollView(m_compScroll, GUI.skin.scrollView);
|
m_compScroll = GUIUnstrip.BeginScrollView(m_compScroll);
|
||||||
GUILayout.Label("<b><size=15>Components</size></b>", null);
|
GUILayout.Label("<b><size=15>Components</size></b>", null);
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
CompPages.DrawLimitInputArea();
|
||||||
|
|
||||||
|
if (CompPages.ItemCount > CompPages.ItemsPerPage)
|
||||||
|
{
|
||||||
|
CompPages.CurrentPageLabel();
|
||||||
|
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
|
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
|
{
|
||||||
|
CompPages.TurnPage(Turn.Left, ref this.m_compScroll);
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
|
{
|
||||||
|
CompPages.TurnPage(Turn.Right, ref this.m_compScroll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||||
if (m_cachedDestroyList.Count > 0)
|
if (m_cachedDestroyList.Count > 0)
|
||||||
{
|
{
|
||||||
@ -267,15 +358,15 @@ namespace Explorer
|
|||||||
|
|
||||||
if (m_components != null)
|
if (m_components != null)
|
||||||
{
|
{
|
||||||
foreach (var component in m_components)
|
int start = CompPages.CalculateOffsetIndex();
|
||||||
|
|
||||||
|
for (int j = start; (j < start + CompPages.ItemsPerPage && j < CompPages.ItemCount); j++)
|
||||||
{
|
{
|
||||||
|
var component = m_components[j];
|
||||||
|
|
||||||
if (!component) continue;
|
if (!component) continue;
|
||||||
|
|
||||||
var ilType = component.GetIl2CppType();
|
var ilType = component.GetIl2CppType();
|
||||||
if (ilType == ReflectionHelpers.TransformType)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
if (ReflectionHelpers.BehaviourType.IsAssignableFrom(ilType))
|
if (ReflectionHelpers.BehaviourType.IsAssignableFrom(ilType))
|
||||||
@ -286,7 +377,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
GUILayout.Space(26);
|
GUILayout.Space(26);
|
||||||
}
|
}
|
||||||
if (GUILayout.Button("<color=cyan>" + ilType.Name + "</color>", new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 90) }))
|
if (GUILayout.Button("<color=cyan>" + ilType.Name + "</color>", new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 100) }))
|
||||||
{
|
{
|
||||||
ReflectObject(component);
|
ReflectObject(component);
|
||||||
}
|
}
|
||||||
@ -308,7 +399,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.EndScrollView();
|
GUIUnstrip.EndScrollView();
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
@ -355,6 +446,16 @@ namespace Explorer
|
|||||||
m_object.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
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.EndHorizontal();
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
@ -379,10 +480,52 @@ namespace Explorer
|
|||||||
|
|
||||||
GUILayout.BeginVertical(GUI.skin.box, null);
|
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||||
|
|
||||||
var t = m_object.transform;
|
m_cachedInput[0] = TranslateControl(TranslateType.Position, ref m_translateAmount, false);
|
||||||
TranslateControl(t, TranslateType.Position, ref m_translateAmount, false);
|
m_cachedInput[1] = TranslateControl(TranslateType.Rotation, ref m_rotateAmount, true);
|
||||||
TranslateControl(t, TranslateType.Rotation, ref m_rotateAmount, true);
|
m_cachedInput[2] = TranslateControl(TranslateType.Scale, ref m_scaleAmount, false);
|
||||||
TranslateControl(t, 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();
|
GUILayout.EndVertical();
|
||||||
|
|
||||||
@ -396,6 +539,30 @@ namespace Explorer
|
|||||||
GUILayout.EndVertical();
|
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
|
public enum TranslateType
|
||||||
{
|
{
|
||||||
Position,
|
Position,
|
||||||
@ -403,50 +570,55 @@ namespace Explorer
|
|||||||
Scale
|
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.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)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case TranslateType.Position: vector = transform.localPosition; break;
|
case TranslateType.Position:
|
||||||
case TranslateType.Rotation: vector = transform.localRotation.eulerAngles; break;
|
var pos = m_localContext ? transform.localPosition : transform.position;
|
||||||
case TranslateType.Scale: vector = transform.localScale; break;
|
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();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
Vector3 input = m_cachedInput[(int)mode];
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||||
|
|
||||||
GUILayout.Label("<color=cyan>X:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
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) });
|
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) });
|
GUILayout.Label("<color=cyan>Z:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||||
PlusMinusFloat(ref vector.z, amount, multByTime);
|
PlusMinusFloat(ref input.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.Label("+/-:", new GUILayoutOption[] { GUILayout.Width(30) });
|
GUILayout.Label("+/-:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
var input = amount.ToString("F3");
|
var amountInput = amount.ToString("F3");
|
||||||
input = GUILayout.TextField(input, new GUILayoutOption[] { GUILayout.Width(40) });
|
amountInput = GUILayout.TextField(amountInput, new GUILayoutOption[] { GUILayout.Width(60) });
|
||||||
if (float.TryParse(input, out float f))
|
if (float.TryParse(amountInput, out float f))
|
||||||
{
|
{
|
||||||
amount = f;
|
amount = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PlusMinusFloat(ref float f, float amount, bool multByTime)
|
private void PlusMinusFloat(ref float f, float amount, bool multByTime)
|
||||||
@ -466,7 +638,5 @@ namespace Explorer
|
|||||||
f += multByTime ? amount * Time.deltaTime : amount;
|
f += multByTime ? amount * Time.deltaTime : amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,10 @@ namespace Explorer
|
|||||||
|
|
||||||
private CacheObjectBase[] m_allCachedMembers;
|
private CacheObjectBase[] m_allCachedMembers;
|
||||||
private CacheObjectBase[] m_cachedMembersFiltered;
|
private CacheObjectBase[] m_cachedMembersFiltered;
|
||||||
private int m_pageOffset;
|
|
||||||
private int m_limitPerPage = 20;
|
public PageHelper Pages = new PageHelper();
|
||||||
|
//private int m_pageOffset;
|
||||||
|
//private int m_limitPerPage = 20;
|
||||||
|
|
||||||
private bool m_autoUpdate = false;
|
private bool m_autoUpdate = false;
|
||||||
private string m_search = "";
|
private string m_search = "";
|
||||||
@ -138,7 +140,7 @@ namespace Explorer
|
|||||||
var name = $"{member.DeclaringType.Name}.{member.Name}";
|
var name = $"{member.DeclaringType.Name}.{member.Name}";
|
||||||
|
|
||||||
// blacklist (should probably make a proper implementation)
|
// blacklist (should probably make a proper implementation)
|
||||||
if (name == "Type.DeclaringMethod" || member.Name.Contains("Il2CppType") || member.Name.StartsWith("get_") || member.Name.StartsWith("set_"))
|
if (name == "Type.DeclaringMethod" || member.Name.StartsWith("get_") || member.Name.StartsWith("set_")) //|| member.Name.Contains("Il2CppType")
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -254,41 +256,32 @@ namespace Explorer
|
|||||||
|
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(10);
|
||||||
|
|
||||||
|
Pages.ItemCount = m_cachedMembersFiltered.Length;
|
||||||
|
|
||||||
// prev/next page buttons
|
// prev/next page buttons
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Label("<b>Limit per page:</b>", new GUILayoutOption[] { GUILayout.Width(125) });
|
|
||||||
var limitString = m_limitPerPage.ToString();
|
|
||||||
limitString = GUILayout.TextField(limitString, new GUILayoutOption[] { GUILayout.Width(60) });
|
|
||||||
if (int.TryParse(limitString, out int lim))
|
|
||||||
{
|
|
||||||
m_limitPerPage = lim;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = m_cachedMembersFiltered.Length;
|
Pages.DrawLimitInputArea();
|
||||||
if (count > m_limitPerPage)
|
|
||||||
|
if (Pages.ItemCount > Pages.ItemsPerPage)
|
||||||
{
|
{
|
||||||
int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)m_limitPerPage)) - 1;
|
|
||||||
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
{
|
{
|
||||||
if (m_pageOffset > 0) m_pageOffset--;
|
Pages.TurnPage(Turn.Left, ref this.scroll);
|
||||||
scroll = Vector2.zero;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
Pages.CurrentPageLabel();
|
||||||
GUILayout.Label($"Page {m_pageOffset + 1}/{maxOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
|
||||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
|
||||||
|
|
||||||
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||||
{
|
{
|
||||||
if (m_pageOffset < maxOffset) m_pageOffset++;
|
Pages.TurnPage(Turn.Right, ref this.scroll);
|
||||||
scroll = Vector2.zero;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
// ====== BODY ======
|
// ====== BODY ======
|
||||||
|
|
||||||
scroll = GUILayout.BeginScrollView(scroll, GUI.skin.scrollView);
|
scroll = GUIUnstrip.BeginScrollView(scroll);
|
||||||
|
|
||||||
GUILayout.Space(10);
|
GUILayout.Space(10);
|
||||||
|
|
||||||
@ -297,18 +290,9 @@ namespace Explorer
|
|||||||
GUILayout.BeginVertical(GUI.skin.box, null);
|
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||||
|
|
||||||
var members = this.m_cachedMembersFiltered;
|
var members = this.m_cachedMembersFiltered;
|
||||||
int start = m_pageOffset * m_limitPerPage;
|
int start = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
if (start >= count)
|
for (int j = start; (j < start + Pages.ItemsPerPage && j < members.Length); j++)
|
||||||
{
|
|
||||||
int maxOffset = (int)Mathf.Ceil((float)(m_cachedMembersFiltered.Length / (decimal)m_limitPerPage)) - 1;
|
|
||||||
if (m_pageOffset > maxOffset)
|
|
||||||
{
|
|
||||||
m_pageOffset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int j = start; (j < start + m_limitPerPage && j < members.Length); j++)
|
|
||||||
{
|
{
|
||||||
var holder = members[j];
|
var holder = members[j];
|
||||||
|
|
||||||
@ -325,12 +309,12 @@ namespace Explorer
|
|||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
// if not last element
|
// if not last element
|
||||||
if (!(j == (start + m_limitPerPage - 1) || j == (members.Length - 1)))
|
if (!(j == (start + Pages.ItemsPerPage - 1) || j == (members.Length - 1)))
|
||||||
UIStyles.HorizontalLine(new Color(0.07f, 0.07f, 0.07f), true);
|
UIStyles.HorizontalLine(new Color(0.07f, 0.07f, 0.07f), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
GUILayout.EndScrollView();
|
GUIUnstrip.EndScrollView();
|
||||||
|
|
||||||
if (!WindowManager.TabView)
|
if (!WindowManager.TabView)
|
||||||
{
|
{
|
||||||
@ -367,7 +351,8 @@ namespace Explorer
|
|||||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
|
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
|
||||||
{
|
{
|
||||||
m_filter = mode;
|
m_filter = mode;
|
||||||
m_pageOffset = 0;
|
Pages.PageOffset = 0;
|
||||||
|
scroll = Vector2.zero;
|
||||||
}
|
}
|
||||||
GUI.color = Color.white;
|
GUI.color = Color.white;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,8 @@ namespace Explorer
|
|||||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||||
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
|
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
|
||||||
|
|
||||||
var r = GUILayoutUtility.GetLastRect();
|
//var r = GUILayoutUtility.GetLastRect();
|
||||||
|
var r = GUIUnstrip.GetLastRect();
|
||||||
|
|
||||||
Vector2 mouse = GUIUtility.ScreenToGUIPoint(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y));
|
Vector2 mouse = GUIUtility.ScreenToGUIPoint(new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y));
|
||||||
|
|
||||||
@ -65,6 +66,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
RESIZE_FAILED = true;
|
RESIZE_FAILED = true;
|
||||||
MelonLogger.Log("Exception on GuiResize: " + e.GetType() + ", " + e.Message);
|
MelonLogger.Log("Exception on GuiResize: " + e.GetType() + ", " + e.Message);
|
||||||
|
MelonLogger.Log(e.StackTrace);
|
||||||
return origRect;
|
return origRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void Init() { }
|
public override void Init() { }
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
while (TargetTabID >= WindowManager.Windows.Count)
|
while (TargetTabID >= WindowManager.Windows.Count)
|
||||||
|
@ -86,34 +86,50 @@ namespace Explorer
|
|||||||
|
|
||||||
// ========= Public Helpers =========
|
// ========= Public Helpers =========
|
||||||
|
|
||||||
public static UIWindow InspectObject(object obj, out bool createdNew)
|
public static UIWindow InspectObject(object obj, out bool createdNew, bool forceReflection = false)
|
||||||
{
|
{
|
||||||
createdNew = false;
|
createdNew = false;
|
||||||
|
|
||||||
UnityEngine.Object uObj = null;
|
if (Input.GetKey(KeyCode.LeftShift))
|
||||||
if (obj is UnityEngine.Object)
|
|
||||||
{
|
{
|
||||||
uObj = obj as UnityEngine.Object;
|
forceReflection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Il2CppSystem.Object iObj = null;
|
||||||
|
if (obj is Il2CppSystem.Object isObj)
|
||||||
|
{
|
||||||
|
iObj = isObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var window in Windows)
|
if (!forceReflection)
|
||||||
{
|
{
|
||||||
bool equals = ReferenceEquals(obj, window.Target);
|
foreach (var window in Windows)
|
||||||
|
|
||||||
if (!equals && uObj != null && window.Target is UnityEngine.Object uTarget)
|
|
||||||
{
|
{
|
||||||
equals = uObj.m_CachedPtr == uTarget.m_CachedPtr;
|
bool equals = ReferenceEquals(obj, window.Target);
|
||||||
}
|
|
||||||
|
|
||||||
if (equals)
|
if (!equals && iObj is Il2CppSystem.Object iCurrent && window.Target is Il2CppSystem.Object iTarget)
|
||||||
{
|
{
|
||||||
FocusWindow(window);
|
if (iCurrent.GetIl2CppType().FullName != iTarget.GetIl2CppType().FullName)
|
||||||
return window;
|
{
|
||||||
|
if (iCurrent is Transform transform)
|
||||||
|
{
|
||||||
|
iCurrent = transform.gameObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
equals = iCurrent.Pointer == iTarget.Pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (equals)
|
||||||
|
{
|
||||||
|
FocusWindow(window);
|
||||||
|
return window;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createdNew = true;
|
createdNew = true;
|
||||||
if (obj is GameObject || obj is Transform)
|
if (!forceReflection && (obj is GameObject || obj is Transform))
|
||||||
{
|
{
|
||||||
return InspectGameObject(obj as GameObject ?? (obj as Transform).gameObject);
|
return InspectGameObject(obj as GameObject ?? (obj as Transform).gameObject);
|
||||||
}
|
}
|
||||||
@ -144,7 +160,7 @@ namespace Explorer
|
|||||||
return new_window;
|
return new_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UIWindow InspectReflection(object obj)
|
private static UIWindow InspectReflection(object obj)
|
||||||
{
|
{
|
||||||
var new_window = UIWindow.CreateWindow<ReflectionWindow>(obj);
|
var new_window = UIWindow.CreateWindow<ReflectionWindow>(obj);
|
||||||
FocusWindow(new_window);
|
FocusWindow(new_window);
|
||||||
|
Reference in New Issue
Block a user