mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-15 15:57:52 +08:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
6adaaf5500 | |||
5de771389e | |||
51cfbe524e | |||
217b93ef4f | |||
42156e1160 | |||
e7208d0c9d | |||
2f3b779199 |
@ -51,7 +51,9 @@ Requires [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) to be ins
|
|||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
@ -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 System.Reflection;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -15,8 +16,23 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
EnumType = Value.GetType();
|
try
|
||||||
EnumNames = Enum.GetNames(EnumType);
|
{
|
||||||
|
EnumType = Value.GetType();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
EnumType = (MemInfo as FieldInfo)?.FieldType ?? (MemInfo as PropertyInfo).PropertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EnumType != null)
|
||||||
|
{
|
||||||
|
EnumNames = Enum.GetNames(EnumType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReflectionException = "Unknown, could not get Enum names.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
|
@ -10,32 +10,9 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public class CacheGameObject : CacheObjectBase
|
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)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
UIHelpers.GameobjButton(GameObj, null, false, width);
|
UIHelpers.GOButton(Value, null, false, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateValue()
|
public override void 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;
|
||||||
@ -145,16 +144,16 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
if (m_entryType == null)
|
if (m_entryType == null)
|
||||||
{
|
{
|
||||||
if (this.MemberInfo != null)
|
if (this.MemInfo != null)
|
||||||
{
|
{
|
||||||
Type memberType = null;
|
Type memberType = null;
|
||||||
switch (this.MemberInfo.MemberType)
|
switch (this.MemInfo.MemberType)
|
||||||
{
|
{
|
||||||
case MemberTypes.Field:
|
case MemberTypes.Field:
|
||||||
memberType = (MemberInfo as FieldInfo).FieldType;
|
memberType = (MemInfo as FieldInfo).FieldType;
|
||||||
break;
|
break;
|
||||||
case MemberTypes.Property:
|
case MemberTypes.Property:
|
||||||
memberType = (MemberInfo as PropertyInfo).PropertyType;
|
memberType = (MemInfo as PropertyInfo).PropertyType;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,17 +200,35 @@ namespace Explorer
|
|||||||
while (enumerator.MoveNext())
|
while (enumerator.MoveNext())
|
||||||
{
|
{
|
||||||
var obj = enumerator.Current;
|
var obj = enumerator.Current;
|
||||||
var type = ReflectionHelpers.GetActualType(obj);
|
|
||||||
|
|
||||||
if (obj is Il2CppSystem.Object iObj)
|
if (obj != null && ReflectionHelpers.GetActualType(obj) is Type t)
|
||||||
{
|
{
|
||||||
obj = iObj.Il2CppCast(type);
|
if (obj is Il2CppSystem.Object iObj)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cast = iObj.Il2CppCast(t);
|
||||||
|
if (cast != null)
|
||||||
|
{
|
||||||
|
obj = cast;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetCacheObject(obj, t) is CacheObjectBase cached)
|
||||||
|
{
|
||||||
|
list.Add(cached);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list.Add(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list.Add(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var cached = GetCacheObject(obj, null, null, type);
|
|
||||||
cached.UpdateValue();
|
|
||||||
|
|
||||||
list.Add(cached);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cachedEntries = list.ToArray();
|
m_cachedEntries = list.ToArray();
|
||||||
@ -257,50 +274,46 @@ 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);
|
||||||
|
|
||||||
int maxOffset = (int)Mathf.Ceil((float)(count / (decimal)ArrayLimit)) - 1;
|
Pages.CurrentPageLabel();
|
||||||
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];
|
||||||
|
|
||||||
@ -310,16 +323,18 @@ namespace Explorer
|
|||||||
|
|
||||||
GUILayout.Space(whitespace);
|
GUILayout.Space(whitespace);
|
||||||
|
|
||||||
if (entry.Value == null)
|
if (entry == null || entry.Value == null)
|
||||||
{
|
{
|
||||||
GUILayout.Label(i + "<i><color=grey> (null)</color></i>", null);
|
GUILayout.Label($"[{i}] <i><color=grey>(null)</color></i>", null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||||
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(30) });
|
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
|
||||||
entry.DrawValue(window, window.width - (whitespace + 85));
|
entry.DrawValue(window, window.width - (whitespace + 85));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
|
@ -24,7 +24,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
if (m_hasParams == null)
|
if (m_hasParams == null)
|
||||||
{
|
{
|
||||||
m_hasParams = (MemberInfo as MethodInfo).GetParameters().Length > 0;
|
m_hasParams = (MemInfo as MethodInfo).GetParameters().Length > 0;
|
||||||
}
|
}
|
||||||
return (bool)m_hasParams;
|
return (bool)m_hasParams;
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
base.Init();
|
base.Init();
|
||||||
|
|
||||||
var mi = MemberInfo as MethodInfo;
|
var mi = MemInfo as MethodInfo;
|
||||||
|
|
||||||
m_arguments = mi.GetParameters();
|
m_arguments = mi.GetParameters();
|
||||||
m_argumentInput = new string[m_arguments.Length];
|
m_argumentInput = new string[m_arguments.Length];
|
||||||
@ -136,12 +136,12 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Label($"null (<color=yellow>{ValueType}</color>)", null);
|
GUILayout.Label($"null (<color=yellow>{ValueTypeName}</color>)", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Label($"<color=grey><i>Not yet evaluated</i></color> (<color=yellow>{ValueType}</color>)", null);
|
GUILayout.Label($"<color=grey><i>Not yet evaluated</i></color> (<color=yellow>{ValueTypeName}</color>)", null);
|
||||||
}
|
}
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ namespace Explorer
|
|||||||
|
|
||||||
private void Evaluate()
|
private void Evaluate()
|
||||||
{
|
{
|
||||||
var mi = MemberInfo as MethodInfo;
|
var mi = MemInfo as MethodInfo;
|
||||||
|
|
||||||
object ret = null;
|
object ret = null;
|
||||||
|
|
||||||
|
@ -13,67 +13,70 @@ namespace Explorer
|
|||||||
public abstract class CacheObjectBase
|
public abstract class CacheObjectBase
|
||||||
{
|
{
|
||||||
public object Value;
|
public object Value;
|
||||||
public string ValueType;
|
public string ValueTypeName;
|
||||||
|
|
||||||
// Reflection window only
|
// Reflection Inspector only
|
||||||
public MemberInfo MemberInfo { get; set; }
|
public MemberInfo MemInfo { get; set; }
|
||||||
public Type DeclaringType { get; set; }
|
public Type DeclaringType { get; set; }
|
||||||
public object DeclaringInstance { get; set; }
|
public object DeclaringInstance { get; set; }
|
||||||
|
public string ReflectionException { get; set; }
|
||||||
|
|
||||||
public string RichTextName
|
public int PropertyIndex { get; private set; }
|
||||||
{
|
private string m_propertyIndexInput = "0";
|
||||||
get
|
|
||||||
{
|
public string RichTextName => m_richTextName ?? GetRichTextName();
|
||||||
if (m_richTextName == null)
|
|
||||||
{
|
|
||||||
GetRichTextName();
|
|
||||||
}
|
|
||||||
return m_richTextName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private string m_richTextName;
|
private string m_richTextName;
|
||||||
|
|
||||||
public string ReflectionException;
|
|
||||||
|
|
||||||
public bool CanWrite
|
public bool CanWrite
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (MemberInfo is FieldInfo fi)
|
if (MemInfo is FieldInfo fi)
|
||||||
{
|
|
||||||
return !(fi.IsLiteral && !fi.IsInitOnly);
|
return !(fi.IsLiteral && !fi.IsInitOnly);
|
||||||
}
|
else if (MemInfo is PropertyInfo pi)
|
||||||
else if (MemberInfo is PropertyInfo pi)
|
|
||||||
{
|
|
||||||
return pi.CanWrite;
|
return pi.CanWrite;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods
|
// ===== Abstract/Virtual Methods ===== //
|
||||||
|
|
||||||
public virtual void Init() { }
|
public virtual void Init() { }
|
||||||
|
|
||||||
public abstract void DrawValue(Rect window, float width);
|
public abstract void DrawValue(Rect window, float width);
|
||||||
|
|
||||||
|
// ===== Static Methods ===== //
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get CacheObject from only an object instance
|
||||||
|
/// Calls GetCacheObject(obj, memberInfo, declaringInstance) with (obj, null, null)</summary>
|
||||||
public static CacheObjectBase GetCacheObject(object obj)
|
public static CacheObjectBase GetCacheObject(object obj)
|
||||||
{
|
{
|
||||||
return GetCacheObject(obj, null, null);
|
return GetCacheObject(obj, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the CacheObject subclass for an object or MemberInfo
|
/// Get CacheObject from an object instance and provide the value type
|
||||||
/// </summary>
|
/// Calls GetCacheObjectImpl directly</summary>
|
||||||
/// <param name="obj">The current value (can be null if memberInfo is not null)</param>
|
public static CacheObjectBase GetCacheObject(object obj, Type valueType)
|
||||||
/// <param name="memberInfo">The MemberInfo (can be null if obj is not null)</param>
|
{
|
||||||
/// <param name="declaringInstance">If MemberInfo is not null, the declaring class instance. Can be null if static.</param>
|
return GetCacheObjectImpl(obj, null, null, valueType);
|
||||||
/// <returns></returns>
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get CacheObject from only a MemberInfo and declaring instance
|
||||||
|
/// Calls GetCacheObject(obj, memberInfo, declaringInstance) with (null, memberInfo, declaringInstance)</summary>
|
||||||
|
public static CacheObjectBase GetCacheObject(MemberInfo memberInfo, object declaringInstance)
|
||||||
|
{
|
||||||
|
return GetCacheObject(null, memberInfo, declaringInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get CacheObject from either an object or MemberInfo, and don't provide the type.
|
||||||
|
/// This gets the type and then calls GetCacheObjectImpl</summary>
|
||||||
public static CacheObjectBase GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance)
|
public static CacheObjectBase GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance)
|
||||||
{
|
{
|
||||||
//var type = ReflectionHelpers.GetActualType(obj) ?? (memberInfo as FieldInfo)?.FieldType ?? (memberInfo as PropertyInfo)?.PropertyType;
|
|
||||||
|
|
||||||
Type type = null;
|
Type type = null;
|
||||||
|
|
||||||
if (obj != null)
|
if (obj != null)
|
||||||
@ -101,18 +104,13 @@ namespace Explorer
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetCacheObject(obj, memberInfo, declaringInstance, type);
|
return GetCacheObjectImpl(obj, memberInfo, declaringInstance, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the CacheObject subclass for an object or MemberInfo
|
/// Actual GetCacheObject implementation (private)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj">The current value (can be null if memberInfo is not null)</param>
|
private static CacheObjectBase GetCacheObjectImpl(object obj, MemberInfo memberInfo, object declaringInstance, Type valueType)
|
||||||
/// <param name="memberInfo">The MemberInfo (can be null if obj is not null)</param>
|
|
||||||
/// <param name="declaringInstance">If MemberInfo is not null, the declaring class instance. Can be null if static.</param>
|
|
||||||
/// <param name="valueType">The type of the object or MemberInfo value.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static CacheObjectBase GetCacheObject(object obj, MemberInfo memberInfo, object declaringInstance, Type valueType)
|
|
||||||
{
|
{
|
||||||
CacheObjectBase holder;
|
CacheObjectBase holder;
|
||||||
|
|
||||||
@ -153,11 +151,11 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
holder.Value = obj;
|
holder.Value = obj;
|
||||||
holder.ValueType = valueType.FullName;
|
holder.ValueTypeName = valueType.FullName;
|
||||||
|
|
||||||
if (memberInfo != null)
|
if (memberInfo != null)
|
||||||
{
|
{
|
||||||
holder.MemberInfo = memberInfo;
|
holder.MemInfo = memberInfo;
|
||||||
holder.DeclaringType = memberInfo.DeclaringType;
|
holder.DeclaringType = memberInfo.DeclaringType;
|
||||||
holder.DeclaringInstance = declaringInstance;
|
holder.DeclaringInstance = declaringInstance;
|
||||||
|
|
||||||
@ -169,30 +167,40 @@ namespace Explorer
|
|||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======== Updating and Setting Value (memberinfo only) =========
|
// ======== Instance Methods =========
|
||||||
|
|
||||||
public virtual void UpdateValue()
|
public virtual void UpdateValue()
|
||||||
{
|
{
|
||||||
if (MemberInfo == null || !string.IsNullOrEmpty(ReflectionException))
|
if (MemInfo == null || !string.IsNullOrEmpty(ReflectionException))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (MemberInfo.MemberType == MemberTypes.Field)
|
if (MemInfo.MemberType == MemberTypes.Field)
|
||||||
{
|
{
|
||||||
var fi = MemberInfo as FieldInfo;
|
var fi = MemInfo as FieldInfo;
|
||||||
Value = fi.GetValue(fi.IsStatic ? null : DeclaringInstance);
|
Value = fi.GetValue(fi.IsStatic ? null : DeclaringInstance);
|
||||||
}
|
}
|
||||||
else if (MemberInfo.MemberType == MemberTypes.Property)
|
else if (MemInfo.MemberType == MemberTypes.Property)
|
||||||
{
|
{
|
||||||
var pi = MemberInfo as PropertyInfo;
|
var pi = MemInfo as PropertyInfo;
|
||||||
bool isStatic = pi.GetAccessors()[0].IsStatic;
|
bool isStatic = pi.GetAccessors()[0].IsStatic;
|
||||||
var target = isStatic ? null : DeclaringInstance;
|
var target = isStatic ? null : DeclaringInstance;
|
||||||
Value = pi.GetValue(target, null);
|
|
||||||
|
if (pi.GetIndexParameters().Length > 0)
|
||||||
|
{
|
||||||
|
var indexes = new object[] { PropertyIndex };
|
||||||
|
Value = pi.GetValue(target, indexes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Value = pi.GetValue(target, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//ReflectionException = null;
|
|
||||||
|
ReflectionException = null;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -204,15 +212,24 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (MemberInfo.MemberType == MemberTypes.Field)
|
if (MemInfo.MemberType == MemberTypes.Field)
|
||||||
{
|
{
|
||||||
var fi = MemberInfo as FieldInfo;
|
var fi = MemInfo as FieldInfo;
|
||||||
fi.SetValue(fi.IsStatic ? null : DeclaringInstance, Value);
|
fi.SetValue(fi.IsStatic ? null : DeclaringInstance, Value);
|
||||||
}
|
}
|
||||||
else if (MemberInfo.MemberType == MemberTypes.Property)
|
else if (MemInfo.MemberType == MemberTypes.Property)
|
||||||
{
|
{
|
||||||
var pi = MemberInfo as PropertyInfo;
|
var pi = MemInfo as PropertyInfo;
|
||||||
pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value);
|
|
||||||
|
if (pi.GetIndexParameters().Length > 0)
|
||||||
|
{
|
||||||
|
var indexes = new object[] { PropertyIndex };
|
||||||
|
pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value, indexes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -221,7 +238,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========= Gui Draw ==========
|
// ========= Instance Gui Draw ==========
|
||||||
|
|
||||||
public const float MAX_LABEL_WIDTH = 400f;
|
public const float MAX_LABEL_WIDTH = 400f;
|
||||||
|
|
||||||
@ -240,11 +257,15 @@ namespace Explorer
|
|||||||
ClampLabelWidth(window, ref labelWidth);
|
ClampLabelWidth(window, ref labelWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MemberInfo != null)
|
if (MemInfo != null)
|
||||||
{
|
{
|
||||||
|
var name = RichTextName;
|
||||||
|
if (MemInfo is PropertyInfo pi && pi.GetIndexParameters().Length > 0)
|
||||||
|
{
|
||||||
|
name += $"[{PropertyIndex}]";
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.Label(name, new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||||
GUILayout.Label(RichTextName, new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -255,20 +276,44 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
GUILayout.Label("<color=red>Reflection failed!</color> (" + ReflectionException + ")", null);
|
GUILayout.Label("<color=red>Reflection failed!</color> (" + ReflectionException + ")", null);
|
||||||
}
|
}
|
||||||
else if (Value == null && MemberInfo?.MemberType != MemberTypes.Method)
|
else if (Value == null && MemInfo?.MemberType != MemberTypes.Method)
|
||||||
{
|
{
|
||||||
GUILayout.Label("<i>null (" + ValueType + ")</i>", null);
|
GUILayout.Label("<i>null (" + ValueTypeName + ")</i>", null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (MemInfo is PropertyInfo pi && pi.GetIndexParameters().Length > 0)
|
||||||
|
{
|
||||||
|
GUILayout.Label("index:", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||||
|
|
||||||
|
m_propertyIndexInput = GUILayout.TextField(m_propertyIndexInput, new GUILayoutOption[] { GUILayout.Width(100) });
|
||||||
|
if (GUILayout.Button("Set", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||||
|
{
|
||||||
|
if (int.TryParse(m_propertyIndexInput, out int i))
|
||||||
|
{
|
||||||
|
PropertyIndex = i;
|
||||||
|
UpdateValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MelonLogger.Log($"Could not parse '{m_propertyIndexInput}' to an int!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new line and space
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(labelWidth);
|
||||||
|
}
|
||||||
|
|
||||||
DrawValue(window, window.width - labelWidth - 90);
|
DrawValue(window, window.width - labelWidth - 90);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetRichTextName()
|
private string GetRichTextName()
|
||||||
{
|
{
|
||||||
string memberColor = "";
|
string memberColor = "";
|
||||||
switch (MemberInfo.MemberType)
|
switch (MemInfo.MemberType)
|
||||||
{
|
{
|
||||||
case MemberTypes.Field:
|
case MemberTypes.Field:
|
||||||
memberColor = "#c266ff"; break;
|
memberColor = "#c266ff"; break;
|
||||||
@ -278,9 +323,9 @@ namespace Explorer
|
|||||||
memberColor = "#ff8000"; break;
|
memberColor = "#ff8000"; break;
|
||||||
};
|
};
|
||||||
|
|
||||||
m_richTextName = $"<color=#2df7b2>{MemberInfo.DeclaringType.Name}</color>.<color={memberColor}>{MemberInfo.Name}</color>";
|
m_richTextName = $"<color=#2df7b2>{MemInfo.DeclaringType.Name}</color>.<color={memberColor}>{MemInfo.Name}</color>";
|
||||||
|
|
||||||
if (MemberInfo is MethodInfo mi)
|
if (MemInfo is MethodInfo mi)
|
||||||
{
|
{
|
||||||
m_richTextName += "(";
|
m_richTextName += "(";
|
||||||
var _params = "";
|
var _params = "";
|
||||||
@ -293,6 +338,8 @@ namespace Explorer
|
|||||||
m_richTextName += _params;
|
m_richTextName += _params;
|
||||||
m_richTextName += ")";
|
m_richTextName += ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return m_richTextName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,33 +12,25 @@ namespace Explorer
|
|||||||
public class CacheOther : CacheObjectBase
|
public class CacheOther : CacheObjectBase
|
||||||
{
|
{
|
||||||
private MethodInfo m_toStringMethod;
|
private MethodInfo m_toStringMethod;
|
||||||
private bool m_triedToGetMethod;
|
|
||||||
|
|
||||||
public MethodInfo ToStringMethod
|
public MethodInfo ToStringMethod
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_toStringMethod == null && !m_triedToGetMethod)
|
if (m_toStringMethod == null)
|
||||||
{
|
{
|
||||||
if (Value == null) return null;
|
|
||||||
|
|
||||||
m_triedToGetMethod = true;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var methods = ReflectionHelpers.GetActualType(Value)
|
m_toStringMethod = ReflectionHelpers.GetActualType(Value).GetMethod("ToString", new Type[0])
|
||||||
.GetMethods(ReflectionHelpers.CommonFlags)
|
?? typeof(object).GetMethod("ToString", new Type[0]);
|
||||||
.Where(x => x.Name == "ToString")
|
|
||||||
.GetEnumerator();
|
|
||||||
|
|
||||||
while (methods.MoveNext())
|
// test invoke
|
||||||
{
|
m_toStringMethod.Invoke(Value, null);
|
||||||
// just get the first (top-most level) method, then break.
|
}
|
||||||
m_toStringMethod = methods.Current;
|
catch
|
||||||
break;
|
{
|
||||||
}
|
m_toStringMethod = typeof(object).GetMethod("ToString", new Type[0]);
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
}
|
}
|
||||||
return m_toStringMethod;
|
return m_toStringMethod;
|
||||||
}
|
}
|
||||||
@ -48,9 +40,9 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
|
string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
|
||||||
|
|
||||||
if (!label.Contains(ValueType))
|
if (!label.Contains(ValueTypeName))
|
||||||
{
|
{
|
||||||
label += $" ({ValueType})";
|
label += $" ({ValueTypeName})";
|
||||||
}
|
}
|
||||||
if (Value is UnityEngine.Object unityObj && !label.Contains(unityObj.name))
|
if (Value is UnityEngine.Object unityObj && !label.Contains(unityObj.name))
|
||||||
{
|
{
|
||||||
@ -58,7 +50,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||||
if (GUILayout.Button("<color=yellow>" + label + "</color>", new GUILayoutOption[] { GUILayout.MaxWidth(width + 40) }))
|
if (GUILayout.Button("<color=yellow>" + label + "</color>", new GUILayoutOption[] { GUILayout.Width(width) }))
|
||||||
{
|
{
|
||||||
WindowManager.InspectObject(Value, out bool _);
|
WindowManager.InspectObject(Value, out bool _);
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ namespace Explorer
|
|||||||
|
|
||||||
public void SetValueFromInput(string value)
|
public void SetValueFromInput(string value)
|
||||||
{
|
{
|
||||||
if (MemberInfo == null)
|
if (MemInfo == null)
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Trying to SetValue but the MemberInfo is null!");
|
MelonLogger.Log("Trying to SetValue but the MemberInfo is null!");
|
||||||
return;
|
return;
|
||||||
|
@ -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.0";
|
public const string VERSION = "1.5.4";
|
||||||
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();
|
||||||
@ -133,7 +135,7 @@ namespace Explorer
|
|||||||
// value that we set back to when we close the menu or disable force-unlock.
|
// value that we set back to when we close the menu or disable force-unlock.
|
||||||
|
|
||||||
[HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Setter)]
|
[HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Setter)]
|
||||||
public class Cursor_lockState
|
public class Cursor_set_lockState
|
||||||
{
|
{
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
public static void Prefix(ref CursorLockMode value)
|
public static void Prefix(ref CursorLockMode value)
|
||||||
@ -170,19 +172,6 @@ namespace Explorer
|
|||||||
|
|
||||||
// Make it appear as though UnlockMouse is disabled to the rest of the application.
|
// Make it appear as though UnlockMouse is disabled to the rest of the application.
|
||||||
|
|
||||||
[HarmonyPatch(typeof(Cursor), nameof(Cursor.visible), MethodType.Getter)]
|
|
||||||
public class Cursor_get_visible
|
|
||||||
{
|
|
||||||
[HarmonyPostfix]
|
|
||||||
public static void Postfix(ref bool __result)
|
|
||||||
{
|
|
||||||
if (ShouldForceMouse)
|
|
||||||
{
|
|
||||||
__result = m_lastVisibleState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Getter)]
|
[HarmonyPatch(typeof(Cursor), nameof(Cursor.lockState), MethodType.Getter)]
|
||||||
public class Cursor_get_lockState
|
public class Cursor_get_lockState
|
||||||
{
|
{
|
||||||
@ -195,5 +184,18 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Cursor), nameof(Cursor.visible), MethodType.Getter)]
|
||||||
|
public class Cursor_get_visible
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void Postfix(ref bool __result)
|
||||||
|
{
|
||||||
|
if (ShouldForceMouse)
|
||||||
|
{
|
||||||
|
__result = m_lastVisibleState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
@ -129,12 +129,17 @@
|
|||||||
<Compile Include="CachedObjects\CacheMethod.cs" />
|
<Compile Include="CachedObjects\CacheMethod.cs" />
|
||||||
<Compile Include="CppExplorer.cs" />
|
<Compile Include="CppExplorer.cs" />
|
||||||
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
||||||
|
<Compile Include="Unstripping\GUIUnstrip.cs" />
|
||||||
|
<Compile Include="Unstripping\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="Unstripping\SliderHandlerUnstrip.cs" />
|
||||||
|
<Compile Include="Unstripping\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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ using UnhollowerBaseLib;
|
|||||||
using UnhollowerRuntimeLib;
|
using UnhollowerRuntimeLib;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using BF = System.Reflection.BindingFlags;
|
using BF = System.Reflection.BindingFlags;
|
||||||
|
using MelonLoader;
|
||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
@ -27,8 +28,9 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) return obj;
|
if (!typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) return obj;
|
||||||
|
|
||||||
var generic = m_tryCastMethodInfo.MakeGenericMethod(castTo);
|
return m_tryCastMethodInfo
|
||||||
return generic.Invoke(obj, null);
|
.MakeGenericMethod(castTo)
|
||||||
|
.Invoke(obj, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ExceptionToString(Exception e)
|
public static string ExceptionToString(Exception e)
|
||||||
@ -81,9 +83,10 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
if (t.IsGenericType)
|
if (t.IsGenericType)
|
||||||
{
|
{
|
||||||
return t.GetGenericTypeDefinition() is Type typeDef
|
var generic = t.GetGenericTypeDefinition();
|
||||||
&& (typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>))
|
|
||||||
|| typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.IList<>)));
|
return generic.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.List<>))
|
||||||
|
|| generic.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.IList<>));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -115,58 +118,36 @@ namespace Explorer
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type GetActualType(object m_object)
|
public static Type GetActualType(object obj)
|
||||||
{
|
{
|
||||||
if (m_object == null) return null;
|
if (obj == null) return null;
|
||||||
|
|
||||||
if (m_object is Il2CppSystem.Object ilObject)
|
if (obj is Il2CppSystem.Object ilObject)
|
||||||
{
|
{
|
||||||
var iltype = ilObject.GetIl2CppType();
|
var ilTypeName = ilObject.GetIl2CppType().AssemblyQualifiedName;
|
||||||
if (Type.GetType(iltype.AssemblyQualifiedName) is Type type)
|
|
||||||
|
if (Type.GetType(ilTypeName) is Type t && !t.FullName.Contains("System.RuntimeType"))
|
||||||
{
|
{
|
||||||
return type;
|
return t;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ilObject.GetType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ilObject.GetType();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return obj.GetType();
|
||||||
return m_object.GetType();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type[] GetAllBaseTypes(object m_object)
|
public static Type[] GetAllBaseTypes(object obj)
|
||||||
{
|
{
|
||||||
var list = new List<Type>();
|
var list = new List<Type>();
|
||||||
|
|
||||||
if (m_object is Il2CppSystem.Object ilObject)
|
var type = GetActualType(obj);
|
||||||
{
|
list.Add(type);
|
||||||
var ilType = ilObject.GetIl2CppType();
|
|
||||||
if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilTypeToManaged)
|
|
||||||
{
|
|
||||||
list.Add(ilTypeToManaged);
|
|
||||||
|
|
||||||
while (ilType.BaseType != null)
|
while (type.BaseType != null)
|
||||||
{
|
|
||||||
ilType = ilType.BaseType;
|
|
||||||
if (Type.GetType(ilType.AssemblyQualifiedName) is Type ilBaseTypeToManaged)
|
|
||||||
{
|
|
||||||
list.Add(ilBaseTypeToManaged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
var type = m_object.GetType();
|
type = type.BaseType;
|
||||||
list.Add(type);
|
list.Add(type);
|
||||||
while (type.BaseType != null)
|
|
||||||
{
|
|
||||||
type = type.BaseType;
|
|
||||||
list.Add(type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.ToArray();
|
return list.ToArray();
|
||||||
|
@ -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();
|
||||||
|
@ -33,12 +33,14 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void HorizontalLine(Color color)
|
public static void HorizontalLine(Color _color, bool small = false)
|
||||||
{
|
{
|
||||||
var c = GUI.color;
|
var orig = GUI.color;
|
||||||
GUI.color = color;
|
|
||||||
GUILayout.Box(GUIContent.none, HorizontalBar, null);
|
GUI.color = _color;
|
||||||
GUI.color = c;
|
GUILayout.Box(GUIContent.none, !small ? HorizontalBar : HorizontalBarSmall, null);
|
||||||
|
|
||||||
|
GUI.color = orig;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GUISkin _customSkin;
|
private static GUISkin _customSkin;
|
||||||
@ -46,8 +48,6 @@ namespace Explorer
|
|||||||
public static Texture2D m_nofocusTex;
|
public static Texture2D m_nofocusTex;
|
||||||
public static Texture2D m_focusTex;
|
public static Texture2D m_focusTex;
|
||||||
|
|
||||||
private static GUIStyle _horizBarStyle;
|
|
||||||
|
|
||||||
private static GUIStyle HorizontalBar
|
private static GUIStyle HorizontalBar
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -63,6 +63,24 @@ namespace Explorer
|
|||||||
return _horizBarStyle;
|
return _horizBarStyle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static GUIStyle _horizBarStyle;
|
||||||
|
|
||||||
|
private static GUIStyle HorizontalBarSmall
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_horizBarSmallStyle == null)
|
||||||
|
{
|
||||||
|
_horizBarSmallStyle = new GUIStyle();
|
||||||
|
_horizBarSmallStyle.normal.background = Texture2D.whiteTexture;
|
||||||
|
_horizBarSmallStyle.margin = new RectOffset(0, 0, 2, 2);
|
||||||
|
_horizBarSmallStyle.fixedHeight = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _horizBarSmallStyle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static GUIStyle _horizBarSmallStyle;
|
||||||
|
|
||||||
private static GUISkin CreateWindowSkin()
|
private static GUISkin CreateWindowSkin()
|
||||||
{
|
{
|
||||||
|
@ -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,9 +14,7 @@ namespace Explorer
|
|||||||
|
|
||||||
public override string Name { get => "Scene Explorer"; set => base.Name = value; }
|
public override string Name { get => "Scene Explorer"; set => base.Name = value; }
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -46,14 +44,14 @@ namespace Explorer
|
|||||||
SetTransformTarget(null);
|
SetTransformTarget(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CheckOffset(ref int offset, int childCount)
|
//public void CheckOffset(ref int offset, int childCount)
|
||||||
{
|
//{
|
||||||
if (offset >= childCount)
|
// if (offset >= childCount)
|
||||||
{
|
// {
|
||||||
offset = 0;
|
// offset = 0;
|
||||||
m_pageOffset = 0;
|
// m_pageOffset = 0;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
@ -63,7 +61,6 @@ namespace Explorer
|
|||||||
m_timeOfLastUpdate = Time.time;
|
m_timeOfLastUpdate = Time.time;
|
||||||
|
|
||||||
m_objectList = new List<GameObjectCache>();
|
m_objectList = new List<GameObjectCache>();
|
||||||
int offset = m_pageOffset * m_limit;
|
|
||||||
|
|
||||||
var allTransforms = new List<Transform>();
|
var allTransforms = new List<Transform>();
|
||||||
|
|
||||||
@ -86,15 +83,14 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_currentTotalCount = allTransforms.Count;
|
Pages.ItemCount = allTransforms.Count;
|
||||||
|
|
||||||
// make sure offset doesn't exceed count
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
CheckOffset(ref offset, m_currentTotalCount);
|
|
||||||
|
|
||||||
// sort by childcount
|
// sort by childcount
|
||||||
allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||||
|
|
||||||
for (int i = offset; i < offset + m_limit && i < m_currentTotalCount; i++)
|
for (int i = offset; i < offset + Pages.ItemsPerPage && i < Pages.ItemCount; i++)
|
||||||
{
|
{
|
||||||
var child = allTransforms[i];
|
var child = allTransforms[i];
|
||||||
m_objectList.Add(new GameObjectCache(child.gameObject));
|
m_objectList.Add(new GameObjectCache(child.gameObject));
|
||||||
@ -128,7 +124,7 @@ 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()
|
||||||
@ -242,32 +238,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;
|
m_timeOfLastUpdate = -1f;
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
m_timeOfLastUpdate = -1f;
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
@ -319,7 +307,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 +330,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
|
||||||
{
|
{
|
||||||
@ -21,11 +17,11 @@ namespace Explorer
|
|||||||
|
|
||||||
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()
|
||||||
@ -91,7 +90,6 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
//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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
443
src/Unstripping/GUIUnstrip.cs
Normal file
443
src/Unstripping/GUIUnstrip.cs
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
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
|
||||||
|
{
|
||||||
|
// This is a manual unstrip of UnityEngine.GUI and UnityEngine.GUILayout methods.
|
||||||
|
// This code is provided "as-is".
|
||||||
|
// Taken from dnSpy output using Unity 2018.4.20.
|
||||||
|
|
||||||
|
// "Unity", Unity logos, and other Unity trademarks are trademarks or
|
||||||
|
// registered trademarks of Unity Technologies or its affiliates in the
|
||||||
|
// U.S. and elsewhere.
|
||||||
|
// https://unity3d.com/legal/terms-of-service
|
||||||
|
// https://unity3d.com/legal/terms-of-service/software
|
||||||
|
|
||||||
|
public class GUIUnstrip
|
||||||
|
{
|
||||||
|
public static int s_ScrollControlId;
|
||||||
|
|
||||||
|
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 ======= //
|
||||||
|
|
||||||
|
// Fix for GUILayoutUtility.GetLastRect().
|
||||||
|
// Calls UnstripExtensions.GetLastRectUnstripped.
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix for GUILayout.Scroller and GUILayout.ScrollerRepeatButton, just calling fixed implementations.
|
||||||
|
|
||||||
|
public static float Scroller(Rect position, float value, float size, float leftValue, float rightValue, GUIStyle slider, GUIStyle thumb, GUIStyle leftButton, GUIStyle rightButton, bool horiz)
|
||||||
|
=> Scroller_Impl(position, value, size, leftValue, rightValue, slider, thumb, leftButton, rightButton, horiz);
|
||||||
|
|
||||||
|
public static bool ScrollerRepeatButton(int scrollerID, Rect rect, GUIStyle style)
|
||||||
|
=> ScrollerRepeatButton_Impl(scrollerID, rect, style);
|
||||||
|
|
||||||
|
// Simple unstrips for HorizontalScrollbar and VerticalScrollbar, they just call the Scroller unstrip.
|
||||||
|
|
||||||
|
public static float HorizontalScrollbar(Rect position, float value, float size, float leftValue, float rightValue, GUIStyle style)
|
||||||
|
{
|
||||||
|
return Scroller(position, value, size, leftValue, rightValue, style, GUI.skin.GetStyle(style.name + "thumb"), GUI.skin.GetStyle(style.name + "leftbutton"), GUI.skin.GetStyle(style.name + "rightbutton"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float VerticalScrollbar(Rect position, float value, float size, float topValue, float bottomValue, GUIStyle style)
|
||||||
|
{
|
||||||
|
return Scroller(position, value, size, topValue, bottomValue, style, GUI.skin.GetStyle(style.name + "thumb"), GUI.skin.GetStyle(style.name + "upbutton"), GUI.skin.GetStyle(style.name + "downbutton"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix for BeginScrollView.
|
||||||
|
// Uses several manually unstripped methods.
|
||||||
|
|
||||||
|
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 unstripping implementation.
|
||||||
|
if (!ManualUnstripFailed)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return BeginScrollView_Impl(scroll, false, false, GUI.skin.horizontalScrollbar, GUI.skin.verticalScrollbar, GUI.skin.scrollView, options);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MelonLogger.Log("Exception on GUIUnstrip.BeginScrollView_Impl: " + e.GetType() + ", " + e.Message + "\r\n" + e.StackTrace);
|
||||||
|
|
||||||
|
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 ======= //
|
||||||
|
|
||||||
|
// Actual unstrip of GUILayout.BeginScrollView()
|
||||||
|
|
||||||
|
private static Vector2 BeginScrollView_Impl(Vector2 scrollPosition, bool alwaysShowHorizontal, bool alwaysShowVertical, GUIStyle horizontalScrollbar,
|
||||||
|
GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options)
|
||||||
|
{
|
||||||
|
GUIUtility.CheckOnGUI();
|
||||||
|
|
||||||
|
var guiscrollGroup = (GUIScrollGroup)GUILayoutUtility.BeginLayoutGroup(
|
||||||
|
background,
|
||||||
|
null,
|
||||||
|
Il2CppType.Of<GUIScrollGroup>()
|
||||||
|
).Il2CppCast(typeof(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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual unstrip of GUI.BeginScrollView() -- note: not GUILayout.
|
||||||
|
|
||||||
|
private static Vector2 BeginScrollView_Impl(Rect position, Vector2 scrollPosition, Rect viewRect, bool alwaysShowHorizontal, bool alwaysShowVertical,
|
||||||
|
GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background)
|
||||||
|
{
|
||||||
|
GUIUtility.CheckOnGUI();
|
||||||
|
|
||||||
|
int controlID = GUIUtility.GetControlID(GUI.s_ScrollviewHash, FocusType.Passive);
|
||||||
|
|
||||||
|
var scrollViewState = (ScrollViewState)GUIUtility.GetStateObject(Il2CppType.Of<ScrollViewState>(), controlID).Il2CppCast(typeof(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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual unstrip of GUI.EndScrollView()
|
||||||
|
|
||||||
|
private static void EndScrollView_Impl(bool handleScrollWheel)
|
||||||
|
{
|
||||||
|
GUIUtility.CheckOnGUI();
|
||||||
|
|
||||||
|
if (ScrollStack.Count <= 0) return;
|
||||||
|
|
||||||
|
//ScrollViewState scrollViewState = (ScrollViewState)GUI.s_ScrollViewStates.Peek();
|
||||||
|
var state = (ScrollViewState)ScrollStack.Peek().Il2CppCast(typeof(ScrollViewState));
|
||||||
|
//ScrollViewExtensions.Dict.TryGetValue(state.Pointer, out ScrollViewExtensions scrollExt);
|
||||||
|
var scrollExt = ScrollViewStateUnstrip.FromPointer(state.Pointer);
|
||||||
|
|
||||||
|
if (scrollExt == null) throw new Exception("Could not get scrollExt!");
|
||||||
|
|
||||||
|
GUIClip.Pop();
|
||||||
|
|
||||||
|
//GUI.s_ScrollViewStates.Pop();
|
||||||
|
ScrollStack.Pop();
|
||||||
|
|
||||||
|
var position = scrollExt.position;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// state.apply = true;
|
||||||
|
scrollExt.apply = true;
|
||||||
|
|
||||||
|
Event.current.Use();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual unstrip of GUI.Scroller
|
||||||
|
|
||||||
|
private static float Scroller_Impl(Rect position, float value, float size, float leftValue, float rightValue, GUIStyle slider, GUIStyle thumb, GUIStyle leftButton, GUIStyle rightButton, bool horiz)
|
||||||
|
{
|
||||||
|
GUIUtility.CheckOnGUI();
|
||||||
|
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 = GUI.Slider(position2, value, size, leftValue, rightValue, slider, thumb, horiz, controlID);
|
||||||
|
value = Slider(position2, value, size, leftValue, rightValue, slider, thumb, horiz, controlID);
|
||||||
|
|
||||||
|
bool flag = Event.current.type == EventType.MouseUp;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
//GUI.s_ScrollControlId = 0;
|
||||||
|
GUIUnstrip.s_ScrollControlId = 0;
|
||||||
|
}
|
||||||
|
if (leftValue < rightValue)
|
||||||
|
{
|
||||||
|
value = Mathf.Clamp(value, leftValue, rightValue - size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = Mathf.Clamp(value, rightValue, leftValue - size);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual unstrip of GUI.Slider
|
||||||
|
|
||||||
|
public static float Slider(Rect position, float value, float size, float start, float end, GUIStyle slider, GUIStyle thumb, bool horiz, int id)
|
||||||
|
{
|
||||||
|
//GUIUtility.CheckOnGUI();
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
id = GUIUtility.GetControlID(GUI.s_SliderHash, FocusType.Passive, position);
|
||||||
|
}
|
||||||
|
var sliderHandler = new SliderHandlerUnstrip(position, value, size, start, end, slider, thumb, horiz, id);
|
||||||
|
return sliderHandler.Handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual unstrip of GUI.ScrollerRepeatButton
|
||||||
|
|
||||||
|
private static bool ScrollerRepeatButton_Impl(int scrollerID, Rect rect, GUIStyle style)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
if (GUI.DoRepeatButton(rect, GUIContent.none, style, FocusType.Passive))
|
||||||
|
{
|
||||||
|
//bool flag = GUI.s_ScrollControlId != scrollerID;
|
||||||
|
//GUI.s_ScrollControlId = scrollerID;
|
||||||
|
|
||||||
|
bool flag = GUIUnstrip.s_ScrollControlId != scrollerID;
|
||||||
|
GUIUnstrip.s_ScrollControlId = scrollerID;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
src/Unstripping/ScrollViewStateUnstrip.cs
Normal file
42
src/Unstripping/ScrollViewStateUnstrip.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Harmony;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
// This is a manual unstrip of UnityEngine.ScrollViewState.
|
||||||
|
// This code is provided "as-is".
|
||||||
|
// Taken from dnSpy output using Unity 2018.4.20.
|
||||||
|
|
||||||
|
// "Unity", Unity logos, and other Unity trademarks are trademarks or
|
||||||
|
// registered trademarks of Unity Technologies or its affiliates in the
|
||||||
|
// U.S. and elsewhere.
|
||||||
|
// https://unity3d.com/legal/terms-of-service
|
||||||
|
// https://unity3d.com/legal/terms-of-service/software
|
||||||
|
|
||||||
|
public class ScrollViewStateUnstrip
|
||||||
|
{
|
||||||
|
public Rect position;
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
381
src/Unstripping/SliderHandlerUnstrip.cs
Normal file
381
src/Unstripping/SliderHandlerUnstrip.cs
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnhollowerRuntimeLib;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
// This is a manual unstrip of UnityEngine.SliderHandler.
|
||||||
|
// This code is provided "as-is".
|
||||||
|
// Taken from dnSpy output using Unity 2018.4.20.
|
||||||
|
|
||||||
|
// "Unity", Unity logos, and other Unity trademarks are trademarks or
|
||||||
|
// registered trademarks of Unity Technologies or its affiliates in the
|
||||||
|
// U.S. and elsewhere.
|
||||||
|
// https://unity3d.com/legal/terms-of-service
|
||||||
|
// https://unity3d.com/legal/terms-of-service/software
|
||||||
|
|
||||||
|
public struct SliderHandlerUnstrip
|
||||||
|
{
|
||||||
|
private readonly Rect position;
|
||||||
|
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).Il2CppCast(typeof(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
50
src/Unstripping/UnstripExtensions.cs
Normal file
50
src/Unstripping/UnstripExtensions.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
// "Unity", Unity logos, and other Unity trademarks are trademarks or
|
||||||
|
// registered trademarks of Unity Technologies or its affiliates in the
|
||||||
|
// U.S. and elsewhere.
|
||||||
|
// https://unity3d.com/legal/terms-of-service
|
||||||
|
// https://unity3d.com/legal/terms-of-service/software
|
||||||
|
|
||||||
|
public static class UnstripExtensions
|
||||||
|
{
|
||||||
|
// This is a manual unstrip of GUILayoutGroup.GetLast().
|
||||||
|
// I'm using it as an Extension because it's easier this way.
|
||||||
|
|
||||||
|
public static Rect GetLastUnstripped(this GUILayoutGroup group)
|
||||||
|
{
|
||||||
|
Rect result;
|
||||||
|
if (group.m_Cursor == 0)
|
||||||
|
{
|
||||||
|
Debug.LogError("You cannot call GetLast immediately after beginning a group.");
|
||||||
|
result = GUILayoutEntry.kDummyRect;
|
||||||
|
}
|
||||||
|
else if (group.m_Cursor <= group.entries.Count)
|
||||||
|
{
|
||||||
|
GUILayoutEntry guilayoutEntry = group.entries[group.m_Cursor - 1];
|
||||||
|
result = guilayoutEntry.rect;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError(string.Concat(new object[]
|
||||||
|
{
|
||||||
|
"Getting control ",
|
||||||
|
group.m_Cursor,
|
||||||
|
"'s position in a group with only ",
|
||||||
|
group.entries.Count,
|
||||||
|
" controls when doing ",
|
||||||
|
Event.current.type
|
||||||
|
}));
|
||||||
|
result = GUILayoutEntry.kDummyRect;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,11 +21,13 @@ 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 Component[] m_components;
|
private Vector2 m_transformScroll = Vector2.zero;
|
||||||
|
private PageHelper ChildPages = new PageHelper();
|
||||||
|
|
||||||
|
private Component[] m_components;
|
||||||
private Vector2 m_compScroll = Vector2.zero;
|
private Vector2 m_compScroll = Vector2.zero;
|
||||||
|
private PageHelper CompPages = new PageHelper();
|
||||||
|
|
||||||
private float m_translateAmount = 0.3f;
|
private float m_translateAmount = 0.3f;
|
||||||
private float m_rotateAmount = 50f;
|
private float m_rotateAmount = 50f;
|
||||||
@ -71,15 +73,10 @@ 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"
|
||||||
: m_object.scene.name;
|
: m_object.scene.name;
|
||||||
|
|
||||||
var list = new List<Transform>();
|
Update();
|
||||||
for (int i = 0; i < m_object.transform.childCount; i++)
|
|
||||||
{
|
|
||||||
list.Add(m_object.transform.GetChild(i));
|
|
||||||
}
|
|
||||||
m_children = list.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
@ -91,12 +88,30 @@ namespace Explorer
|
|||||||
throw new Exception("Object is null!");
|
throw new Exception("Object is null!");
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<Component>();
|
var list = new List<Transform>();
|
||||||
|
for (int i = 0; i < m_object.transform.childCount; i++)
|
||||||
|
{
|
||||||
|
list.Add(m_object.transform.GetChild(i));
|
||||||
|
}
|
||||||
|
list.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||||
|
m_children = list.ToArray();
|
||||||
|
|
||||||
|
ChildPages.ItemCount = m_children.Length;
|
||||||
|
|
||||||
|
var list2 = new List<Component>();
|
||||||
foreach (var comp in m_object.GetComponents(ReflectionHelpers.ComponentType))
|
foreach (var comp in m_object.GetComponents(ReflectionHelpers.ComponentType))
|
||||||
{
|
{
|
||||||
list.Add(comp);
|
var ilType = comp.GetIl2CppType();
|
||||||
|
if (ilType == ReflectionHelpers.TransformType)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list2.Add(comp);
|
||||||
}
|
}
|
||||||
m_components = list.ToArray();
|
m_components = list2.ToArray();
|
||||||
|
|
||||||
|
CompPages.ItemCount = m_components.Length;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -106,7 +121,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 +169,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 +220,7 @@ namespace Explorer
|
|||||||
|
|
||||||
GameObjectControls();
|
GameObjectControls();
|
||||||
|
|
||||||
GUILayout.EndScrollView();
|
GUIUnstrip.EndScrollView();
|
||||||
|
|
||||||
if (!WindowManager.TabView)
|
if (!WindowManager.TabView)
|
||||||
{
|
{
|
||||||
@ -218,29 +237,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 +285,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 +324,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 +343,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 +365,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.EndScrollView();
|
GUIUnstrip.EndScrollView();
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
|
@ -13,15 +13,17 @@ namespace Explorer
|
|||||||
public class ReflectionWindow : UIWindow
|
public class ReflectionWindow : UIWindow
|
||||||
{
|
{
|
||||||
public override string Title => WindowManager.TabView
|
public override string Title => WindowManager.TabView
|
||||||
? $"<color=cyan>[R]</color> {ObjectType.Name}"
|
? $"<color=cyan>[R]</color> {TargetType.Name}"
|
||||||
: $"Reflection Inspector ({ObjectType.Name})";
|
: $"Reflection Inspector ({TargetType.Name})";
|
||||||
|
|
||||||
public Type ObjectType;
|
public Type TargetType;
|
||||||
|
|
||||||
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 = "";
|
||||||
@ -35,16 +37,11 @@ namespace Explorer
|
|||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
var type = ReflectionHelpers.GetActualType(Target);
|
var type = ReflectionHelpers.GetActualType(Target);
|
||||||
if (type == null)
|
|
||||||
{
|
|
||||||
MelonLogger.Log($"Could not get underlying type for object! Type: {Target?.GetType().AssemblyQualifiedName}, Value ToString: {Target?.ToString()}");
|
|
||||||
DestroyWindow();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectType = type;
|
TargetType = type;
|
||||||
|
|
||||||
var types = ReflectionHelpers.GetAllBaseTypes(Target);
|
var types = ReflectionHelpers.GetAllBaseTypes(Target);
|
||||||
|
|
||||||
CacheMembers(types);
|
CacheMembers(types);
|
||||||
|
|
||||||
if (Target is Il2CppSystem.Object ilObject)
|
if (Target is Il2CppSystem.Object ilObject)
|
||||||
@ -90,13 +87,13 @@ namespace Explorer
|
|||||||
|
|
||||||
private bool ShouldProcessMember(CacheObjectBase holder)
|
private bool ShouldProcessMember(CacheObjectBase holder)
|
||||||
{
|
{
|
||||||
if (m_filter != MemberTypes.All && m_filter != holder.MemberInfo?.MemberType) return false;
|
if (m_filter != MemberTypes.All && m_filter != holder.MemInfo?.MemberType) return false;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(holder.ReflectionException) && m_hideFailedReflection) return false;
|
if (!string.IsNullOrEmpty(holder.ReflectionException) && m_hideFailedReflection) return false;
|
||||||
|
|
||||||
if (m_search == "" || holder.MemberInfo == null) return true;
|
if (m_search == "" || holder.MemInfo == null) return true;
|
||||||
|
|
||||||
var name = holder.MemberInfo.DeclaringType.Name + "." + holder.MemberInfo.Name;
|
var name = holder.MemInfo.DeclaringType.Name + "." + holder.MemInfo.Name;
|
||||||
|
|
||||||
return name.ToLower().Contains(m_search.ToLower());
|
return name.ToLower().Contains(m_search.ToLower());
|
||||||
}
|
}
|
||||||
@ -118,7 +115,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Exception getting members for type: " + declaringType.Name);
|
MelonLogger.Log($"Exception getting members for type: {declaringType.FullName}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,11 +137,14 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
if (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property || member.MemberType == MemberTypes.Method)
|
if (member.MemberType == MemberTypes.Field || member.MemberType == MemberTypes.Property || member.MemberType == MemberTypes.Method)
|
||||||
{
|
{
|
||||||
// ignore these
|
var name = $"{member.DeclaringType.Name}.{member.Name}";
|
||||||
if (member.Name.Contains("Il2CppType") || member.Name.StartsWith("get_") || member.Name.StartsWith("set_"))
|
|
||||||
continue;
|
// blacklist (should probably make a proper implementation)
|
||||||
|
if (name == "Type.DeclaringMethod" || member.Name.StartsWith("get_") || member.Name.StartsWith("set_")) //|| member.Name.Contains("Il2CppType")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var name = member.DeclaringType.Name + "." + member.Name;
|
|
||||||
if (member is MethodInfo mi)
|
if (member is MethodInfo mi)
|
||||||
{
|
{
|
||||||
name += " (";
|
name += " (";
|
||||||
@ -161,7 +161,7 @@ namespace Explorer
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var cached = CacheObjectBase.GetCacheObject(null, member, target);
|
var cached = CacheObjectBase.GetCacheObject(member, target);
|
||||||
if (cached != null)
|
if (cached != null)
|
||||||
{
|
{
|
||||||
names.Add(name);
|
names.Add(name);
|
||||||
@ -198,7 +198,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Label("<b>Type:</b> <color=cyan>" + ObjectType.FullName + "</color>", new GUILayoutOption[] { GUILayout.Width(245f) });
|
GUILayout.Label("<b>Type:</b> <color=cyan>" + TargetType.FullName + "</color>", new GUILayoutOption[] { GUILayout.Width(245f) });
|
||||||
if (m_uObj)
|
if (m_uObj)
|
||||||
{
|
{
|
||||||
GUILayout.Label("Name: " + m_uObj.name, null);
|
GUILayout.Label("Name: " + m_uObj.name, null);
|
||||||
@ -256,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);
|
||||||
|
|
||||||
@ -298,38 +289,32 @@ namespace Explorer
|
|||||||
|
|
||||||
GUILayout.BeginVertical(GUI.skin.box, null);
|
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
var members = this.m_cachedMembersFiltered;
|
var members = this.m_cachedMembersFiltered;
|
||||||
int offsetIndex = (m_pageOffset * m_limitPerPage) + index;
|
int start = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
if (offsetIndex >= 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 = offsetIndex; (j < offsetIndex + m_limitPerPage && j < members.Length); j++)
|
|
||||||
{
|
{
|
||||||
var holder = members[j];
|
var holder = members[j];
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
|
GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
holder.Draw(rect, 180f);
|
holder.Draw(rect, 180f);
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
index++;
|
// if not last element
|
||||||
|
if (!(j == (start + Pages.ItemsPerPage - 1) || j == (members.Length - 1)))
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
@ -366,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +86,90 @@ namespace Explorer
|
|||||||
|
|
||||||
// ========= Public Helpers =========
|
// ========= Public Helpers =========
|
||||||
|
|
||||||
|
public static UIWindow InspectObject(object obj, out bool createdNew, bool forceReflection = false)
|
||||||
|
{
|
||||||
|
createdNew = false;
|
||||||
|
|
||||||
|
if (Input.GetKey(KeyCode.LeftShift))
|
||||||
|
{
|
||||||
|
forceReflection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Il2CppSystem.Object iObj = null;
|
||||||
|
if (obj is Il2CppSystem.Object isObj)
|
||||||
|
{
|
||||||
|
iObj = isObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!forceReflection)
|
||||||
|
{
|
||||||
|
foreach (var window in Windows)
|
||||||
|
{
|
||||||
|
bool equals = ReferenceEquals(obj, window.Target);
|
||||||
|
|
||||||
|
if (!equals && iObj is Il2CppSystem.Object iCurrent && window.Target is Il2CppSystem.Object iTarget)
|
||||||
|
{
|
||||||
|
if (iCurrent.GetIl2CppType() != iTarget.GetIl2CppType())
|
||||||
|
{
|
||||||
|
if (iCurrent is Transform transform)
|
||||||
|
{
|
||||||
|
iCurrent = transform.gameObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
equals = iCurrent.Pointer == iTarget.Pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (equals)
|
||||||
|
{
|
||||||
|
FocusWindow(window);
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createdNew = true;
|
||||||
|
if (!forceReflection && (obj is GameObject || obj is Transform))
|
||||||
|
{
|
||||||
|
return InspectGameObject(obj as GameObject ?? (obj as Transform).gameObject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return InspectReflection(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FocusWindow(UIWindow window)
|
||||||
|
{
|
||||||
|
if (!TabView)
|
||||||
|
{
|
||||||
|
GUI.BringWindowToFront(window.windowID);
|
||||||
|
GUI.FocusWindow(window.windowID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TabViewWindow.Instance.TargetTabID = Windows.IndexOf(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UIWindow InspectGameObject(GameObject obj)
|
||||||
|
{
|
||||||
|
var new_window = UIWindow.CreateWindow<GameObjectWindow>(obj);
|
||||||
|
FocusWindow(new_window);
|
||||||
|
|
||||||
|
return new_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UIWindow InspectReflection(object obj)
|
||||||
|
{
|
||||||
|
var new_window = UIWindow.CreateWindow<ReflectionWindow>(obj);
|
||||||
|
FocusWindow(new_window);
|
||||||
|
|
||||||
|
return new_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Misc Helpers ===
|
||||||
|
|
||||||
public static bool IsMouseInWindow
|
public static bool IsMouseInWindow
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -140,71 +224,5 @@ namespace Explorer
|
|||||||
|
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UIWindow InspectObject(object obj, out bool createdNew)
|
|
||||||
{
|
|
||||||
createdNew = false;
|
|
||||||
|
|
||||||
UnityEngine.Object uObj = null;
|
|
||||||
if (obj is UnityEngine.Object)
|
|
||||||
{
|
|
||||||
uObj = obj as UnityEngine.Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var window in Windows)
|
|
||||||
{
|
|
||||||
bool equals = ReferenceEquals(obj, window.Target);
|
|
||||||
|
|
||||||
if (!equals && uObj != null && window.Target is UnityEngine.Object uTarget)
|
|
||||||
{
|
|
||||||
equals = uObj.m_CachedPtr == uTarget.m_CachedPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (equals)
|
|
||||||
{
|
|
||||||
FocusWindow(window);
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createdNew = true;
|
|
||||||
if (obj is GameObject || obj is Transform)
|
|
||||||
{
|
|
||||||
return InspectGameObject(obj as GameObject ?? (obj as Transform).gameObject);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return InspectReflection(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void FocusWindow(UIWindow window)
|
|
||||||
{
|
|
||||||
if (!TabView)
|
|
||||||
{
|
|
||||||
GUI.BringWindowToFront(window.windowID);
|
|
||||||
GUI.FocusWindow(window.windowID);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TabViewWindow.Instance.TargetTabID = Windows.IndexOf(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static UIWindow InspectGameObject(GameObject obj)
|
|
||||||
{
|
|
||||||
var new_window = UIWindow.CreateWindow<GameObjectWindow>(obj);
|
|
||||||
FocusWindow(new_window);
|
|
||||||
|
|
||||||
return new_window;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UIWindow InspectReflection(object obj)
|
|
||||||
{
|
|
||||||
var new_window = UIWindow.CreateWindow<ReflectionWindow>(obj);
|
|
||||||
FocusWindow(new_window);
|
|
||||||
|
|
||||||
return new_window;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user