mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-26 10:03:10 +08:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
4e8b84b67e | |||
5b94e31a12 | |||
692a37635e | |||
9cb1cea025 | |||
e13f198815 | |||
9a059c1056 | |||
ffb6cad8c2 | |||
d0a4863139 | |||
bb8837d58c | |||
a236b272c1 | |||
18de1eaf1c | |||
b1264c6912 | |||
9836566e55 |
15
README.md
15
README.md
@ -1,4 +1,4 @@
|
|||||||
# CppExplorer []()
|
# CppExplorer [](https://github.com/HerpDerpinstine/MelonLoader)
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img align="center" src="https://sinai-dev.github.io/images/thumbs/02.png">
|
<img align="center" src="https://sinai-dev.github.io/images/thumbs/02.png">
|
||||||
@ -14,10 +14,9 @@
|
|||||||
<img src="https://img.shields.io/github/downloads/sinai-dev/CppExplorer/total.svg" />
|
<img src="https://img.shields.io/github/downloads/sinai-dev/CppExplorer/total.svg" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
### Known issue
|
### Known issues
|
||||||
Due to limitations with [Il2CppAssemblyUnhollower](https://github.com/knah/Il2CppAssemblyUnhollower)'s Unstripping, CppExplorer may encounter a `MissingMethodException` when trying to use certain UnityEngine methods.
|
* CppExplorer may experience a `MissingMethodException` when trying to use certain UnityEngine methods. If you experience this, please open an issue and I will do my best to fix it.
|
||||||
|
* Scrolling with mouse wheel in the CppExplorer menu may not work on all games at the moment.
|
||||||
Since version [1.5.4](https://github.com/sinai-dev/CppExplorer/releases/tag/1.5.4), CppExplorer manually unstrips most of these methods itself. If you encounter more methods which failed unstripping, please let me know by opening an issue and I will do my best to fix it.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Scene hierarchy explorer
|
* Scene hierarchy explorer
|
||||||
@ -45,7 +44,7 @@ Requires [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) to be ins
|
|||||||
* A simple menu which allows you to traverse the Transform heirarchy of the scene.
|
* A simple menu which allows you to traverse the Transform heirarchy of the scene.
|
||||||
* Click on a GameObject to set it as the current path, or <b>Inspect</b> it to send it to an Inspector Window.
|
* Click on a GameObject to set it as the current path, or <b>Inspect</b> it to send it to an Inspector Window.
|
||||||
|
|
||||||
[](https://i.imgur.com/2b0q0jL.png)
|
[](https://i.imgur.com/BzTOCvp.png)
|
||||||
|
|
||||||
### Inspectors
|
### Inspectors
|
||||||
|
|
||||||
@ -60,7 +59,7 @@ CppExplorer has two main inspector modes: <b>GameObject Inspector</b>, and <b>Re
|
|||||||
* Allows you to see the children and components on a GameObject.
|
* Allows you to see the children and components on a GameObject.
|
||||||
* Can use some basic GameObject Controls such as translating and rotating the object, destroy it, clone it, etc.
|
* Can use some basic GameObject Controls such as translating and rotating the object, destroy it, clone it, etc.
|
||||||
|
|
||||||
[](https://i.imgur.com/JTxqlx4.png)
|
[](https://i.imgur.com/DiDvl0Q.png)
|
||||||
|
|
||||||
### Reflection Inspector
|
### Reflection Inspector
|
||||||
|
|
||||||
@ -68,7 +67,7 @@ CppExplorer has two main inspector modes: <b>GameObject Inspector</b>, and <b>Re
|
|||||||
* Allows you to inspect Properties, Fields and basic Methods, as well as set primitive values and evaluate primitive methods.
|
* Allows you to inspect Properties, Fields and basic Methods, as well as set primitive values and evaluate primitive methods.
|
||||||
* Can search and filter members for the ones you are interested in.
|
* Can search and filter members for the ones you are interested in.
|
||||||
|
|
||||||
[](https://i.imgur.com/iq92m0l.png)
|
[](https://i.imgur.com/Pq127XD.png)
|
||||||
|
|
||||||
### Object Search
|
### Object Search
|
||||||
|
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using MelonLoader;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Explorer
|
|
||||||
{
|
|
||||||
public class CacheDictionary : CacheObjectBase
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
public override void Init()
|
|
||||||
{
|
|
||||||
//base.Init();
|
|
||||||
|
|
||||||
Value = "Unsupported";
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateValue()
|
|
||||||
{
|
|
||||||
//base.UpdateValue();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
|
||||||
{
|
|
||||||
GUILayout.Label("<color=red>Dictionary (unsupported)</color>", null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,6 +14,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public object Value;
|
public object Value;
|
||||||
public string ValueTypeName;
|
public string ValueTypeName;
|
||||||
|
public Type ValueType;
|
||||||
|
|
||||||
// Reflection Inspector only
|
// Reflection Inspector only
|
||||||
public MemberInfo MemInfo { get; set; }
|
public MemberInfo MemInfo { get; set; }
|
||||||
@ -79,11 +80,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
Type type = null;
|
Type type = null;
|
||||||
|
|
||||||
if (obj != null)
|
if (memberInfo != null)
|
||||||
{
|
|
||||||
type = ReflectionHelpers.GetActualType(obj);
|
|
||||||
}
|
|
||||||
else if (memberInfo != null)
|
|
||||||
{
|
{
|
||||||
if (memberInfo is FieldInfo fi)
|
if (memberInfo is FieldInfo fi)
|
||||||
{
|
{
|
||||||
@ -98,6 +95,10 @@ namespace Explorer
|
|||||||
type = mi.ReturnType;
|
type = mi.ReturnType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (obj != null)
|
||||||
|
{
|
||||||
|
type = ReflectionHelpers.GetActualType(obj);
|
||||||
|
}
|
||||||
|
|
||||||
if (type == null)
|
if (type == null)
|
||||||
{
|
{
|
||||||
@ -114,6 +115,11 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
CacheObjectBase holder;
|
CacheObjectBase holder;
|
||||||
|
|
||||||
|
// This is pretty ugly, could probably make a cleaner implementation.
|
||||||
|
// However, the only cleaner ways I can think of are slower and probably not worth it.
|
||||||
|
|
||||||
|
// Note: the order is somewhat important.
|
||||||
|
|
||||||
if (memberInfo is MethodInfo mi)
|
if (memberInfo is MethodInfo mi)
|
||||||
{
|
{
|
||||||
if (CacheMethod.CanEvaluate(mi))
|
if (CacheMethod.CanEvaluate(mi))
|
||||||
@ -137,20 +143,38 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
holder = new CacheEnum();
|
holder = new CacheEnum();
|
||||||
}
|
}
|
||||||
else if (ReflectionHelpers.IsArray(valueType) || ReflectionHelpers.IsList(valueType))
|
else if (valueType == typeof(Vector2) || valueType == typeof(Vector3) || valueType == typeof(Vector4))
|
||||||
{
|
{
|
||||||
holder = new CacheList();
|
holder = new CacheVector();
|
||||||
}
|
}
|
||||||
|
else if (valueType == typeof(Quaternion))
|
||||||
|
{
|
||||||
|
holder = new CacheQuaternion();
|
||||||
|
}
|
||||||
|
else if (valueType == typeof(Color))
|
||||||
|
{
|
||||||
|
holder = new CacheColor();
|
||||||
|
}
|
||||||
|
else if (valueType == typeof(Rect))
|
||||||
|
{
|
||||||
|
holder = new CacheRect();
|
||||||
|
}
|
||||||
|
// must check this before IsEnumerable
|
||||||
else if (ReflectionHelpers.IsDictionary(valueType))
|
else if (ReflectionHelpers.IsDictionary(valueType))
|
||||||
{
|
{
|
||||||
holder = new CacheDictionary();
|
holder = new CacheDictionary();
|
||||||
}
|
}
|
||||||
|
else if (ReflectionHelpers.IsEnumerable(valueType) || ReflectionHelpers.IsCppList(valueType))
|
||||||
|
{
|
||||||
|
holder = new CacheList();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
holder = new CacheOther();
|
holder = new CacheOther();
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.Value = obj;
|
holder.Value = obj;
|
||||||
|
holder.ValueType = valueType;
|
||||||
holder.ValueTypeName = valueType.FullName;
|
holder.ValueTypeName = valueType.FullName;
|
||||||
|
|
||||||
if (memberInfo != null)
|
if (memberInfo != null)
|
||||||
|
278
src/CachedObjects/Object/CacheDictionary.cs
Normal file
278
src/CachedObjects/Object/CacheDictionary.cs
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public class CacheDictionary : CacheObjectBase
|
||||||
|
{
|
||||||
|
public bool IsExpanded { get; set; }
|
||||||
|
public PageHelper Pages = new PageHelper();
|
||||||
|
|
||||||
|
public float WhiteSpace = 215f;
|
||||||
|
public float ButtonWidthOffset = 290f;
|
||||||
|
|
||||||
|
private CacheObjectBase[] m_cachedKeys;
|
||||||
|
private CacheObjectBase[] m_cachedValues;
|
||||||
|
|
||||||
|
public Type TypeOfKeys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (m_keysType == null) GetGenericArguments();
|
||||||
|
return m_keysType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Type m_keysType;
|
||||||
|
|
||||||
|
public Type TypeOfValues
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (m_valuesType == null) GetGenericArguments();
|
||||||
|
return m_valuesType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Type m_valuesType;
|
||||||
|
|
||||||
|
public IDictionary IDict
|
||||||
|
{
|
||||||
|
get => m_iDictionary ?? (m_iDictionary = Value as IDictionary) ?? Il2CppDictionaryToMono();
|
||||||
|
set => m_iDictionary = value;
|
||||||
|
}
|
||||||
|
private IDictionary m_iDictionary;
|
||||||
|
|
||||||
|
// This is a bit janky due to Il2Cpp Dictionary not implementing IDictionary.
|
||||||
|
private IDictionary Il2CppDictionaryToMono()
|
||||||
|
{
|
||||||
|
// note: "ValueType" is the Dictionary itself, TypeOfValues is the 'Dictionary.Values' type.
|
||||||
|
|
||||||
|
// make generic dictionary from key and value type
|
||||||
|
var dict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>)
|
||||||
|
.MakeGenericType(TypeOfKeys, TypeOfValues));
|
||||||
|
|
||||||
|
// get keys and values
|
||||||
|
var keys = ValueType.GetProperty("Keys") .GetValue(Value);
|
||||||
|
var values = ValueType.GetProperty("Values").GetValue(Value);
|
||||||
|
|
||||||
|
// create lists to hold them
|
||||||
|
var keyList = new List<object>();
|
||||||
|
var valueList = new List<object>();
|
||||||
|
|
||||||
|
// get keys enumerator and store keys
|
||||||
|
var keyEnumerator = keys.GetType().GetMethod("GetEnumerator").Invoke(keys, null);
|
||||||
|
var keyCollectionType = keyEnumerator.GetType();
|
||||||
|
var keyMoveNext = keyCollectionType.GetMethod("MoveNext");
|
||||||
|
var keyCurrent = keyCollectionType.GetProperty("Current");
|
||||||
|
while ((bool)keyMoveNext.Invoke(keyEnumerator, null))
|
||||||
|
{
|
||||||
|
keyList.Add(keyCurrent.GetValue(keyEnumerator));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get values enumerator and store values
|
||||||
|
var valueEnumerator = values.GetType().GetMethod("GetEnumerator").Invoke(values, null);
|
||||||
|
var valueCollectionType = valueEnumerator.GetType();
|
||||||
|
var valueMoveNext = valueCollectionType.GetMethod("MoveNext");
|
||||||
|
var valueCurrent = valueCollectionType.GetProperty("Current");
|
||||||
|
while ((bool)valueMoveNext.Invoke(valueEnumerator, null))
|
||||||
|
{
|
||||||
|
valueList.Add(valueCurrent.GetValue(valueEnumerator));
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally iterate into actual dictionary
|
||||||
|
for (int i = 0; i < keyList.Count; i++)
|
||||||
|
{
|
||||||
|
dict.Add(keyList[i], valueList[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== Methods ==========
|
||||||
|
|
||||||
|
private void GetGenericArguments()
|
||||||
|
{
|
||||||
|
if (m_keysType == null || m_valuesType == null)
|
||||||
|
{
|
||||||
|
if (this.MemInfo != null)
|
||||||
|
{
|
||||||
|
Type memberType = null;
|
||||||
|
switch (this.MemInfo.MemberType)
|
||||||
|
{
|
||||||
|
case MemberTypes.Field:
|
||||||
|
memberType = (MemInfo as FieldInfo).FieldType;
|
||||||
|
break;
|
||||||
|
case MemberTypes.Property:
|
||||||
|
memberType = (MemInfo as PropertyInfo).PropertyType;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memberType != null && memberType.IsGenericType)
|
||||||
|
{
|
||||||
|
m_keysType = memberType.GetGenericArguments()[0];
|
||||||
|
m_valuesType = memberType.GetGenericArguments()[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Value != null)
|
||||||
|
{
|
||||||
|
var type = Value.GetType();
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
m_keysType = type.GetGenericArguments()[0];
|
||||||
|
m_valuesType = type.GetGenericArguments()[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateValue()
|
||||||
|
{
|
||||||
|
base.UpdateValue();
|
||||||
|
|
||||||
|
// reset
|
||||||
|
IDict = null;
|
||||||
|
|
||||||
|
if (Value == null || IDict == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var keys = new List<CacheObjectBase>();
|
||||||
|
foreach (var key in IDict.Keys)
|
||||||
|
{
|
||||||
|
var cache = GetCacheObject(key, TypeOfKeys);
|
||||||
|
cache.UpdateValue();
|
||||||
|
keys.Add(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = new List<CacheObjectBase>();
|
||||||
|
foreach (var val in IDict.Values)
|
||||||
|
{
|
||||||
|
var cache = GetCacheObject(val, TypeOfValues);
|
||||||
|
cache.UpdateValue();
|
||||||
|
values.Add(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cachedKeys = keys.ToArray();
|
||||||
|
m_cachedValues = values.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= GUI Draw =============
|
||||||
|
|
||||||
|
public override void DrawValue(Rect window, float width)
|
||||||
|
{
|
||||||
|
if (m_cachedKeys == null || m_cachedValues == null)
|
||||||
|
{
|
||||||
|
GUILayout.Label("Cached keys or values is null!", null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = m_cachedKeys.Length;
|
||||||
|
|
||||||
|
if (!IsExpanded)
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||||
|
string btnLabel = $"<color=yellow>[{count}] Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
|
||||||
|
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - ButtonWidthOffset) }))
|
||||||
|
{
|
||||||
|
WindowManager.InspectObject(Value, out bool _);
|
||||||
|
}
|
||||||
|
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||||
|
|
||||||
|
GUILayout.Space(5);
|
||||||
|
|
||||||
|
if (IsExpanded)
|
||||||
|
{
|
||||||
|
float whitespace = WhiteSpace;
|
||||||
|
if (whitespace > 0)
|
||||||
|
{
|
||||||
|
ClampLabelWidth(window, ref whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pages.ItemCount = count;
|
||||||
|
|
||||||
|
if (count > Pages.ItemsPerPage)
|
||||||
|
{
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
|
||||||
|
Pages.CurrentPageLabel();
|
||||||
|
|
||||||
|
// prev/next page buttons
|
||||||
|
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||||
|
{
|
||||||
|
Pages.TurnPage(Turn.Left);
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||||
|
{
|
||||||
|
Pages.TurnPage(Turn.Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pages.DrawLimitInputArea();
|
||||||
|
|
||||||
|
GUILayout.Space(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
|
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
||||||
|
{
|
||||||
|
var key = m_cachedKeys[i];
|
||||||
|
var val = m_cachedValues[i];
|
||||||
|
|
||||||
|
//collapsing the BeginHorizontal called from ReflectionWindow.WindowFunction or previous array entry
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
|
//GUILayout.Space(whitespace);
|
||||||
|
|
||||||
|
if (key == null || val == null)
|
||||||
|
{
|
||||||
|
GUILayout.Label($"[{i}] <i><color=grey>(null)</color></i>", null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||||
|
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(new GUILayoutOption[] { GUILayout.MinWidth((window.width / 3) - 60f) });
|
||||||
|
GUILayout.Label("Key:", new GUILayoutOption[] { GUILayout.Width(40) });
|
||||||
|
key.DrawValue(window, (window.width / 2) - 30f);
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Label("Value:", new GUILayoutOption[] { GUILayout.Width(40) });
|
||||||
|
val.DrawValue(window, (window.width / 2) - 30f);
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -218,6 +218,7 @@ namespace Explorer
|
|||||||
|
|
||||||
if (GetCacheObject(obj, t) is CacheObjectBase cached)
|
if (GetCacheObject(obj, t) is CacheObjectBase cached)
|
||||||
{
|
{
|
||||||
|
cached.UpdateValue();
|
||||||
list.Add(cached);
|
list.Add(cached);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -262,7 +263,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||||
string btnLabel = "<color=yellow>[" + count + "] " + EntryType + "</color>";
|
string btnLabel = "<color=yellow>[" + count + "] " + EntryType.FullName + "</color>";
|
||||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - ButtonWidthOffset) }))
|
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - ButtonWidthOffset) }))
|
||||||
{
|
{
|
||||||
WindowManager.InspectObject(Value, out bool _);
|
WindowManager.InspectObject(Value, out bool _);
|
||||||
@ -305,12 +306,6 @@ namespace Explorer
|
|||||||
GUILayout.Space(5);
|
GUILayout.Space(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
//int offset = ArrayOffset * ArrayLimit;
|
|
||||||
//if (offset >= count)
|
|
||||||
//{
|
|
||||||
// offset = 0;
|
|
||||||
// ArrayOffset = 0;
|
|
||||||
//}
|
|
||||||
int offset = Pages.CalculateOffsetIndex();
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
@ -212,6 +212,11 @@ namespace Explorer
|
|||||||
cacheList.WhiteSpace = 0f;
|
cacheList.WhiteSpace = 0f;
|
||||||
cacheList.ButtonWidthOffset += 70f;
|
cacheList.ButtonWidthOffset += 70f;
|
||||||
}
|
}
|
||||||
|
else if (m_cachedReturnValue is CacheDictionary cacheDict)
|
||||||
|
{
|
||||||
|
cacheDict.WhiteSpace = 0f;
|
||||||
|
cacheDict.ButtonWidthOffset += 70f;
|
||||||
|
}
|
||||||
m_cachedReturnValue.UpdateValue();
|
m_cachedReturnValue.UpdateValue();
|
||||||
}
|
}
|
||||||
else
|
else
|
87
src/CachedObjects/Struct/CacheColor.cs
Normal file
87
src/CachedObjects/Struct/CacheColor.cs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public class CacheColor : CacheObjectBase
|
||||||
|
{
|
||||||
|
private string r = "0";
|
||||||
|
private string g = "0";
|
||||||
|
private string b = "0";
|
||||||
|
private string a = "0";
|
||||||
|
|
||||||
|
public override void UpdateValue()
|
||||||
|
{
|
||||||
|
base.UpdateValue();
|
||||||
|
|
||||||
|
var color = (Color)Value;
|
||||||
|
|
||||||
|
r = color.r.ToString();
|
||||||
|
g = color.g.ToString();
|
||||||
|
b = color.b.ToString();
|
||||||
|
a = color.a.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawValue(Rect window, float width)
|
||||||
|
{
|
||||||
|
GUILayout.Label($"<color=yellow>Color</color>: {((Color)Value).ToString()}", null);
|
||||||
|
|
||||||
|
if (CanWrite)
|
||||||
|
{
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
var whitespace = window.width - width - 90;
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("R:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
r = GUILayout.TextField(r, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("G:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
g = GUILayout.TextField(g, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("B:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
b = GUILayout.TextField(b, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("A:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
a = GUILayout.TextField(a, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
// draw set value button
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||||
|
{
|
||||||
|
SetValueFromInput();
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetValueFromInput()
|
||||||
|
{
|
||||||
|
if (float.TryParse(r, out float fR)
|
||||||
|
&& float.TryParse(g, out float fG)
|
||||||
|
&& float.TryParse(b, out float fB)
|
||||||
|
&& float.TryParse(a, out float fA))
|
||||||
|
{
|
||||||
|
Value = new Color(fR, fB, fG, fA);
|
||||||
|
SetValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.Label(Value.ToString(), null);// + "<color=yellow><i> (" + ValueType + ")</i></color>", null);
|
GUILayout.Label(Value.ToString() + "<color=yellow><i> (" + ValueType + ")</i></color>", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetEnum(ref object value, int change)
|
public void SetEnum(ref object value, int change)
|
@ -8,91 +8,37 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public class CachePrimitive : CacheObjectBase
|
public class CachePrimitive : CacheObjectBase
|
||||||
{
|
{
|
||||||
public enum PrimitiveTypes
|
private bool m_isBool;
|
||||||
{
|
private bool m_isString;
|
||||||
Bool,
|
|
||||||
Double,
|
|
||||||
Float,
|
|
||||||
Int,
|
|
||||||
String,
|
|
||||||
Char
|
|
||||||
}
|
|
||||||
|
|
||||||
private string m_valueToString;
|
private string m_valueToString;
|
||||||
|
|
||||||
public PrimitiveTypes PrimitiveType;
|
public MethodInfo ParseMethod => m_parseMethod ?? (m_parseMethod = Value.GetType().GetMethod("Parse", new Type[] { typeof(string) }));
|
||||||
|
|
||||||
public MethodInfo ParseMethod
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (m_parseMethod == null)
|
|
||||||
{
|
|
||||||
m_parseMethod = Value.GetType().GetMethod("Parse", new Type[] { typeof(string) });
|
|
||||||
}
|
|
||||||
return m_parseMethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MethodInfo m_parseMethod;
|
private MethodInfo m_parseMethod;
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
if (Value == null)
|
if (ValueType == null)
|
||||||
{
|
{
|
||||||
// this must mean it is a string. No other primitive type should be nullable.
|
ValueType = Value?.GetType();
|
||||||
PrimitiveType = PrimitiveTypes.String;
|
|
||||||
return;
|
// has to be a string at this point
|
||||||
|
if (ValueType == null)
|
||||||
|
{
|
||||||
|
ValueType = typeof(string);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_valueToString = Value.ToString();
|
if (ValueType == typeof(string))
|
||||||
var type = Value.GetType();
|
|
||||||
|
|
||||||
if (type == typeof(bool))
|
|
||||||
{
|
{
|
||||||
PrimitiveType = PrimitiveTypes.Bool;
|
m_isString = true;
|
||||||
}
|
}
|
||||||
else if (type == typeof(double))
|
else if (ValueType == typeof(bool))
|
||||||
{
|
{
|
||||||
PrimitiveType = PrimitiveTypes.Double;
|
m_isBool = true;
|
||||||
}
|
|
||||||
else if (type == typeof(float))
|
|
||||||
{
|
|
||||||
PrimitiveType = PrimitiveTypes.Float;
|
|
||||||
}
|
|
||||||
else if (IsInteger(type))
|
|
||||||
{
|
|
||||||
PrimitiveType = PrimitiveTypes.Int;
|
|
||||||
}
|
|
||||||
else if (type == typeof(char))
|
|
||||||
{
|
|
||||||
PrimitiveType = PrimitiveTypes.Char;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PrimitiveType = PrimitiveTypes.String;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsInteger(Type type)
|
|
||||||
{
|
|
||||||
// For our purposes, all types of int can be treated the same, including IntPtr.
|
|
||||||
return _integerTypes.Contains(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly HashSet<Type> _integerTypes = new HashSet<Type>
|
|
||||||
{
|
|
||||||
typeof(int),
|
|
||||||
typeof(uint),
|
|
||||||
typeof(short),
|
|
||||||
typeof(ushort),
|
|
||||||
typeof(long),
|
|
||||||
typeof(ulong),
|
|
||||||
typeof(byte),
|
|
||||||
typeof(sbyte),
|
|
||||||
typeof(IntPtr)
|
|
||||||
};
|
|
||||||
|
|
||||||
public override void UpdateValue()
|
public override void UpdateValue()
|
||||||
{
|
{
|
||||||
base.UpdateValue();
|
base.UpdateValue();
|
||||||
@ -102,11 +48,10 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
if (PrimitiveType == PrimitiveTypes.Bool)
|
if (m_isBool)
|
||||||
{
|
{
|
||||||
var b = (bool)Value;
|
var b = (bool)Value;
|
||||||
var color = $"<color={(b ? "lime>" : "red>")}";
|
var label = $"<color={(b ? "lime" : "red")}>{b}</color>";
|
||||||
var label = $"{color}{b}</color>";
|
|
||||||
|
|
||||||
if (CanWrite)
|
if (CanWrite)
|
||||||
{
|
{
|
||||||
@ -123,7 +68,8 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Label("<color=yellow><i>" + PrimitiveType + "</i></color>", new GUILayoutOption[] { GUILayout.Width(50) });
|
// using ValueType.Name instead of ValueTypeName, because we only want the short name.
|
||||||
|
GUILayout.Label("<color=yellow><i>" + ValueType.Name + "</i></color>", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||||
|
|
||||||
int dynSize = 25 + (m_valueToString.Length * 15);
|
int dynSize = 25 + (m_valueToString.Length * 15);
|
||||||
var maxwidth = window.width - 300f;
|
var maxwidth = window.width - 300f;
|
||||||
@ -150,7 +96,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetValueFromInput(string value)
|
public void SetValueFromInput(string valueString)
|
||||||
{
|
{
|
||||||
if (MemInfo == null)
|
if (MemInfo == null)
|
||||||
{
|
{
|
||||||
@ -158,16 +104,15 @@ namespace Explorer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PrimitiveType == PrimitiveTypes.String)
|
if (m_isString)
|
||||||
{
|
{
|
||||||
Value = value;
|
Value = valueString;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var val = ParseMethod.Invoke(null, new object[] { value });
|
Value = ParseMethod.Invoke(null, new object[] { valueString });
|
||||||
Value = val;
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
78
src/CachedObjects/Struct/CacheQuaternion.cs
Normal file
78
src/CachedObjects/Struct/CacheQuaternion.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public class CacheQuaternion : CacheObjectBase
|
||||||
|
{
|
||||||
|
private string x = "0";
|
||||||
|
private string y = "0";
|
||||||
|
private string z = "0";
|
||||||
|
|
||||||
|
public override void UpdateValue()
|
||||||
|
{
|
||||||
|
base.UpdateValue();
|
||||||
|
|
||||||
|
var euler = ((Quaternion)Value).eulerAngles;
|
||||||
|
|
||||||
|
x = euler.x.ToString();
|
||||||
|
y = euler.y.ToString();
|
||||||
|
z = euler.z.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawValue(Rect window, float width)
|
||||||
|
{
|
||||||
|
GUILayout.Label($"<color=yellow>Quaternion</color>: {((Quaternion)Value).eulerAngles.ToString()}", null);
|
||||||
|
|
||||||
|
if (CanWrite)
|
||||||
|
{
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
var whitespace = window.width - width - 90;
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
// draw set value button
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||||
|
{
|
||||||
|
SetValueFromInput();
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetValueFromInput()
|
||||||
|
{
|
||||||
|
if (float.TryParse(x, out float fX)
|
||||||
|
&& float.TryParse(y, out float fY)
|
||||||
|
&& float.TryParse(z, out float fZ))
|
||||||
|
{
|
||||||
|
Value = Quaternion.Euler(new Vector3(fX, fY, fZ));
|
||||||
|
SetValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
src/CachedObjects/Struct/CacheRect.cs
Normal file
87
src/CachedObjects/Struct/CacheRect.cs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public class CacheRect : CacheObjectBase
|
||||||
|
{
|
||||||
|
private string x = "0";
|
||||||
|
private string y = "0";
|
||||||
|
private string w = "0";
|
||||||
|
private string h = "0";
|
||||||
|
|
||||||
|
public override void UpdateValue()
|
||||||
|
{
|
||||||
|
base.UpdateValue();
|
||||||
|
|
||||||
|
var rect = (Rect)Value;
|
||||||
|
|
||||||
|
x = rect.x.ToString();
|
||||||
|
y = rect.y.ToString();
|
||||||
|
w = rect.width.ToString();
|
||||||
|
h = rect.height.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawValue(Rect window, float width)
|
||||||
|
{
|
||||||
|
GUILayout.Label($"<color=yellow>Rect</color>: {((Rect)Value).ToString()}", null);
|
||||||
|
|
||||||
|
if (CanWrite)
|
||||||
|
{
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
var whitespace = window.width - width - 90;
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("H:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
h = GUILayout.TextField(h, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
// draw set value button
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||||
|
{
|
||||||
|
SetValueFromInput();
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetValueFromInput()
|
||||||
|
{
|
||||||
|
if (float.TryParse(x, out float fX)
|
||||||
|
&& float.TryParse(y, out float fY)
|
||||||
|
&& float.TryParse(w, out float fW)
|
||||||
|
&& float.TryParse(h, out float fH))
|
||||||
|
{
|
||||||
|
Value = new Rect(fX, fY, fW, fH);
|
||||||
|
SetValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
142
src/CachedObjects/Struct/CacheVector.cs
Normal file
142
src/CachedObjects/Struct/CacheVector.cs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public class CacheVector : CacheObjectBase
|
||||||
|
{
|
||||||
|
public int VectorSize = 2;
|
||||||
|
|
||||||
|
private string x = "0";
|
||||||
|
private string y = "0";
|
||||||
|
private string z = "0";
|
||||||
|
private string w = "0";
|
||||||
|
|
||||||
|
private MethodInfo m_toStringMethod;
|
||||||
|
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
if (Value is Vector2)
|
||||||
|
{
|
||||||
|
VectorSize = 2;
|
||||||
|
}
|
||||||
|
else if (Value is Vector3)
|
||||||
|
{
|
||||||
|
VectorSize = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VectorSize = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_toStringMethod = Value.GetType().GetMethod("ToString", new Type[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateValue()
|
||||||
|
{
|
||||||
|
base.UpdateValue();
|
||||||
|
|
||||||
|
if (Value is Vector2 vec2)
|
||||||
|
{
|
||||||
|
x = vec2.x.ToString();
|
||||||
|
y = vec2.y.ToString();
|
||||||
|
}
|
||||||
|
else if (Value is Vector3 vec3)
|
||||||
|
{
|
||||||
|
x = vec3.x.ToString();
|
||||||
|
y = vec3.y.ToString();
|
||||||
|
z = vec3.z.ToString();
|
||||||
|
}
|
||||||
|
else if (Value is Vector4 vec4)
|
||||||
|
{
|
||||||
|
x = vec4.x.ToString();
|
||||||
|
y = vec4.y.ToString();
|
||||||
|
z = vec4.z.ToString();
|
||||||
|
w = vec4.w.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawValue(Rect window, float width)
|
||||||
|
{
|
||||||
|
GUILayout.Label($"<color=yellow>Vector{VectorSize}</color>: {(string)m_toStringMethod.Invoke(Value, new object[0])}", null);
|
||||||
|
|
||||||
|
if (CanWrite)
|
||||||
|
{
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
var whitespace = window.width - width - 90;
|
||||||
|
|
||||||
|
// always draw x and y
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
if (VectorSize > 2)
|
||||||
|
{
|
||||||
|
// draw z
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
if (VectorSize > 3)
|
||||||
|
{
|
||||||
|
// draw w
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw set value button
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(whitespace);
|
||||||
|
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||||
|
{
|
||||||
|
SetValueFromInput();
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetValueFromInput()
|
||||||
|
{
|
||||||
|
if (float.TryParse(x, out float fX)
|
||||||
|
&& float.TryParse(y, out float fY)
|
||||||
|
&& float.TryParse(z, out float fZ)
|
||||||
|
&& float.TryParse(w, out float fW))
|
||||||
|
{
|
||||||
|
object vector = null;
|
||||||
|
|
||||||
|
switch (VectorSize)
|
||||||
|
{
|
||||||
|
case 2: vector = new Vector2(fX, fY); break;
|
||||||
|
case 3: vector = new Vector3(fX, fY, fZ); break;
|
||||||
|
case 4: vector = new Vector4(fX, fY, fZ, fW); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vector != null)
|
||||||
|
{
|
||||||
|
Value = vector;
|
||||||
|
SetValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@ -12,7 +13,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.5";
|
public const string VERSION = "1.6.0";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
|
|
||||||
public const string NAME = "CppExplorer"
|
public const string NAME = "CppExplorer"
|
||||||
|
@ -120,17 +120,21 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="CachedObjects\CacheDictionary.cs" />
|
<Compile Include="CachedObjects\Struct\CacheColor.cs" />
|
||||||
<Compile Include="CachedObjects\CacheEnum.cs" />
|
<Compile Include="CachedObjects\Object\CacheDictionary.cs" />
|
||||||
<Compile Include="CachedObjects\CacheGameObject.cs" />
|
<Compile Include="CachedObjects\Struct\CacheEnum.cs" />
|
||||||
<Compile Include="CachedObjects\CacheList.cs" />
|
<Compile Include="CachedObjects\Object\CacheGameObject.cs" />
|
||||||
<Compile Include="CachedObjects\CachePrimitive.cs" />
|
<Compile Include="CachedObjects\Object\CacheList.cs" />
|
||||||
<Compile Include="CachedObjects\CacheOther.cs" />
|
<Compile Include="CachedObjects\Struct\CachePrimitive.cs" />
|
||||||
<Compile Include="CachedObjects\CacheMethod.cs" />
|
<Compile Include="CachedObjects\Other\CacheOther.cs" />
|
||||||
|
<Compile Include="CachedObjects\Other\CacheMethod.cs" />
|
||||||
|
<Compile Include="CachedObjects\Struct\CacheQuaternion.cs" />
|
||||||
|
<Compile Include="CachedObjects\Struct\CacheVector.cs" />
|
||||||
|
<Compile Include="CachedObjects\Struct\CacheRect.cs" />
|
||||||
<Compile Include="CppExplorer.cs" />
|
<Compile Include="CppExplorer.cs" />
|
||||||
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
||||||
<Compile Include="Unstripping\GUIUnstrip.cs" />
|
<Compile Include="UnstripFixes\GUIUnstrip.cs" />
|
||||||
<Compile Include="Unstripping\ScrollViewStateUnstrip.cs" />
|
<Compile Include="UnstripFixes\ScrollViewStateUnstrip.cs" />
|
||||||
<Compile Include="Extensions\UnityExtensions.cs" />
|
<Compile Include="Extensions\UnityExtensions.cs" />
|
||||||
<Compile Include="Helpers\PageHelper.cs" />
|
<Compile Include="Helpers\PageHelper.cs" />
|
||||||
<Compile Include="Helpers\ReflectionHelpers.cs" />
|
<Compile Include="Helpers\ReflectionHelpers.cs" />
|
||||||
@ -138,8 +142,8 @@
|
|||||||
<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="UnstripFixes\SliderHandlerUnstrip.cs" />
|
||||||
<Compile Include="Unstripping\UnstripExtensions.cs" />
|
<Compile Include="UnstripFixes\UnstripExtensions.cs" />
|
||||||
<Compile Include="Windows\ResizeDrag.cs" />
|
<Compile Include="Windows\ResizeDrag.cs" />
|
||||||
<Compile Include="Windows\TabViewWindow.cs" />
|
<Compile Include="Windows\TabViewWindow.cs" />
|
||||||
<Compile Include="Windows\UIWindow.cs" />
|
<Compile Include="Windows\UIWindow.cs" />
|
||||||
|
@ -16,7 +16,18 @@ namespace Explorer
|
|||||||
public class PageHelper
|
public class PageHelper
|
||||||
{
|
{
|
||||||
public int PageOffset { get; set; }
|
public int PageOffset { get; set; }
|
||||||
public int ItemsPerPage { get; set; } = 20;
|
|
||||||
|
public int ItemsPerPage
|
||||||
|
{
|
||||||
|
get => m_itemsPerPage;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
m_itemsPerPage = value;
|
||||||
|
CalculateMaxOffset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private int m_itemsPerPage = 20;
|
||||||
|
|
||||||
public int ItemCount
|
public int ItemCount
|
||||||
{
|
{
|
||||||
get => m_count;
|
get => m_count;
|
||||||
|
@ -74,12 +74,13 @@ namespace Explorer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsArray(Type t)
|
public static bool IsEnumerable(Type t)
|
||||||
{
|
{
|
||||||
return typeof(System.Collections.IEnumerable).IsAssignableFrom(t);
|
return typeof(System.Collections.IEnumerable).IsAssignableFrom(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsList(Type t)
|
// Only Il2Cpp List needs this check. C# List is IEnumerable.
|
||||||
|
public static bool IsCppList(Type t)
|
||||||
{
|
{
|
||||||
if (t.IsGenericType)
|
if (t.IsGenericType)
|
||||||
{
|
{
|
||||||
@ -98,21 +99,21 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
return t.IsGenericType
|
return t.IsGenericType
|
||||||
&& t.GetGenericTypeDefinition() is Type typeDef
|
&& t.GetGenericTypeDefinition() is Type typeDef
|
||||||
&& typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.Dictionary<,>));
|
&& (typeDef.IsAssignableFrom(typeof(Il2CppSystem.Collections.Generic.Dictionary<,>))
|
||||||
|
|| typeDef.IsAssignableFrom(typeof(Dictionary<,>)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type GetTypeByName(string typeName)
|
public static Type GetTypeByName(string typeName)
|
||||||
{
|
{
|
||||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
{
|
{
|
||||||
try
|
foreach (var type in GetTypesSafe(asm))
|
||||||
{
|
{
|
||||||
if (asm.GetType(typeName) is Type type)
|
if (type.FullName == typeName)
|
||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -137,6 +138,13 @@ namespace Explorer
|
|||||||
return obj.GetType();
|
return obj.GetType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Type> GetTypesSafe(Assembly asm)
|
||||||
|
{
|
||||||
|
try { return asm.GetTypes(); }
|
||||||
|
catch (ReflectionTypeLoadException e) { return e.Types.Where(x => x != null); }
|
||||||
|
catch { return Enumerable.Empty<Type>(); }
|
||||||
|
}
|
||||||
|
|
||||||
public static Type[] GetAllBaseTypes(object obj)
|
public static Type[] GetAllBaseTypes(object obj)
|
||||||
{
|
{
|
||||||
var list = new List<Type>();
|
var list = new List<Type>();
|
||||||
|
@ -56,7 +56,10 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
_horizBarStyle = new GUIStyle();
|
_horizBarStyle = new GUIStyle();
|
||||||
_horizBarStyle.normal.background = Texture2D.whiteTexture;
|
_horizBarStyle.normal.background = Texture2D.whiteTexture;
|
||||||
_horizBarStyle.margin = new RectOffset(0, 0, 4, 4);
|
var rectOffset = new RectOffset();
|
||||||
|
rectOffset.top = 4;
|
||||||
|
rectOffset.bottom = 4;
|
||||||
|
_horizBarStyle.margin = rectOffset;
|
||||||
_horizBarStyle.fixedHeight = 2;
|
_horizBarStyle.fixedHeight = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +76,10 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
_horizBarSmallStyle = new GUIStyle();
|
_horizBarSmallStyle = new GUIStyle();
|
||||||
_horizBarSmallStyle.normal.background = Texture2D.whiteTexture;
|
_horizBarSmallStyle.normal.background = Texture2D.whiteTexture;
|
||||||
_horizBarSmallStyle.margin = new RectOffset(0, 0, 2, 2);
|
var rectOffset = new RectOffset();
|
||||||
|
rectOffset.top = 2;
|
||||||
|
rectOffset.bottom = 2;
|
||||||
|
_horizBarSmallStyle.margin = rectOffset;
|
||||||
_horizBarSmallStyle.fixedHeight = 1;
|
_horizBarSmallStyle.fixedHeight = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public class ConsolePage : WindowPage
|
public class ConsolePage : WindowPage
|
||||||
{
|
{
|
||||||
public override string Name { get => "C# Console"; set => base.Name = value; }
|
public override string Name { get => "C# Console"; }
|
||||||
|
|
||||||
private ScriptEvaluator _evaluator;
|
private ScriptEvaluator _evaluator;
|
||||||
private readonly StringBuilder _sb = new StringBuilder();
|
private readonly StringBuilder _sb = new StringBuilder();
|
||||||
|
@ -12,27 +12,26 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public static ScenePage Instance;
|
public static ScenePage Instance;
|
||||||
|
|
||||||
public override string Name { get => "Scene Explorer"; set => base.Name = value; }
|
public override string Name { get => "Scene Explorer"; }
|
||||||
|
|
||||||
public PageHelper Pages = new PageHelper();
|
public PageHelper Pages = new PageHelper();
|
||||||
|
|
||||||
private float m_timeOfLastUpdate = -1f;
|
private float m_timeOfLastUpdate = -1f;
|
||||||
|
private const int PASSIVE_UPDATE_INTERVAL = 1;
|
||||||
|
|
||||||
// ----- Holders for GUI elements ----- //
|
private static bool m_getRootObjectsFailed;
|
||||||
|
|
||||||
private string m_currentScene = "";
|
private static string m_currentScene = "";
|
||||||
|
|
||||||
// gameobject list
|
// gameobject list
|
||||||
private Transform m_currentTransform;
|
private Transform m_currentTransform;
|
||||||
private List<GameObjectCache> m_objectList = new List<GameObjectCache>();
|
private readonly List<GameObjectCache> m_objectList = new List<GameObjectCache>();
|
||||||
|
|
||||||
// search bar
|
// search bar
|
||||||
private bool m_searching = false;
|
private bool m_searching = false;
|
||||||
private string m_searchInput = "";
|
private string m_searchInput = "";
|
||||||
private List<GameObjectCache> m_searchResults = new List<GameObjectCache>();
|
private List<GameObjectCache> m_searchResults = new List<GameObjectCache>();
|
||||||
|
|
||||||
// ------------ Init and Update ------------ //
|
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
Instance = this;
|
Instance = this;
|
||||||
@ -44,64 +43,6 @@ namespace Explorer
|
|||||||
SetTransformTarget(null);
|
SetTransformTarget(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
//public void CheckOffset(ref int offset, int childCount)
|
|
||||||
//{
|
|
||||||
// if (offset >= childCount)
|
|
||||||
// {
|
|
||||||
// offset = 0;
|
|
||||||
// m_pageOffset = 0;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
public override void Update()
|
|
||||||
{
|
|
||||||
if (m_searching) return;
|
|
||||||
|
|
||||||
if (Time.time - m_timeOfLastUpdate < 1f) return;
|
|
||||||
m_timeOfLastUpdate = Time.time;
|
|
||||||
|
|
||||||
m_objectList = new List<GameObjectCache>();
|
|
||||||
|
|
||||||
var allTransforms = new List<Transform>();
|
|
||||||
|
|
||||||
// get current list of all transforms (either scene root or our current transform children)
|
|
||||||
if (m_currentTransform)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < m_currentTransform.childCount; i++)
|
|
||||||
{
|
|
||||||
allTransforms.Add(m_currentTransform.GetChild(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var scene = SceneManager.GetSceneByName(m_currentScene);
|
|
||||||
|
|
||||||
var list = new Il2CppSystem.Collections.Generic.List<GameObject>
|
|
||||||
{
|
|
||||||
Capacity = scene.rootCount
|
|
||||||
};
|
|
||||||
Scene.GetRootGameObjectsInternal(scene.handle, list);
|
|
||||||
|
|
||||||
foreach (var obj in list)
|
|
||||||
{
|
|
||||||
allTransforms.Add(obj.transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Pages.ItemCount = allTransforms.Count;
|
|
||||||
|
|
||||||
int offset = Pages.CalculateOffsetIndex();
|
|
||||||
|
|
||||||
// sort by childcount
|
|
||||||
allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
|
||||||
|
|
||||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < Pages.ItemCount; i++)
|
|
||||||
{
|
|
||||||
var child = allTransforms[i];
|
|
||||||
m_objectList.Add(new GameObjectCache(child.gameObject));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTransformTarget(Transform t)
|
public void SetTransformTarget(Transform t)
|
||||||
{
|
{
|
||||||
m_currentTransform = t;
|
m_currentTransform = t;
|
||||||
@ -109,8 +50,7 @@ namespace Explorer
|
|||||||
if (m_searching)
|
if (m_searching)
|
||||||
CancelSearch();
|
CancelSearch();
|
||||||
|
|
||||||
m_timeOfLastUpdate = -1f;
|
Update_Impl(true);
|
||||||
Update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TraverseUp()
|
public void TraverseUp()
|
||||||
@ -135,23 +75,123 @@ namespace Explorer
|
|||||||
public void CancelSearch()
|
public void CancelSearch()
|
||||||
{
|
{
|
||||||
m_searching = false;
|
m_searching = false;
|
||||||
|
|
||||||
|
if (m_getRootObjectsFailed && !m_currentTransform)
|
||||||
|
{
|
||||||
|
GetRootObjectsManual_Impl();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<GameObjectCache> SearchSceneObjects(string _search)
|
public List<GameObjectCache> SearchSceneObjects(string _search)
|
||||||
{
|
{
|
||||||
var matches = new List<GameObjectCache>();
|
var matches = new List<GameObjectCache>();
|
||||||
|
|
||||||
foreach (var obj in Resources.FindObjectsOfTypeAll<GameObject>())
|
foreach (var obj in Resources.FindObjectsOfTypeAll(ReflectionHelpers.GameObjectType))
|
||||||
{
|
{
|
||||||
if (obj.name.ToLower().Contains(_search.ToLower()) && obj.scene.name == m_currentScene)
|
var go = obj.TryCast<GameObject>();
|
||||||
|
if (go.name.ToLower().Contains(_search.ToLower()) && go.scene.name == m_currentScene)
|
||||||
{
|
{
|
||||||
matches.Add(new GameObjectCache(obj));
|
matches.Add(new GameObjectCache(go));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Update()
|
||||||
|
{
|
||||||
|
if (m_searching) return;
|
||||||
|
|
||||||
|
if (Time.time - m_timeOfLastUpdate < PASSIVE_UPDATE_INTERVAL) return;
|
||||||
|
m_timeOfLastUpdate = Time.time;
|
||||||
|
|
||||||
|
Update_Impl();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update_Impl(bool manual = false)
|
||||||
|
{
|
||||||
|
List<Transform> allTransforms = new List<Transform>();
|
||||||
|
|
||||||
|
// get current list of all transforms (either scene root or our current transform children)
|
||||||
|
if (m_currentTransform)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_currentTransform.childCount; i++)
|
||||||
|
{
|
||||||
|
allTransforms.Add(m_currentTransform.GetChild(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!m_getRootObjectsFailed)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var scene = SceneManager.GetSceneByName(m_currentScene);
|
||||||
|
|
||||||
|
allTransforms.AddRange(scene.GetRootGameObjects()
|
||||||
|
.Select(it => it.transform));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
MelonLogger.Log("Exception getting root scene objects, falling back to backup method...");
|
||||||
|
|
||||||
|
m_getRootObjectsFailed = true;
|
||||||
|
allTransforms.AddRange(GetRootObjectsManual_Impl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!manual)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
allTransforms.AddRange(GetRootObjectsManual_Impl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pages.ItemCount = allTransforms.Count;
|
||||||
|
|
||||||
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
|
// sort by childcount
|
||||||
|
allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||||
|
|
||||||
|
m_objectList.Clear();
|
||||||
|
|
||||||
|
for (int i = offset; i < offset + Pages.ItemsPerPage && i < Pages.ItemCount; i++)
|
||||||
|
{
|
||||||
|
var child = allTransforms[i];
|
||||||
|
m_objectList.Add(new GameObjectCache(child.gameObject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<Transform> GetRootObjectsManual_Impl()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var array = Resources.FindObjectsOfTypeAll(ReflectionHelpers.TransformType);
|
||||||
|
|
||||||
|
var list = new List<Transform>();
|
||||||
|
foreach (var obj in array)
|
||||||
|
{
|
||||||
|
var transform = obj.TryCast<Transform>();
|
||||||
|
if (transform.parent == null && transform.gameObject.scene.name == m_currentScene)
|
||||||
|
{
|
||||||
|
list.Add(transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MelonLogger.Log("Exception getting root scene objects (manual): "
|
||||||
|
+ e.GetType() + ", " + e.Message + "\r\n"
|
||||||
|
+ e.StackTrace);
|
||||||
|
return new Transform[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --------- GUI Draw Function --------- //
|
// --------- GUI Draw Function --------- //
|
||||||
|
|
||||||
public override void DrawWindow()
|
public override void DrawWindow()
|
||||||
@ -251,8 +291,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
Pages.TurnPage(Turn.Left, ref this.scroll);
|
Pages.TurnPage(Turn.Left, ref this.scroll);
|
||||||
|
|
||||||
m_timeOfLastUpdate = -1f;
|
Update_Impl(true);
|
||||||
Update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pages.CurrentPageLabel();
|
Pages.CurrentPageLabel();
|
||||||
@ -261,8 +300,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
Pages.TurnPage(Turn.Right, ref this.scroll);
|
Pages.TurnPage(Turn.Right, ref this.scroll);
|
||||||
|
|
||||||
m_timeOfLastUpdate = -1f;
|
Update_Impl(true);
|
||||||
Update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,12 +330,24 @@ namespace Explorer
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Label("Scene Root GameObjects:", null);
|
GUILayout.Label("Scene Root GameObjects:", null);
|
||||||
|
|
||||||
|
if (m_getRootObjectsFailed)
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("Update Root Object List (auto-update failed!)", null))
|
||||||
|
{
|
||||||
|
Update_Impl(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_objectList.Count > 0)
|
if (m_objectList.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var obj in m_objectList)
|
for (int i = 0; i < m_objectList.Count; i++)
|
||||||
{
|
{
|
||||||
|
var obj = m_objectList[i];
|
||||||
|
|
||||||
|
if (obj == null) continue;
|
||||||
|
|
||||||
if (!obj.RefGameObject)
|
if (!obj.RefGameObject)
|
||||||
{
|
{
|
||||||
string label = "<color=red><i>null";
|
string label = "<color=red><i>null";
|
||||||
|
@ -13,7 +13,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public static SearchPage Instance;
|
public static SearchPage Instance;
|
||||||
|
|
||||||
public override string Name { get => "Object Search"; set => base.Name = value; }
|
public override string Name { get => "Object Search"; }
|
||||||
|
|
||||||
private string m_searchInput = "";
|
private string m_searchInput = "";
|
||||||
private string m_typeInput = "";
|
private string m_typeInput = "";
|
||||||
@ -137,14 +137,11 @@ namespace Explorer
|
|||||||
|
|
||||||
if (m_searchResults.Count > 0)
|
if (m_searchResults.Count > 0)
|
||||||
{
|
{
|
||||||
//int offset = m_pageOffset * this.m_limit;
|
|
||||||
//if (offset >= count) m_pageOffset = 0;
|
|
||||||
int offset = Pages.CalculateOffsetIndex();
|
int offset = Pages.CalculateOffsetIndex();
|
||||||
|
|
||||||
for (int i = offset; i < offset + Pages.ItemsPerPage && 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -175,16 +172,6 @@ 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;
|
|
||||||
//GUILayout.Label("Results per page:", new GUILayoutOption[] { GUILayout.Width(120) });
|
|
||||||
//var resultinput = m_limit.ToString();
|
|
||||||
//resultinput = GUILayout.TextField(resultinput, new GUILayoutOption[] { GUILayout.Width(55) });
|
|
||||||
//if (int.TryParse(resultinput, out int _i) && _i > 0)
|
|
||||||
//{
|
|
||||||
// m_limit = _i;
|
|
||||||
//}
|
|
||||||
//GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
|
||||||
|
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
@ -266,7 +253,7 @@ namespace Explorer
|
|||||||
CacheResults(FindAllObjectsOfType(m_searchInput, m_typeInput));
|
CacheResults(FindAllObjectsOfType(m_searchInput, m_typeInput));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<object> FindAllObjectsOfType(string _search, string _type)
|
private List<object> FindAllObjectsOfType(string searchQuery, string typeName)
|
||||||
{
|
{
|
||||||
Il2CppSystem.Type searchType = null;
|
Il2CppSystem.Type searchType = null;
|
||||||
|
|
||||||
@ -274,13 +261,18 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var findType = ReflectionHelpers.GetTypeByName(_type);
|
if (ReflectionHelpers.GetTypeByName(typeName) is Type t)
|
||||||
searchType = Il2CppSystem.Type.GetType(findType.AssemblyQualifiedName);
|
{
|
||||||
//MelonLogger.Log("Search type: " + findType.AssemblyQualifiedName);
|
searchType = Il2CppSystem.Type.GetType(t.AssemblyQualifiedName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"Could not find a Type by the name of '{typeName}'!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Exception: " + e.GetType() + ", " + e.Message + "\r\n" + e.StackTrace);
|
MelonLogger.Log("Exception getting Search Type: " + e.GetType() + ", " + e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TypeMode == TypeFilter.Object)
|
else if (TypeMode == TypeFilter.Object)
|
||||||
@ -298,7 +290,10 @@ namespace Explorer
|
|||||||
|
|
||||||
if (!ReflectionHelpers.ObjectType.IsAssignableFrom(searchType))
|
if (!ReflectionHelpers.ObjectType.IsAssignableFrom(searchType))
|
||||||
{
|
{
|
||||||
MelonLogger.LogError("Your Custom Class Type must inherit from UnityEngine.Object!");
|
if (searchType != null)
|
||||||
|
{
|
||||||
|
MelonLogger.LogWarning("Your Custom Class Type must inherit from UnityEngine.Object!");
|
||||||
|
}
|
||||||
return new List<object>();
|
return new List<object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,12 +308,13 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
if (i >= 2000) break;
|
if (i >= 2000) break;
|
||||||
|
|
||||||
if (_search != "" && !obj.name.ToLower().Contains(_search.ToLower()))
|
if (searchQuery != "" && !obj.name.ToLower().Contains(searchQuery.ToLower()))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchType == ReflectionHelpers.ComponentType && ReflectionHelpers.TransformType.IsAssignableFrom(obj.GetIl2CppType()))
|
if (searchType.FullName == ReflectionHelpers.ComponentType.FullName
|
||||||
|
&& ReflectionHelpers.TransformType.IsAssignableFrom(obj.GetIl2CppType()))
|
||||||
{
|
{
|
||||||
// Transforms shouldn't really be counted as Components, skip them.
|
// Transforms shouldn't really be counted as Components, skip them.
|
||||||
// They're more akin to GameObjects.
|
// They're more akin to GameObjects.
|
||||||
@ -376,43 +372,70 @@ namespace Explorer
|
|||||||
|
|
||||||
// ====== other ========
|
// ====== other ========
|
||||||
|
|
||||||
|
private static bool FilterName(string name)
|
||||||
|
{
|
||||||
|
// Don't really want these instances.
|
||||||
|
return !name.StartsWith("Mono")
|
||||||
|
&& !name.StartsWith("System")
|
||||||
|
&& !name.StartsWith("Il2CppSystem")
|
||||||
|
&& !name.StartsWith("Iced");
|
||||||
|
}
|
||||||
|
|
||||||
// credit: ManlyMarco (RuntimeUnityEditor)
|
// credit: ManlyMarco (RuntimeUnityEditor)
|
||||||
public static IEnumerable<object> GetInstanceClassScanner()
|
public static IEnumerable<object> GetInstanceClassScanner()
|
||||||
{
|
{
|
||||||
var query = AppDomain.CurrentDomain.GetAssemblies()
|
var query = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
.Where(x => !x.FullName.StartsWith("Mono"))
|
.SelectMany(ReflectionHelpers.GetTypesSafe)
|
||||||
.SelectMany(GetTypesSafe)
|
|
||||||
.Where(t => t.IsClass && !t.IsAbstract && !t.ContainsGenericParameters);
|
.Where(t => t.IsClass && !t.IsAbstract && !t.ContainsGenericParameters);
|
||||||
|
|
||||||
|
var flags = BindingFlags.Public | BindingFlags.Static;
|
||||||
|
var flatFlags = flags | BindingFlags.FlattenHierarchy;
|
||||||
|
|
||||||
foreach (var type in query)
|
foreach (var type in query)
|
||||||
{
|
{
|
||||||
object obj = null;
|
object obj = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
obj = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)?.GetValue(null, null);
|
var pi = type.GetProperty("Instance", flags);
|
||||||
}
|
|
||||||
catch
|
if (pi == null)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
obj = type.GetField("Instance", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)?.GetValue(null);
|
pi = type.GetProperty("Instance", flatFlags);
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
|
if (pi != null)
|
||||||
{
|
{
|
||||||
|
obj = pi.GetValue(null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var fi = type.GetField("Instance", flags);
|
||||||
|
|
||||||
|
if (fi == null)
|
||||||
|
{
|
||||||
|
fi = type.GetField("Instance", flatFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fi != null)
|
||||||
|
{
|
||||||
|
obj = fi.GetValue(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (obj != null && !obj.ToString().StartsWith("Mono"))
|
catch { }
|
||||||
|
|
||||||
|
if (obj != null)
|
||||||
{
|
{
|
||||||
|
var t = ReflectionHelpers.GetActualType(obj);
|
||||||
|
|
||||||
|
if (!FilterName(t.FullName) || ReflectionHelpers.IsEnumerable(t) || ReflectionHelpers.IsCppList(t))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
yield return obj;
|
yield return obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<Type> GetTypesSafe(Assembly asm)
|
|
||||||
{
|
|
||||||
try { return asm.GetTypes(); }
|
|
||||||
catch (ReflectionTypeLoadException e) { return e.Types.Where(x => x != null); }
|
|
||||||
catch { return Enumerable.Empty<Type>(); }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public abstract class WindowPage
|
public abstract class WindowPage
|
||||||
{
|
{
|
||||||
public virtual string Name { get; set; }
|
public virtual string Name { get; }
|
||||||
|
|
||||||
public Vector2 scroll = Vector2.zero;
|
public Vector2 scroll = Vector2.zero;
|
||||||
|
|
||||||
|
@ -13,13 +13,6 @@ using Harmony;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
// This is a copy+paste of UnityEngine source code, fixed for Il2Cpp.
|
|
||||||
// Taken from dnSpy output using Unity 2018.4.20.
|
|
||||||
|
|
||||||
// Subject to Unity's License and ToS.
|
|
||||||
// https://unity3d.com/legal/terms-of-service
|
|
||||||
// https://unity3d.com/legal/terms-of-service/software
|
|
||||||
|
|
||||||
public class GUIUnstrip
|
public class GUIUnstrip
|
||||||
{
|
{
|
||||||
public static int s_ScrollControlId;
|
public static int s_ScrollControlId;
|
||||||
@ -31,19 +24,26 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
#if Release_2019
|
if (m_scrollViewStatesInfo == null)
|
||||||
return GUI.scrollViewStates;
|
{
|
||||||
#else
|
try
|
||||||
return GUI.s_ScrollViewStates;
|
{
|
||||||
#endif
|
m_scrollViewStatesInfo = typeof(GUI).GetProperty("scrollViewStates");
|
||||||
|
if (m_scrollViewStatesInfo == null) throw new Exception();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
m_scrollViewStatesInfo = typeof(GUI).GetProperty("s_scrollViewStates");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (GenericStack)m_scrollViewStatesInfo?.GetValue(null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static PropertyInfo m_scrollViewStatesInfo;
|
||||||
|
|
||||||
// ======= public methods ======= //
|
// ======= public methods ======= //
|
||||||
|
|
||||||
// Fix for GUILayoutUtility.GetLastRect().
|
|
||||||
// Calls UnstripExtensions.GetLastUnstripped().
|
|
||||||
|
|
||||||
public static Rect GetLastRect()
|
public static Rect GetLastRect()
|
||||||
{
|
{
|
||||||
EventType type = Event.current.type;
|
EventType type = Event.current.type;
|
||||||
@ -59,28 +59,7 @@ namespace Explorer
|
|||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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_Impl(position, value, size, leftValue, rightValue, style,
|
|
||||||
GUI.skin.GetStyle(style.name + "thumb"),
|
|
||||||
GUI.skin.GetStyle(style.name + "leftbutton"),
|
|
||||||
GUI.skin.GetStyle(style.name + "rightbutton"),
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float VerticalScrollbar(Rect position, float value, float size, float topValue, float bottomValue, GUIStyle style)
|
|
||||||
{
|
|
||||||
return Scroller_Impl(position, value, size, topValue, bottomValue, style,
|
|
||||||
GUI.skin.GetStyle(style.name + "thumb"),
|
|
||||||
GUI.skin.GetStyle(style.name + "upbutton"),
|
|
||||||
GUI.skin.GetStyle(style.name + "downbutton"),
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix for BeginScrollView.
|
// Fix for BeginScrollView.
|
||||||
// Uses several manually unstripped methods.
|
|
||||||
|
|
||||||
public static Vector2 BeginScrollView(Vector2 scroll, params GUILayoutOption[] options)
|
public static Vector2 BeginScrollView(Vector2 scroll, params GUILayoutOption[] options)
|
||||||
{
|
{
|
||||||
@ -98,7 +77,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try manual unstripping implementation.
|
// Try manual implementation.
|
||||||
if (!ManualUnstripFailed)
|
if (!ManualUnstripFailed)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -107,7 +86,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Exception on GUIUnstrip.BeginScrollView_Impl: " + e.GetType() + ", " + e.Message + "\r\n" + e.StackTrace);
|
MelonLogger.Log("Exception on GUIUnstrip.BeginScrollView_ImplLayout: " + e.GetType() + ", " + e.Message + "\r\n" + e.StackTrace);
|
||||||
|
|
||||||
ManualUnstripFailed = true;
|
ManualUnstripFailed = true;
|
||||||
return scroll;
|
return scroll;
|
||||||
@ -136,8 +115,6 @@ namespace Explorer
|
|||||||
|
|
||||||
// ======= private methods ======= //
|
// ======= private methods ======= //
|
||||||
|
|
||||||
// Actual unstrip of GUILayout.BeginScrollView()
|
|
||||||
|
|
||||||
private static Vector2 BeginScrollView_ImplLayout(Vector2 scrollPosition, bool alwaysShowHorizontal, bool alwaysShowVertical,
|
private static Vector2 BeginScrollView_ImplLayout(Vector2 scrollPosition, bool alwaysShowHorizontal, bool alwaysShowVertical,
|
||||||
GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options)
|
GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background, params GUILayoutOption[] options)
|
||||||
{
|
{
|
||||||
@ -171,8 +148,6 @@ namespace Explorer
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual unstrip of GUI.BeginScrollView()
|
|
||||||
|
|
||||||
private static Vector2 BeginScrollView_Impl(Rect position, Vector2 scrollPosition, Rect viewRect, bool alwaysShowHorizontal,
|
private static Vector2 BeginScrollView_Impl(Rect position, Vector2 scrollPosition, Rect viewRect, bool alwaysShowHorizontal,
|
||||||
bool alwaysShowVertical, GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background)
|
bool alwaysShowVertical, GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background)
|
||||||
{
|
{
|
||||||
@ -204,7 +179,7 @@ namespace Explorer
|
|||||||
|
|
||||||
ScrollStack.Push(scrollViewState);
|
ScrollStack.Push(scrollViewState);
|
||||||
|
|
||||||
Rect screenRect = new Rect(position);
|
Rect screenRect = new Rect(position.x, position.y, position.width, position.height);
|
||||||
EventType type = Event.current.type;
|
EventType type = Event.current.type;
|
||||||
if (type != EventType.Layout)
|
if (type != EventType.Layout)
|
||||||
{
|
{
|
||||||
@ -238,7 +213,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
if (flag2 && horizontalScrollbar != GUIStyle.none)
|
if (flag2 && horizontalScrollbar != GUIStyle.none)
|
||||||
{
|
{
|
||||||
scrollPosition.x = HorizontalScrollbar(
|
scrollPosition.x = HorizBar_Impl(
|
||||||
new Rect(
|
new Rect(
|
||||||
position.x,
|
position.x,
|
||||||
position.yMax - horizontalScrollbar.fixedHeight,
|
position.yMax - horizontalScrollbar.fixedHeight,
|
||||||
@ -260,7 +235,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
if (flag && verticalScrollbar != GUIStyle.none)
|
if (flag && verticalScrollbar != GUIStyle.none)
|
||||||
{
|
{
|
||||||
scrollPosition.y = VerticalScrollbar(
|
scrollPosition.y = VertBar_Impl(
|
||||||
new Rect(
|
new Rect(
|
||||||
screenRect.xMax + (float)verticalScrollbar.margin.left,
|
screenRect.xMax + (float)verticalScrollbar.margin.left,
|
||||||
screenRect.y,
|
screenRect.y,
|
||||||
@ -296,7 +271,23 @@ namespace Explorer
|
|||||||
return scrollPosition;
|
return scrollPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual unstrip of GUI.EndScrollView()
|
public static float HorizBar_Impl(Rect position, float value, float size, float leftValue, float rightValue, GUIStyle style)
|
||||||
|
{
|
||||||
|
return Scroller_Impl(position, value, size, leftValue, rightValue, style,
|
||||||
|
GUI.skin.GetStyle(style.name + "thumb"),
|
||||||
|
GUI.skin.GetStyle(style.name + "leftbutton"),
|
||||||
|
GUI.skin.GetStyle(style.name + "rightbutton"),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float VertBar_Impl(Rect position, float value, float size, float topValue, float bottomValue, GUIStyle style)
|
||||||
|
{
|
||||||
|
return Scroller_Impl(position, value, size, topValue, bottomValue, style,
|
||||||
|
GUI.skin.GetStyle(style.name + "thumb"),
|
||||||
|
GUI.skin.GetStyle(style.name + "upbutton"),
|
||||||
|
GUI.skin.GetStyle(style.name + "downbutton"),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
private static void EndScrollView_Impl(bool handleScrollWheel)
|
private static void EndScrollView_Impl(bool handleScrollWheel)
|
||||||
{
|
{
|
||||||
@ -336,8 +327,6 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
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();
|
GUIUtility.CheckOnGUI();
|
||||||
@ -358,7 +347,7 @@ namespace Explorer
|
|||||||
rect2 = new Rect(position.x, position.yMax - rightButton.fixedHeight, position.width, rightButton.fixedHeight);
|
rect2 = new Rect(position.x, position.yMax - rightButton.fixedHeight, position.width, rightButton.fixedHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
value = Slider(position2, value, size, leftValue, rightValue, slider, thumb, horiz, controlID);
|
value = Slider_Impl(position2, value, size, leftValue, rightValue, slider, thumb, horiz, controlID);
|
||||||
|
|
||||||
bool flag = Event.current.type == EventType.MouseUp;
|
bool flag = Event.current.type == EventType.MouseUp;
|
||||||
if (ScrollerRepeatButton_Impl(controlID, rect, leftButton))
|
if (ScrollerRepeatButton_Impl(controlID, rect, leftButton))
|
||||||
@ -384,9 +373,7 @@ namespace Explorer
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual unstrip of GUI.Slider
|
public static float Slider_Impl(Rect position, float value, float size, float start, float end, GUIStyle slider, GUIStyle thumb, bool horiz, int id)
|
||||||
|
|
||||||
public static float Slider(Rect position, float value, float size, float start, float end, GUIStyle slider, GUIStyle thumb, bool horiz, int id)
|
|
||||||
{
|
{
|
||||||
if (id == 0)
|
if (id == 0)
|
||||||
{
|
{
|
||||||
@ -396,8 +383,6 @@ namespace Explorer
|
|||||||
return sliderHandler.Handle();
|
return sliderHandler.Handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual unstrip of GUI.ScrollerRepeatButton
|
|
||||||
|
|
||||||
private static bool ScrollerRepeatButton_Impl(int scrollerID, Rect rect, GUIStyle style)
|
private static bool ScrollerRepeatButton_Impl(int scrollerID, Rect rect, GUIStyle style)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
@ -9,13 +9,6 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
// This is a copy+paste of UnityEngine source code, fixed for Il2Cpp.
|
|
||||||
// Taken from dnSpy output using Unity 2018.4.20.
|
|
||||||
|
|
||||||
// Subject to Unity's License and ToS.
|
|
||||||
// https://unity3d.com/legal/terms-of-service
|
|
||||||
// https://unity3d.com/legal/terms-of-service/software
|
|
||||||
|
|
||||||
public class ScrollViewStateUnstrip
|
public class ScrollViewStateUnstrip
|
||||||
{
|
{
|
||||||
public Rect position;
|
public Rect position;
|
||||||
@ -24,9 +17,6 @@ namespace Explorer
|
|||||||
public Vector2 scrollPosition;
|
public Vector2 scrollPosition;
|
||||||
public bool apply;
|
public bool apply;
|
||||||
|
|
||||||
// The code below is not unstripped.
|
|
||||||
// This is a custom dictionary to allow for the manual implementation.
|
|
||||||
|
|
||||||
public static Dictionary<IntPtr, ScrollViewStateUnstrip> Dict = new Dictionary<IntPtr, ScrollViewStateUnstrip>();
|
public static Dictionary<IntPtr, ScrollViewStateUnstrip> Dict = new Dictionary<IntPtr, ScrollViewStateUnstrip>();
|
||||||
|
|
||||||
public static ScrollViewStateUnstrip FromPointer(IntPtr ptr)
|
public static ScrollViewStateUnstrip FromPointer(IntPtr ptr)
|
@ -8,13 +8,6 @@ using UnhollowerRuntimeLib;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
// This is a copy+paste of UnityEngine source code, fixed for Il2Cpp.
|
|
||||||
// Taken from dnSpy output using Unity 2018.4.20.
|
|
||||||
|
|
||||||
// Subject to Unity's License and ToS.
|
|
||||||
// https://unity3d.com/legal/terms-of-service
|
|
||||||
// https://unity3d.com/legal/terms-of-service/software
|
|
||||||
|
|
||||||
public struct SliderHandlerUnstrip
|
public struct SliderHandlerUnstrip
|
||||||
{
|
{
|
||||||
private readonly Rect position;
|
private readonly Rect position;
|
27
src/UnstripFixes/UnstripExtensions.cs
Normal file
27
src/UnstripFixes/UnstripExtensions.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer
|
||||||
|
{
|
||||||
|
public static class UnstripExtensions
|
||||||
|
{
|
||||||
|
public static Rect GetLastUnstripped(this GUILayoutGroup group)
|
||||||
|
{
|
||||||
|
Rect result;
|
||||||
|
if (group.m_Cursor > 0 && group.m_Cursor <= group.entries.Count)
|
||||||
|
{
|
||||||
|
GUILayoutEntry guilayoutEntry = group.entries[group.m_Cursor - 1];
|
||||||
|
result = guilayoutEntry.rect;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = GUILayoutEntry.kDummyRect;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,51 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Explorer
|
|
||||||
{
|
|
||||||
// This is a copy+paste of UnityEngine source code, fixed for Il2Cpp.
|
|
||||||
// Taken from dnSpy output using Unity 2018.4.20.
|
|
||||||
|
|
||||||
// Subject to Unity's License and ToS.
|
|
||||||
// https://unity3d.com/legal/terms-of-service
|
|
||||||
// https://unity3d.com/legal/terms-of-service/software
|
|
||||||
|
|
||||||
public static class UnstripExtensions
|
|
||||||
{
|
|
||||||
// This is a manual unstrip of GUILayoutGroup.GetLast().
|
|
||||||
// I'm using it as an Extension because it's easier this way.
|
|
||||||
|
|
||||||
public static Rect GetLastUnstripped(this GUILayoutGroup group)
|
|
||||||
{
|
|
||||||
Rect result;
|
|
||||||
if (group.m_Cursor == 0)
|
|
||||||
{
|
|
||||||
Debug.LogError("You cannot call GetLast immediately after beginning a group.");
|
|
||||||
result = GUILayoutEntry.kDummyRect;
|
|
||||||
}
|
|
||||||
else if (group.m_Cursor <= group.entries.Count)
|
|
||||||
{
|
|
||||||
GUILayoutEntry guilayoutEntry = group.entries[group.m_Cursor - 1];
|
|
||||||
result = guilayoutEntry.rect;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError(string.Concat(new object[]
|
|
||||||
{
|
|
||||||
"Getting control ",
|
|
||||||
group.m_Cursor,
|
|
||||||
"'s position in a group with only ",
|
|
||||||
group.entries.Count,
|
|
||||||
" controls when doing ",
|
|
||||||
Event.current.type
|
|
||||||
}));
|
|
||||||
result = GUILayoutEntry.kDummyRect;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -29,9 +29,17 @@ namespace Explorer
|
|||||||
private Vector2 m_compScroll = Vector2.zero;
|
private Vector2 m_compScroll = Vector2.zero;
|
||||||
private PageHelper CompPages = new PageHelper();
|
private PageHelper CompPages = new PageHelper();
|
||||||
|
|
||||||
|
private readonly Vector3[] m_cachedInput = new Vector3[3];
|
||||||
private float m_translateAmount = 0.3f;
|
private float m_translateAmount = 0.3f;
|
||||||
private float m_rotateAmount = 50f;
|
private float m_rotateAmount = 50f;
|
||||||
private float m_scaleAmount = 0.1f;
|
private float m_scaleAmount = 0.1f;
|
||||||
|
private bool m_freeze;
|
||||||
|
private Vector3 m_frozenPosition;
|
||||||
|
private Quaternion m_frozenRotation;
|
||||||
|
private Vector3 m_frozenScale;
|
||||||
|
private bool m_autoApplyTransform;
|
||||||
|
private bool m_autoUpdateTransform;
|
||||||
|
private bool m_localContext;
|
||||||
|
|
||||||
private readonly List<Component> m_cachedDestroyList = new List<Component>();
|
private readonly List<Component> m_cachedDestroyList = new List<Component>();
|
||||||
//private string m_addComponentInput = "";
|
//private string m_addComponentInput = "";
|
||||||
@ -73,12 +81,29 @@ namespace Explorer
|
|||||||
|
|
||||||
m_name = m_object.name;
|
m_name = m_object.name;
|
||||||
m_scene = string.IsNullOrEmpty(m_object.scene.name)
|
m_scene = string.IsNullOrEmpty(m_object.scene.name)
|
||||||
? "None"
|
? "None (Asset/Resource)"
|
||||||
: m_object.scene.name;
|
: m_object.scene.name;
|
||||||
|
|
||||||
|
CacheTransformValues();
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CacheTransformValues()
|
||||||
|
{
|
||||||
|
if (m_localContext)
|
||||||
|
{
|
||||||
|
m_cachedInput[0] = m_object.transform.localPosition;
|
||||||
|
m_cachedInput[1] = m_object.transform.localEulerAngles;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_cachedInput[0] = m_object.transform.position;
|
||||||
|
m_cachedInput[1] = m_object.transform.eulerAngles;
|
||||||
|
}
|
||||||
|
m_cachedInput[2] = m_object.transform.localScale;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -88,28 +113,37 @@ namespace Explorer
|
|||||||
throw new Exception("Object is null!");
|
throw new Exception("Object is null!");
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<Transform>();
|
if (m_freeze)
|
||||||
|
{
|
||||||
|
if (m_localContext)
|
||||||
|
{
|
||||||
|
m_object.transform.localPosition = m_frozenPosition;
|
||||||
|
m_object.transform.localRotation = m_frozenRotation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_object.transform.position = m_frozenPosition;
|
||||||
|
m_object.transform.rotation = m_frozenRotation;
|
||||||
|
}
|
||||||
|
m_object.transform.localScale = m_frozenScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update child objects
|
||||||
|
var childList = new List<Transform>();
|
||||||
for (int i = 0; i < m_object.transform.childCount; i++)
|
for (int i = 0; i < m_object.transform.childCount; i++)
|
||||||
{
|
{
|
||||||
list.Add(m_object.transform.GetChild(i));
|
childList.Add(m_object.transform.GetChild(i));
|
||||||
}
|
}
|
||||||
list.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
childList.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||||
m_children = list.ToArray();
|
m_children = childList.ToArray();
|
||||||
|
|
||||||
ChildPages.ItemCount = m_children.Length;
|
ChildPages.ItemCount = m_children.Length;
|
||||||
|
|
||||||
var list2 = new List<Component>();
|
// update components
|
||||||
foreach (var comp in m_object.GetComponents(ReflectionHelpers.ComponentType))
|
var compList = new Il2CppSystem.Collections.Generic.List<Component>();
|
||||||
{
|
m_object.GetComponentsInternal(ReflectionHelpers.ComponentType, true, false, true, false, compList);
|
||||||
var ilType = comp.GetIl2CppType();
|
|
||||||
if (ilType == ReflectionHelpers.TransformType)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
list2.Add(comp);
|
m_components = compList.ToArray();
|
||||||
}
|
|
||||||
m_components = list2.ToArray();
|
|
||||||
|
|
||||||
CompPages.ItemCount = m_components.Length;
|
CompPages.ItemCount = m_components.Length;
|
||||||
}
|
}
|
||||||
@ -412,6 +446,16 @@ namespace Explorer
|
|||||||
m_object.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
m_object.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lbl = m_freeze ? "<color=lime>Unfreeze</color>" : "<color=orange>Freeze Pos/Rot</color>";
|
||||||
|
if (GUILayout.Button(lbl, new GUILayoutOption[] { GUILayout.Width(110) }))
|
||||||
|
{
|
||||||
|
m_freeze = !m_freeze;
|
||||||
|
if (m_freeze)
|
||||||
|
{
|
||||||
|
UpdateFreeze();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
@ -436,10 +480,52 @@ namespace Explorer
|
|||||||
|
|
||||||
GUILayout.BeginVertical(GUI.skin.box, null);
|
GUILayout.BeginVertical(GUI.skin.box, null);
|
||||||
|
|
||||||
var t = m_object.transform;
|
m_cachedInput[0] = TranslateControl(TranslateType.Position, ref m_translateAmount, false);
|
||||||
TranslateControl(t, TranslateType.Position, ref m_translateAmount, false);
|
m_cachedInput[1] = TranslateControl(TranslateType.Rotation, ref m_rotateAmount, true);
|
||||||
TranslateControl(t, TranslateType.Rotation, ref m_rotateAmount, true);
|
m_cachedInput[2] = TranslateControl(TranslateType.Scale, ref m_scaleAmount, false);
|
||||||
TranslateControl(t, TranslateType.Scale, ref m_scaleAmount, false);
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
if (GUILayout.Button("<color=lime>Apply to Transform</color>", null) || m_autoApplyTransform)
|
||||||
|
{
|
||||||
|
if (m_localContext)
|
||||||
|
{
|
||||||
|
m_object.transform.localPosition = m_cachedInput[0];
|
||||||
|
m_object.transform.localEulerAngles = m_cachedInput[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_object.transform.position = m_cachedInput[0];
|
||||||
|
m_object.transform.eulerAngles = m_cachedInput[1];
|
||||||
|
}
|
||||||
|
m_object.transform.localScale = m_cachedInput[2];
|
||||||
|
|
||||||
|
if (m_freeze)
|
||||||
|
{
|
||||||
|
UpdateFreeze();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GUILayout.Button("<color=lime>Update from Transform</color>", null) || m_autoUpdateTransform)
|
||||||
|
{
|
||||||
|
CacheTransformValues();
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
BoolToggle(ref m_autoApplyTransform, "Auto-apply to Transform?");
|
||||||
|
BoolToggle(ref m_autoUpdateTransform, "Auto-update from transform?");
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
bool b = m_localContext;
|
||||||
|
b = GUILayout.Toggle(b, "<color=" + (b ? "lime" : "red") + ">Use local transform values?</color>", null);
|
||||||
|
if (b != m_localContext)
|
||||||
|
{
|
||||||
|
m_localContext = b;
|
||||||
|
CacheTransformValues();
|
||||||
|
if (m_freeze)
|
||||||
|
{
|
||||||
|
UpdateFreeze();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
|
|
||||||
@ -453,6 +539,30 @@ namespace Explorer
|
|||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateFreeze()
|
||||||
|
{
|
||||||
|
if (m_localContext)
|
||||||
|
{
|
||||||
|
m_frozenPosition = m_object.transform.localPosition;
|
||||||
|
m_frozenRotation = m_object.transform.localRotation;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_frozenPosition = m_object.transform.position;
|
||||||
|
m_frozenRotation = m_object.transform.rotation;
|
||||||
|
}
|
||||||
|
m_frozenScale = m_object.transform.localScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BoolToggle(ref bool value, string message)
|
||||||
|
{
|
||||||
|
string lbl = "<color=";
|
||||||
|
lbl += value ? "lime" : "red";
|
||||||
|
lbl += $">{message}</color>";
|
||||||
|
|
||||||
|
value = GUILayout.Toggle(value, lbl, null);
|
||||||
|
}
|
||||||
|
|
||||||
public enum TranslateType
|
public enum TranslateType
|
||||||
{
|
{
|
||||||
Position,
|
Position,
|
||||||
@ -460,50 +570,55 @@ namespace Explorer
|
|||||||
Scale
|
Scale
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TranslateControl(Transform transform, TranslateType mode, ref float amount, bool multByTime)
|
private Vector3 TranslateControl(TranslateType mode, ref float amount, bool multByTime)
|
||||||
{
|
{
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Label("<color=cyan><b>" + mode + "</b></color>:", new GUILayoutOption[] { GUILayout.Width(65) });
|
GUILayout.Label($"<color=cyan><b>{(m_localContext ? "Local " : "")}{mode}</b></color>:",
|
||||||
|
new GUILayoutOption[] { GUILayout.Width(m_localContext ? 110 : 65) });
|
||||||
|
|
||||||
Vector3 vector = Vector3.zero;
|
var transform = m_object.transform;
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case TranslateType.Position: vector = transform.localPosition; break;
|
case TranslateType.Position:
|
||||||
case TranslateType.Rotation: vector = transform.localRotation.eulerAngles; break;
|
var pos = m_localContext ? transform.localPosition : transform.position;
|
||||||
case TranslateType.Scale: vector = transform.localScale; break;
|
GUILayout.Label(pos.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||||
|
break;
|
||||||
|
case TranslateType.Rotation:
|
||||||
|
var rot = m_localContext ? transform.localEulerAngles : transform.eulerAngles;
|
||||||
|
GUILayout.Label(rot.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||||
|
break;
|
||||||
|
case TranslateType.Scale:
|
||||||
|
GUILayout.Label(transform.localScale.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
GUILayout.Label(vector.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
Vector3 input = m_cachedInput[(int)mode];
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||||
|
|
||||||
GUILayout.Label("<color=cyan>X:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
GUILayout.Label("<color=cyan>X:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||||
PlusMinusFloat(ref vector.x, amount, multByTime);
|
PlusMinusFloat(ref input.x, amount, multByTime);
|
||||||
|
|
||||||
GUILayout.Label("<color=cyan>Y:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
GUILayout.Label("<color=cyan>Y:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||||
PlusMinusFloat(ref vector.y, amount, multByTime);
|
PlusMinusFloat(ref input.y, amount, multByTime);
|
||||||
|
|
||||||
GUILayout.Label("<color=cyan>Z:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
GUILayout.Label("<color=cyan>Z:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||||
PlusMinusFloat(ref vector.z, amount, multByTime);
|
PlusMinusFloat(ref input.z, amount, multByTime);
|
||||||
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case TranslateType.Position: transform.localPosition = vector; break;
|
|
||||||
case TranslateType.Rotation: transform.localRotation = Quaternion.Euler(vector); break;
|
|
||||||
case TranslateType.Scale: transform.localScale = vector; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.Label("+/-:", new GUILayoutOption[] { GUILayout.Width(30) });
|
GUILayout.Label("+/-:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
var input = amount.ToString("F3");
|
var amountInput = amount.ToString("F3");
|
||||||
input = GUILayout.TextField(input, new GUILayoutOption[] { GUILayout.Width(40) });
|
amountInput = GUILayout.TextField(amountInput, new GUILayoutOption[] { GUILayout.Width(60) });
|
||||||
if (float.TryParse(input, out float f))
|
if (float.TryParse(amountInput, out float f))
|
||||||
{
|
{
|
||||||
amount = f;
|
amount = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PlusMinusFloat(ref float f, float amount, bool multByTime)
|
private void PlusMinusFloat(ref float f, float amount, bool multByTime)
|
||||||
@ -523,7 +638,5 @@ namespace Explorer
|
|||||||
f += multByTime ? amount * Time.deltaTime : amount;
|
f += multByTime ? amount * Time.deltaTime : amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void Init() { }
|
public override void Init() { }
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
while (TargetTabID >= WindowManager.Windows.Count)
|
while (TargetTabID >= WindowManager.Windows.Count)
|
||||||
|
@ -109,7 +109,7 @@ namespace Explorer
|
|||||||
|
|
||||||
if (!equals && iObj is Il2CppSystem.Object iCurrent && window.Target is Il2CppSystem.Object iTarget)
|
if (!equals && iObj is Il2CppSystem.Object iCurrent && window.Target is Il2CppSystem.Object iTarget)
|
||||||
{
|
{
|
||||||
if (iCurrent.GetIl2CppType() != iTarget.GetIl2CppType())
|
if (iCurrent.GetIl2CppType().FullName != iTarget.GetIl2CppType().FullName)
|
||||||
{
|
{
|
||||||
if (iCurrent is Transform transform)
|
if (iCurrent is Transform transform)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user