mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-13 15:26:36 +08:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
6ea435deee | |||
94f749342d | |||
0769b7ef23 | |||
5086dcc82b | |||
56abd38e92 | |||
a7e6ae87df | |||
b5c584bb02 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@
|
|||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
*.sln.docstates
|
*.sln.docstates
|
||||||
|
*/mcs-unity*
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
14
README.md
14
README.md
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
### Known issues
|
### Known issues
|
||||||
* CppExplorer may experience a `MissingMethodException` when trying to use certain UnityEngine methods. If you experience this, please open an issue and I will do my best to fix it.
|
* 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.
|
||||||
|
* Reflection may fail with certain types (eg. `Nullable<T>`, some Dictionary types, etc). Please see [Il2CppAssemblyUnhollower](https://github.com/knah/Il2CppAssemblyUnhollower#known-issues) for more details.
|
||||||
* Scrolling with mouse wheel in the CppExplorer menu may not work on all games at the moment.
|
* Scrolling with mouse wheel in the CppExplorer menu may not work on all games at the moment.
|
||||||
|
|
||||||
## How to install
|
## How to install
|
||||||
@ -91,10 +92,21 @@ CppExplorer can force the mouse to be visible and unlocked when the menu is open
|
|||||||
* For Hellpoint, use [HPExplorerMouseControl](https://github.com/sinai-dev/Hellpoint-Mods/tree/master/HPExplorerMouseControl/HPExplorerMouseControl)
|
* For Hellpoint, use [HPExplorerMouseControl](https://github.com/sinai-dev/Hellpoint-Mods/tree/master/HPExplorerMouseControl/HPExplorerMouseControl)
|
||||||
* You can create your own plugin using one of the two plugins above as an example. Usually only a few simple Harmony patches are needed to fix the problem.
|
* You can create your own plugin using one of the two plugins above as an example. Usually only a few simple Harmony patches are needed to fix the problem.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
If you'd like to build this yourself, everything you need (other than MelonLoader) is included with this repository, there is no need for recursive cloning etc.
|
||||||
|
|
||||||
|
1. Install MelonLoader for your game.
|
||||||
|
2. Open the `src\CppExplorer.csproj` file in a text editor.
|
||||||
|
3. Scroll down until you see the `<ItemGroup>` containing the References.
|
||||||
|
4. Fix all of the paths in the `..\Steam\` directory for your game (use the full path if you need to).
|
||||||
|
5. Open the `src\CppExplorer.sln` project and build it.
|
||||||
|
6. The dll is built to the `Release\` folder in the root of the repository.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
Written by Sinai.
|
Written by Sinai.
|
||||||
|
|
||||||
Thanks to:
|
Thanks to:
|
||||||
* [ManlyMarco](https://github.com/ManlyMarco) for their [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor), which I used for the REPL Console and the "Find instances" snippet, and the UI style.
|
* [ManlyMarco](https://github.com/ManlyMarco) for their [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor), which I used for the REPL Console and the "Find instances" snippet, and the UI style.
|
||||||
* [denikson](https://github.com/denikson) for [mcs-unity](https://github.com/denikson/mcs-unity). I commented out the `SkipVisibilityExt` constructor in `mcs.dll` since it was causing an exception with the Hook it attempted.
|
* [denikson](https://github.com/denikson) for [mcs-unity](https://github.com/denikson/mcs-unity). I commented out the `SkipVisibilityExt` constructor since it was causing an exception with the Hook it attempted.
|
||||||
|
BIN
img.png
BIN
img.png
Binary file not shown.
Before Width: | Height: | Size: 449 KiB After Width: | Height: | Size: 524 KiB |
@ -19,8 +19,12 @@ namespace Explorer
|
|||||||
public MemberInfo MemInfo { get; set; }
|
public MemberInfo MemInfo { get; set; }
|
||||||
public Type DeclaringType { get; set; }
|
public Type DeclaringType { get; set; }
|
||||||
public object DeclaringInstance { get; set; }
|
public object DeclaringInstance { get; set; }
|
||||||
public int PropertyIndex { get; private set; }
|
|
||||||
private string m_propertyIndexInput = "0";
|
public bool HasParameters => m_arguments != null && m_arguments.Length > 0;
|
||||||
|
public bool m_evaluated = false;
|
||||||
|
public bool m_isEvaluating;
|
||||||
|
public ParameterInfo[] m_arguments = new ParameterInfo[0];
|
||||||
|
public string[] m_argumentInput = new string[0];
|
||||||
|
|
||||||
public string ReflectionException { get; set; }
|
public string ReflectionException { get; set; }
|
||||||
|
|
||||||
@ -43,7 +47,6 @@ namespace Explorer
|
|||||||
// ===== Abstract/Virtual Methods ===== //
|
// ===== Abstract/Virtual Methods ===== //
|
||||||
|
|
||||||
public virtual void Init() { }
|
public virtual void Init() { }
|
||||||
|
|
||||||
public abstract void DrawValue(Rect window, float width);
|
public abstract void DrawValue(Rect window, float width);
|
||||||
|
|
||||||
// ===== Static Methods ===== //
|
// ===== Static Methods ===== //
|
||||||
@ -114,12 +117,21 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
CacheObjectBase holder;
|
CacheObjectBase holder;
|
||||||
|
|
||||||
|
var pi = memberInfo as PropertyInfo;
|
||||||
|
var mi = memberInfo as MethodInfo;
|
||||||
|
|
||||||
|
// if PropertyInfo, check if can process args
|
||||||
|
if (pi != null && !CanProcessArgs(pi.GetIndexParameters()))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// This is pretty ugly, could probably make a cleaner implementation.
|
// 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.
|
// However, the only cleaner ways I can think of are slower and probably not worth it.
|
||||||
|
|
||||||
// Note: the order is somewhat important.
|
// Note: the order is somewhat important.
|
||||||
|
|
||||||
if (memberInfo is MethodInfo mi)
|
if (mi != null)
|
||||||
{
|
{
|
||||||
if (CacheMethod.CanEvaluate(mi))
|
if (CacheMethod.CanEvaluate(mi))
|
||||||
{
|
{
|
||||||
@ -181,7 +193,21 @@ namespace Explorer
|
|||||||
holder.MemInfo = memberInfo;
|
holder.MemInfo = memberInfo;
|
||||||
holder.DeclaringType = memberInfo.DeclaringType;
|
holder.DeclaringType = memberInfo.DeclaringType;
|
||||||
holder.DeclaringInstance = declaringInstance;
|
holder.DeclaringInstance = declaringInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pi != null)
|
||||||
|
{
|
||||||
|
holder.m_arguments = pi.GetIndexParameters();
|
||||||
|
}
|
||||||
|
else if (mi != null)
|
||||||
|
{
|
||||||
|
holder.m_arguments = mi.GetParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.m_argumentInput = new string[holder.m_arguments.Length];
|
||||||
|
|
||||||
|
if (!holder.HasParameters)
|
||||||
|
{
|
||||||
holder.UpdateValue();
|
holder.UpdateValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,11 +216,57 @@ namespace Explorer
|
|||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool CanProcessArgs(ParameterInfo[] parameters)
|
||||||
|
{
|
||||||
|
foreach (var param in parameters)
|
||||||
|
{
|
||||||
|
if (!param.ParameterType.IsPrimitive && param.ParameterType != typeof(string))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// ======== Instance Methods =========
|
// ======== Instance Methods =========
|
||||||
|
|
||||||
|
public object[] ParseArguments()
|
||||||
|
{
|
||||||
|
var parsedArgs = new List<object>();
|
||||||
|
for (int i = 0; i < m_arguments.Length; i++)
|
||||||
|
{
|
||||||
|
var input = m_argumentInput[i];
|
||||||
|
var type = m_arguments[i].ParameterType;
|
||||||
|
|
||||||
|
if (type == typeof(string))
|
||||||
|
{
|
||||||
|
parsedArgs.Add(input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parsedArgs.Add(type.GetMethod("Parse", new Type[] { typeof(string) }).Invoke(null, new object[] { input }));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//MelonLogger.Log($"Unable to parse '{input}' to type '{type.Name}'");
|
||||||
|
|
||||||
|
// try add a null arg i guess
|
||||||
|
parsedArgs.Add(null);
|
||||||
|
|
||||||
|
//break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedArgs.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void UpdateValue()
|
public virtual void UpdateValue()
|
||||||
{
|
{
|
||||||
if (MemInfo == null || !string.IsNullOrEmpty(ReflectionException))
|
if (MemInfo == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -209,13 +281,11 @@ namespace Explorer
|
|||||||
else if (MemInfo.MemberType == MemberTypes.Property)
|
else if (MemInfo.MemberType == MemberTypes.Property)
|
||||||
{
|
{
|
||||||
var pi = MemInfo as PropertyInfo;
|
var pi = MemInfo as PropertyInfo;
|
||||||
bool isStatic = pi.GetAccessors()[0].IsStatic;
|
var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance;
|
||||||
var target = isStatic ? null : DeclaringInstance;
|
|
||||||
|
|
||||||
if (pi.GetIndexParameters().Length > 0)
|
if (HasParameters)
|
||||||
{
|
{
|
||||||
var indexes = new object[] { PropertyIndex };
|
Value = pi.GetValue(target, ParseArguments());
|
||||||
Value = pi.GetValue(target, indexes);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -224,6 +294,8 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReflectionException = null;
|
ReflectionException = null;
|
||||||
|
m_evaluated = true;
|
||||||
|
m_isEvaluating = false;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -244,10 +316,9 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
var pi = MemInfo as PropertyInfo;
|
var pi = MemInfo as PropertyInfo;
|
||||||
|
|
||||||
if (pi.GetIndexParameters().Length > 0)
|
if (HasParameters)
|
||||||
{
|
{
|
||||||
var indexes = new object[] { PropertyIndex };
|
pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value, ParseArguments());
|
||||||
pi.SetValue(pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance, Value, indexes);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -264,6 +335,7 @@ namespace Explorer
|
|||||||
// ========= Instance Gui Draw ==========
|
// ========= Instance Gui Draw ==========
|
||||||
|
|
||||||
public const float MAX_LABEL_WIDTH = 400f;
|
public const float MAX_LABEL_WIDTH = 400f;
|
||||||
|
public const string EVALUATE_LABEL = "<color=lime>Evaluate</color>";
|
||||||
|
|
||||||
public static void ClampLabelWidth(Rect window, ref float labelWidth)
|
public static void ClampLabelWidth(Rect window, ref float labelWidth)
|
||||||
{
|
{
|
||||||
@ -282,19 +354,86 @@ namespace Explorer
|
|||||||
|
|
||||||
if (MemInfo != null)
|
if (MemInfo != null)
|
||||||
{
|
{
|
||||||
var name = RichTextName;
|
GUILayout.Label(RichTextName, new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||||
if (MemInfo is PropertyInfo pi && pi.GetIndexParameters().Length > 0)
|
|
||||||
{
|
|
||||||
name += $"[{PropertyIndex}]";
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.Label(name, new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Space(labelWidth);
|
GUILayout.Space(labelWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cm = this as CacheMethod;
|
||||||
|
|
||||||
|
if (HasParameters)
|
||||||
|
{
|
||||||
|
GUILayout.BeginVertical(null);
|
||||||
|
|
||||||
|
if (m_isEvaluating)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_arguments.Length; i++)
|
||||||
|
{
|
||||||
|
var name = m_arguments[i].Name;
|
||||||
|
var input = m_argumentInput[i];
|
||||||
|
var type = m_arguments[i].ParameterType.Name;
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Label(i.ToString(), new GUILayoutOption[] { GUILayout.Width(30) });
|
||||||
|
m_argumentInput[i] = GUILayout.TextField(input, new GUILayoutOption[] { GUILayout.Width(150) });
|
||||||
|
GUILayout.Label("<color=#2df7b2>" + type + "</color> <color=cyan>" + name + "</color>", null);
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
if (cm != null)
|
||||||
|
{
|
||||||
|
if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) }))
|
||||||
|
{
|
||||||
|
cm.Evaluate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) }))
|
||||||
|
{
|
||||||
|
UpdateValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Cancel", new GUILayoutOption[] { GUILayout.Width(70) }))
|
||||||
|
{
|
||||||
|
m_isEvaluating = false;
|
||||||
|
}
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GUILayout.Button($"Evaluate ({m_arguments.Length} params)", new GUILayoutOption[] { GUILayout.Width(150) }))
|
||||||
|
{
|
||||||
|
m_isEvaluating = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.EndVertical();
|
||||||
|
|
||||||
|
// new line and space
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(labelWidth);
|
||||||
|
}
|
||||||
|
else if (cm != null)
|
||||||
|
{
|
||||||
|
//GUILayout.BeginHorizontal(null);
|
||||||
|
|
||||||
|
if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) }))
|
||||||
|
{
|
||||||
|
cm.Evaluate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// new line and space
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
GUILayout.BeginHorizontal(null);
|
||||||
|
GUILayout.Space(labelWidth);
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(ReflectionException))
|
if (!string.IsNullOrEmpty(ReflectionException))
|
||||||
{
|
{
|
||||||
GUILayout.Label("<color=red>Reflection failed!</color> (" + ReflectionException + ")", null);
|
GUILayout.Label("<color=red>Reflection failed!</color> (" + ReflectionException + ")", null);
|
||||||
@ -305,30 +444,6 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (MemInfo is PropertyInfo pi && pi.GetIndexParameters().Length > 0)
|
|
||||||
{
|
|
||||||
GUILayout.Label("index:", new GUILayoutOption[] { GUILayout.Width(50) });
|
|
||||||
|
|
||||||
m_propertyIndexInput = GUILayout.TextField(m_propertyIndexInput, new GUILayoutOption[] { GUILayout.Width(100) });
|
|
||||||
if (GUILayout.Button("Set", new GUILayoutOption[] { GUILayout.Width(60) }))
|
|
||||||
{
|
|
||||||
if (int.TryParse(m_propertyIndexInput, out int i))
|
|
||||||
{
|
|
||||||
PropertyIndex = i;
|
|
||||||
UpdateValue();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MelonLogger.Log($"Could not parse '{m_propertyIndexInput}' to an int!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// new line and space
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
GUILayout.BeginHorizontal(null);
|
|
||||||
GUILayout.Space(labelWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawValue(window, window.width - labelWidth - 90);
|
DrawValue(window, window.width - labelWidth - 90);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -348,15 +463,15 @@ namespace Explorer
|
|||||||
|
|
||||||
m_richTextName = $"<color=#2df7b2>{MemInfo.DeclaringType.Name}</color>.<color={memberColor}>{MemInfo.Name}</color>";
|
m_richTextName = $"<color=#2df7b2>{MemInfo.DeclaringType.Name}</color>.<color={memberColor}>{MemInfo.Name}</color>";
|
||||||
|
|
||||||
if (MemInfo is MethodInfo mi)
|
if (m_arguments.Length > 0)
|
||||||
{
|
{
|
||||||
m_richTextName += "(";
|
m_richTextName += "(";
|
||||||
var _params = "";
|
var _params = "";
|
||||||
foreach (var param in mi.GetParameters())
|
foreach (var param in m_arguments)
|
||||||
{
|
{
|
||||||
if (_params != "") _params += ", ";
|
if (_params != "") _params += ", ";
|
||||||
|
|
||||||
_params += $"<color=#a6e9e9>{param.Name}</color>";
|
_params += $"<color=#2df7b2>{param.ParameterType.Name}</color> <color=#a6e9e9>{param.Name}</color>";
|
||||||
}
|
}
|
||||||
m_richTextName += _params;
|
m_richTextName += _params;
|
||||||
m_richTextName += ")";
|
m_richTextName += ")";
|
||||||
|
@ -15,7 +15,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public bool IsExpanded { get; set; }
|
public bool IsExpanded { get; set; }
|
||||||
public float WhiteSpace { get; set; } = 215f;
|
public float WhiteSpace { get; set; } = 215f;
|
||||||
public float ButtonWidthOffset { get; set; } = 290f;
|
public float ButtonWidthOffset { get; set; } = 350f;
|
||||||
|
|
||||||
public PageHelper Pages = new PageHelper();
|
public PageHelper Pages = new PageHelper();
|
||||||
|
|
||||||
@ -152,7 +152,6 @@ namespace Explorer
|
|||||||
foreach (var key in IDict.Keys)
|
foreach (var key in IDict.Keys)
|
||||||
{
|
{
|
||||||
var cache = GetCacheObject(key, TypeOfKeys);
|
var cache = GetCacheObject(key, TypeOfKeys);
|
||||||
cache.UpdateValue();
|
|
||||||
keys.Add(cache);
|
keys.Add(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +159,6 @@ namespace Explorer
|
|||||||
foreach (var val in IDict.Values)
|
foreach (var val in IDict.Values)
|
||||||
{
|
{
|
||||||
var cache = GetCacheObject(val, TypeOfValues);
|
var cache = GetCacheObject(val, TypeOfValues);
|
||||||
cache.UpdateValue();
|
|
||||||
values.Add(cache);
|
values.Add(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,6 +168,11 @@ namespace Explorer
|
|||||||
|
|
||||||
private bool EnsureDictionaryIsSupported()
|
private bool EnsureDictionaryIsSupported()
|
||||||
{
|
{
|
||||||
|
if (typeof(IDictionary).IsAssignableFrom(ValueType))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return Check(TypeOfKeys) && Check(TypeOfValues);
|
return Check(TypeOfKeys) && Check(TypeOfValues);
|
||||||
@ -200,6 +203,12 @@ namespace Explorer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float whitespace = WhiteSpace;
|
||||||
|
if (whitespace > 0)
|
||||||
|
{
|
||||||
|
ClampLabelWidth(window, ref whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
int count = m_cachedKeys.Length;
|
int count = m_cachedKeys.Length;
|
||||||
|
|
||||||
if (!IsExpanded)
|
if (!IsExpanded)
|
||||||
@ -217,9 +226,11 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var negativeWhitespace = window.width - (whitespace + 100f);
|
||||||
|
|
||||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||||
string btnLabel = $"<color=yellow>[{count}] Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
|
string btnLabel = $"<color=#2df7b2>[{count}] Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
|
||||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - ButtonWidthOffset) }))
|
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.Width(negativeWhitespace) }))
|
||||||
{
|
{
|
||||||
WindowManager.InspectObject(Value, out bool _);
|
WindowManager.InspectObject(Value, out bool _);
|
||||||
}
|
}
|
||||||
@ -229,12 +240,6 @@ namespace Explorer
|
|||||||
|
|
||||||
if (IsExpanded)
|
if (IsExpanded)
|
||||||
{
|
{
|
||||||
float whitespace = WhiteSpace;
|
|
||||||
if (whitespace > 0)
|
|
||||||
{
|
|
||||||
ClampLabelWidth(window, ref whitespace);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pages.ItemCount = count;
|
Pages.ItemCount = count;
|
||||||
|
|
||||||
if (count > Pages.ItemsPerPage)
|
if (count > Pages.ItemsPerPage)
|
||||||
|
@ -219,7 +219,6 @@ 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
|
||||||
@ -246,6 +245,12 @@ namespace Explorer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float whitespace = WhiteSpace;
|
||||||
|
if (whitespace > 0)
|
||||||
|
{
|
||||||
|
ClampLabelWidth(window, ref whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
int count = m_cachedEntries.Length;
|
int count = m_cachedEntries.Length;
|
||||||
|
|
||||||
if (!IsExpanded)
|
if (!IsExpanded)
|
||||||
@ -263,9 +268,11 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var negativeWhitespace = window.width - (whitespace + 100f);
|
||||||
|
|
||||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||||
string btnLabel = "<color=yellow>[" + count + "] " + EntryType.FullName + "</color>";
|
string btnLabel = $"[{count}] <color=#2df7b2>{EntryType.FullName}</color>";
|
||||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(window.width - ButtonWidthOffset) }))
|
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.MaxWidth(negativeWhitespace) }))
|
||||||
{
|
{
|
||||||
WindowManager.InspectObject(Value, out bool _);
|
WindowManager.InspectObject(Value, out bool _);
|
||||||
}
|
}
|
||||||
@ -275,12 +282,6 @@ namespace Explorer
|
|||||||
|
|
||||||
if (IsExpanded)
|
if (IsExpanded)
|
||||||
{
|
{
|
||||||
float whitespace = WhiteSpace;
|
|
||||||
if (whitespace > 0)
|
|
||||||
{
|
|
||||||
ClampLabelWidth(window, ref whitespace);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pages.ItemCount = count;
|
Pages.ItemCount = count;
|
||||||
|
|
||||||
if (count > Pages.ItemsPerPage)
|
if (count > Pages.ItemsPerPage)
|
||||||
|
@ -11,15 +11,8 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
public class CacheMethod : CacheObjectBase
|
public class CacheMethod : CacheObjectBase
|
||||||
{
|
{
|
||||||
private bool m_evaluated = false;
|
|
||||||
private CacheObjectBase m_cachedReturnValue;
|
private CacheObjectBase m_cachedReturnValue;
|
||||||
|
|
||||||
private bool m_isEvaluating;
|
|
||||||
private ParameterInfo[] m_arguments;
|
|
||||||
private string[] m_argumentInput;
|
|
||||||
|
|
||||||
public bool HasParameters => m_arguments != null && m_arguments.Length > 0;
|
|
||||||
|
|
||||||
public static bool CanEvaluate(MethodInfo mi)
|
public static bool CanEvaluate(MethodInfo mi)
|
||||||
{
|
{
|
||||||
// TODO generic args
|
// TODO generic args
|
||||||
@ -29,25 +22,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// primitive and string args supported
|
// primitive and string args supported
|
||||||
foreach (var param in mi.GetParameters())
|
return CanProcessArgs(mi.GetParameters());
|
||||||
{
|
|
||||||
if (!param.ParameterType.IsPrimitive && param.ParameterType != typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Init()
|
|
||||||
{
|
|
||||||
base.Init();
|
|
||||||
|
|
||||||
var mi = MemInfo as MethodInfo;
|
|
||||||
|
|
||||||
m_arguments = mi.GetParameters();
|
|
||||||
m_argumentInput = new string[m_arguments.Length];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateValue()
|
public override void UpdateValue()
|
||||||
@ -55,10 +30,11 @@ namespace Explorer
|
|||||||
//base.UpdateValue();
|
//base.UpdateValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Evaluate()
|
public void Evaluate()
|
||||||
{
|
{
|
||||||
var mi = MemInfo as MethodInfo;
|
m_isEvaluating = false;
|
||||||
|
|
||||||
|
var mi = MemInfo as MethodInfo;
|
||||||
object ret = null;
|
object ret = null;
|
||||||
|
|
||||||
if (!HasParameters)
|
if (!HasParameters)
|
||||||
@ -68,38 +44,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var parsedArgs = new List<object>();
|
var parsedArgs = ParseArguments();
|
||||||
for (int i = 0; i < m_arguments.Length; i++)
|
|
||||||
{
|
|
||||||
var input = m_argumentInput[i];
|
|
||||||
var type = m_arguments[i].ParameterType;
|
|
||||||
|
|
||||||
if (type == typeof(string))
|
|
||||||
{
|
|
||||||
parsedArgs.Add(input);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (type.GetMethod("Parse", new Type[] { typeof(string) }).Invoke(null, new object[] { input }) is object parsed)
|
|
||||||
{
|
|
||||||
parsedArgs.Add(parsed);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// try add a null arg i guess
|
|
||||||
parsedArgs.Add(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
MelonLogger.Log($"Unable to parse '{input}' to type '{type.Name}'");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -115,13 +60,6 @@ namespace Explorer
|
|||||||
if (ret != null)
|
if (ret != null)
|
||||||
{
|
{
|
||||||
m_cachedReturnValue = GetCacheObject(ret);
|
m_cachedReturnValue = GetCacheObject(ret);
|
||||||
|
|
||||||
if (m_cachedReturnValue is IExpandHeight expander)
|
|
||||||
{
|
|
||||||
expander.WhiteSpace = 0f;
|
|
||||||
expander.ButtonWidthOffset += 70f;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_cachedReturnValue.UpdateValue();
|
m_cachedReturnValue.UpdateValue();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -134,58 +72,6 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
GUILayout.BeginVertical(null);
|
|
||||||
|
|
||||||
string evaluateLabel = "<color=lime>Evaluate</color>";
|
|
||||||
if (HasParameters)
|
|
||||||
{
|
|
||||||
if (m_isEvaluating)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < m_arguments.Length; i++)
|
|
||||||
{
|
|
||||||
var name = m_arguments[i].Name;
|
|
||||||
var input = m_argumentInput[i];
|
|
||||||
var type = m_arguments[i].ParameterType.Name;
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
|
||||||
m_argumentInput[i] = GUILayout.TextField(input, new GUILayoutOption[] { GUILayout.Width(150) });
|
|
||||||
GUILayout.Label(i + ": <color=cyan>" + name + "</color> <color=yellow>(" + type + ")</color>", null);
|
|
||||||
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
|
||||||
if (GUILayout.Button(evaluateLabel, new GUILayoutOption[] { GUILayout.Width(70) }))
|
|
||||||
{
|
|
||||||
Evaluate();
|
|
||||||
m_isEvaluating = false;
|
|
||||||
}
|
|
||||||
if (GUILayout.Button("Cancel", new GUILayoutOption[] { GUILayout.Width(70) }))
|
|
||||||
{
|
|
||||||
m_isEvaluating = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GUILayout.BeginHorizontal(null);
|
|
||||||
if (GUILayout.Button($"Evaluate ({m_arguments.Length} params)", new GUILayoutOption[] { GUILayout.Width(150) }))
|
|
||||||
{
|
|
||||||
m_isEvaluating = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GUILayout.BeginHorizontal(null);
|
|
||||||
if (GUILayout.Button(evaluateLabel, new GUILayoutOption[] { GUILayout.Width(70) }))
|
|
||||||
{
|
|
||||||
Evaluate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
|
||||||
if (m_evaluated)
|
if (m_evaluated)
|
||||||
{
|
{
|
||||||
if (m_cachedReturnValue != null)
|
if (m_cachedReturnValue != null)
|
||||||
@ -194,16 +80,13 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Label($"null (<color=yellow>{ValueTypeName}</color>)", null);
|
GUILayout.Label($"null (<color=#2df7b2>{ValueTypeName}</color>)", null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUILayout.Label($"<color=grey><i>Not yet evaluated</i></color> (<color=yellow>{ValueTypeName}</color>)", null);
|
GUILayout.Label($"<color=grey><i>Not yet evaluated</i></color> (<color=#2df7b2>{ValueTypeName}</color>)", null);
|
||||||
}
|
}
|
||||||
GUILayout.EndHorizontal();
|
|
||||||
|
|
||||||
GUILayout.EndVertical();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,15 +42,20 @@ namespace Explorer
|
|||||||
|
|
||||||
if (!label.Contains(ValueTypeName))
|
if (!label.Contains(ValueTypeName))
|
||||||
{
|
{
|
||||||
label += $" ({ValueTypeName})";
|
label += $" (<color=#2df7b2>{ValueTypeName}</color>)";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
label = label.Replace(ValueTypeName, $"<color=#2df7b2>{ValueTypeName}</color>");
|
||||||
|
}
|
||||||
|
|
||||||
if (Value is UnityEngine.Object unityObj && !label.Contains(unityObj.name))
|
if (Value is UnityEngine.Object unityObj && !label.Contains(unityObj.name))
|
||||||
{
|
{
|
||||||
label = unityObj.name + " | " + label;
|
label = unityObj.name + " | " + label;
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||||
if (GUILayout.Button("<color=yellow>" + label + "</color>", new GUILayoutOption[] { GUILayout.Width(width - 15) }))
|
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(width - 15) }))
|
||||||
{
|
{
|
||||||
WindowManager.InspectObject(Value, out bool _);
|
WindowManager.InspectObject(Value, out bool _);
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,17 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CacheColor : CacheObjectBase
|
public class CacheColor : CacheObjectBase, IExpandHeight
|
||||||
{
|
{
|
||||||
private string r = "0";
|
private string r = "0";
|
||||||
private string g = "0";
|
private string g = "0";
|
||||||
private string b = "0";
|
private string b = "0";
|
||||||
private string a = "0";
|
private string a = "0";
|
||||||
|
|
||||||
|
public bool IsExpanded { get; set; }
|
||||||
|
public float WhiteSpace { get; set; } = 215f;
|
||||||
|
public float ButtonWidthOffset { get; set; } = 290f;
|
||||||
|
|
||||||
public override void UpdateValue()
|
public override void UpdateValue()
|
||||||
{
|
{
|
||||||
base.UpdateValue();
|
base.UpdateValue();
|
||||||
@ -28,12 +32,38 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
GUILayout.Label($"<color=yellow>Color</color>: {((Color)Value).ToString()}", null);
|
|
||||||
|
|
||||||
if (CanWrite)
|
if (CanWrite)
|
||||||
|
{
|
||||||
|
if (!IsExpanded)
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var c = (Color)Value;
|
||||||
|
GUI.color = c;
|
||||||
|
GUILayout.Label($"<color=#2df7b2>Color:</color> {c.ToString()}", null);
|
||||||
|
GUI.color = Color.white;
|
||||||
|
|
||||||
|
if (CanWrite && IsExpanded)
|
||||||
{
|
{
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
var whitespace = window.width - width - 90;
|
|
||||||
|
float whitespace = WhiteSpace;
|
||||||
|
if (whitespace > 0)
|
||||||
|
{
|
||||||
|
ClampLabelWidth(window, ref whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Space(whitespace);
|
GUILayout.Space(whitespace);
|
||||||
|
@ -51,7 +51,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.Label(Value.ToString() + "<color=yellow><i> (" + ValueType + ")</i></color>", null);
|
GUILayout.Label(Value.ToString() + "<color=#2df7b2><i> (" + ValueType + ")</i></color>", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetEnum(ref object value, int change)
|
public void SetEnum(ref object value, int change)
|
||||||
|
@ -69,10 +69,10 @@ namespace Explorer
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// using ValueType.Name instead of ValueTypeName, because we only want the short name.
|
// 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) });
|
GUILayout.Label("<color=#2df7b2><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 - 310f;
|
||||||
if (CanWrite) maxwidth -= 60;
|
if (CanWrite) maxwidth -= 60;
|
||||||
|
|
||||||
if (dynSize > maxwidth)
|
if (dynSize > maxwidth)
|
||||||
@ -92,7 +92,7 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GUILayout.Space(5);
|
GUILayout.Space(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,12 +7,16 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CacheQuaternion : CacheObjectBase
|
public class CacheQuaternion : CacheObjectBase, IExpandHeight
|
||||||
{
|
{
|
||||||
private string x = "0";
|
private string x = "0";
|
||||||
private string y = "0";
|
private string y = "0";
|
||||||
private string z = "0";
|
private string z = "0";
|
||||||
|
|
||||||
|
public bool IsExpanded { get; set; }
|
||||||
|
public float WhiteSpace { get; set; } = 215f;
|
||||||
|
public float ButtonWidthOffset { get; set; } = 290f;
|
||||||
|
|
||||||
public override void UpdateValue()
|
public override void UpdateValue()
|
||||||
{
|
{
|
||||||
base.UpdateValue();
|
base.UpdateValue();
|
||||||
@ -26,12 +30,35 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
GUILayout.Label($"<color=yellow>Quaternion</color>: {((Quaternion)Value).eulerAngles.ToString()}", null);
|
|
||||||
|
|
||||||
if (CanWrite)
|
if (CanWrite)
|
||||||
|
{
|
||||||
|
if (!IsExpanded)
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.Label($"<color=#2df7b2>Quaternion</color>: {((Quaternion)Value).eulerAngles.ToString()}", null);
|
||||||
|
|
||||||
|
if (CanWrite && IsExpanded)
|
||||||
{
|
{
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
var whitespace = window.width - width - 90;
|
|
||||||
|
float whitespace = WhiteSpace;
|
||||||
|
if (whitespace > 0)
|
||||||
|
{
|
||||||
|
ClampLabelWidth(window, ref whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Space(whitespace);
|
GUILayout.Space(whitespace);
|
||||||
|
@ -7,13 +7,17 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CacheRect : CacheObjectBase
|
public class CacheRect : CacheObjectBase, IExpandHeight
|
||||||
{
|
{
|
||||||
private string x = "0";
|
private string x = "0";
|
||||||
private string y = "0";
|
private string y = "0";
|
||||||
private string w = "0";
|
private string w = "0";
|
||||||
private string h = "0";
|
private string h = "0";
|
||||||
|
|
||||||
|
public bool IsExpanded { get; set; }
|
||||||
|
public float WhiteSpace { get; set; } = 215f;
|
||||||
|
public float ButtonWidthOffset { get; set; } = 290f;
|
||||||
|
|
||||||
public override void UpdateValue()
|
public override void UpdateValue()
|
||||||
{
|
{
|
||||||
base.UpdateValue();
|
base.UpdateValue();
|
||||||
@ -28,12 +32,35 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
GUILayout.Label($"<color=yellow>Rect</color>: {((Rect)Value).ToString()}", null);
|
|
||||||
|
|
||||||
if (CanWrite)
|
if (CanWrite)
|
||||||
|
{
|
||||||
|
if (!IsExpanded)
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.Label($"<color=#2df7b2>Rect</color>: {((Rect)Value).ToString()}", null);
|
||||||
|
|
||||||
|
if (CanWrite && IsExpanded)
|
||||||
{
|
{
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
var whitespace = window.width - width - 90;
|
|
||||||
|
float whitespace = WhiteSpace;
|
||||||
|
if (whitespace > 0)
|
||||||
|
{
|
||||||
|
ClampLabelWidth(window, ref whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
GUILayout.Space(whitespace);
|
GUILayout.Space(whitespace);
|
||||||
|
@ -8,7 +8,7 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Explorer
|
namespace Explorer
|
||||||
{
|
{
|
||||||
public class CacheVector : CacheObjectBase
|
public class CacheVector : CacheObjectBase, IExpandHeight
|
||||||
{
|
{
|
||||||
public int VectorSize = 2;
|
public int VectorSize = 2;
|
||||||
|
|
||||||
@ -19,6 +19,10 @@ namespace Explorer
|
|||||||
|
|
||||||
private MethodInfo m_toStringMethod;
|
private MethodInfo m_toStringMethod;
|
||||||
|
|
||||||
|
public bool IsExpanded { get; set; }
|
||||||
|
public float WhiteSpace { get; set; } = 215f;
|
||||||
|
public float ButtonWidthOffset { get; set; } = 290f;
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
if (Value is Vector2)
|
if (Value is Vector2)
|
||||||
@ -63,12 +67,34 @@ namespace Explorer
|
|||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
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)
|
if (CanWrite)
|
||||||
|
{
|
||||||
|
if (!IsExpanded)
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
|
{
|
||||||
|
IsExpanded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayout.Label($"<color=#2df7b2>Vector{VectorSize}</color>: {(string)m_toStringMethod.Invoke(Value, new object[0])}", null);
|
||||||
|
|
||||||
|
if (CanWrite && IsExpanded)
|
||||||
{
|
{
|
||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
var whitespace = window.width - width - 90;
|
float whitespace = WhiteSpace;
|
||||||
|
if (whitespace > 0)
|
||||||
|
{
|
||||||
|
ClampLabelWidth(window, ref whitespace);
|
||||||
|
}
|
||||||
|
|
||||||
// always draw x and y
|
// always draw x and y
|
||||||
GUILayout.BeginHorizontal(null);
|
GUILayout.BeginHorizontal(null);
|
||||||
|
@ -13,7 +13,7 @@ namespace Explorer
|
|||||||
public class CppExplorer : MelonMod
|
public class CppExplorer : MelonMod
|
||||||
{
|
{
|
||||||
public const string NAME = "CppExplorer";
|
public const string NAME = "CppExplorer";
|
||||||
public const string VERSION = "1.6.4";
|
public const string VERSION = "1.6.5";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
public const string GUID = "com.sinai.cppexplorer";
|
public const string GUID = "com.sinai.cppexplorer";
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ namespace Explorer
|
|||||||
{
|
{
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
||||||
InputHelper.CheckInput();
|
InputHelper.Init();
|
||||||
|
|
||||||
new MainMenu();
|
new MainMenu();
|
||||||
new WindowManager();
|
new WindowManager();
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
<ProjectGuid>{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}</ProjectGuid>
|
<ProjectGuid>{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}</ProjectGuid>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
@ -24,6 +24,7 @@
|
|||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<!-- Replace the '..\Steam\..` references with ones from your game (make sure to use the 'MelonLoader\' folder) -->
|
||||||
<Reference Include="Il2Cppmscorlib">
|
<Reference Include="Il2Cppmscorlib">
|
||||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Il2Cppmscorlib.dll</HintPath>
|
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Il2Cppmscorlib.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
@ -46,7 +47,6 @@
|
|||||||
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerBaseLib.dll</HintPath>
|
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnhollowerBaseLib.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<!-- Replace these references with ones from your game (..\MelonLoader\ folder) -->
|
|
||||||
<Reference Include="UnityEngine">
|
<Reference Include="UnityEngine">
|
||||||
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.dll</HintPath>
|
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\UnityEngine.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
@ -88,6 +88,7 @@
|
|||||||
<Compile Include="CppExplorer.cs" />
|
<Compile Include="CppExplorer.cs" />
|
||||||
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
<Compile Include="Extensions\ReflectionExtensions.cs" />
|
||||||
<Compile Include="Helpers\InputHelper.cs" />
|
<Compile Include="Helpers\InputHelper.cs" />
|
||||||
|
<Compile Include="Tests\TestClass.cs" />
|
||||||
<Compile Include="UnstripFixes\GUIUnstrip.cs" />
|
<Compile Include="UnstripFixes\GUIUnstrip.cs" />
|
||||||
<Compile Include="UnstripFixes\ScrollViewStateUnstrip.cs" />
|
<Compile Include="UnstripFixes\ScrollViewStateUnstrip.cs" />
|
||||||
<Compile Include="Extensions\UnityExtensions.cs" />
|
<Compile Include="Extensions\UnityExtensions.cs" />
|
||||||
|
@ -10,8 +10,8 @@ Global
|
|||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.Build.0 = Release|Any CPU
|
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release|Any CPU.Build.0 = Debug|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -15,19 +15,88 @@ namespace Explorer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class InputHelper
|
public static class InputHelper
|
||||||
{
|
{
|
||||||
public static void CheckInput()
|
// If Input module failed to load at all
|
||||||
|
public static bool NO_INPUT;
|
||||||
|
|
||||||
|
// Base UnityEngine.Input class
|
||||||
|
private static Type Input => _input ?? (_input = ReflectionHelpers.GetTypeByName("UnityEngine.Input"));
|
||||||
|
private static Type _input;
|
||||||
|
|
||||||
|
// Cached member infos
|
||||||
|
private static PropertyInfo _mousePosition;
|
||||||
|
private static MethodInfo _getKey;
|
||||||
|
private static MethodInfo _getKeyDown;
|
||||||
|
private static MethodInfo _getMouseButton;
|
||||||
|
private static MethodInfo _getMouseButtonDown;
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
{
|
{
|
||||||
if (Input == null)
|
if (Input == null && !TryManuallyLoadInput())
|
||||||
|
{
|
||||||
|
NO_INPUT = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache reflection now that we know Input is loaded
|
||||||
|
|
||||||
|
_mousePosition = Input.GetProperty("mousePosition");
|
||||||
|
|
||||||
|
_getKey = Input.GetMethod("GetKey", new Type[] { typeof(KeyCode) });
|
||||||
|
_getKeyDown = Input.GetMethod("GetKeyDown", new Type[] { typeof(KeyCode) });
|
||||||
|
_getMouseButton = Input.GetMethod("GetMouseButton", new Type[] { typeof(int) });
|
||||||
|
_getMouseButtonDown = Input.GetMethod("GetMouseButtonDown", new Type[] { typeof(int) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable IDE1006 // Camel-case property (Unity style)
|
||||||
|
public static Vector3 mousePosition
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (NO_INPUT) return Vector3.zero;
|
||||||
|
return (Vector3)_mousePosition.GetValue(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma warning restore IDE1006
|
||||||
|
|
||||||
|
public static bool GetKeyDown(KeyCode key)
|
||||||
|
{
|
||||||
|
if (NO_INPUT) return false;
|
||||||
|
return (bool)_getKeyDown.Invoke(null, new object[] { key });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetKey(KeyCode key)
|
||||||
|
{
|
||||||
|
if (NO_INPUT) return false;
|
||||||
|
return (bool)_getKey.Invoke(null, new object[] { key });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param>
|
||||||
|
public static bool GetMouseButtonDown(int btn)
|
||||||
|
{
|
||||||
|
if (NO_INPUT) return false;
|
||||||
|
return (bool)_getMouseButtonDown.Invoke(null, new object[] { btn });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param>
|
||||||
|
public static bool GetMouseButton(int btn)
|
||||||
|
{
|
||||||
|
if (NO_INPUT) return false;
|
||||||
|
return (bool)_getMouseButton.Invoke(null, new object[] { btn });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryManuallyLoadInput()
|
||||||
{
|
{
|
||||||
MelonLogger.Log("UnityEngine.Input is null, trying to load manually....");
|
MelonLogger.Log("UnityEngine.Input is null, trying to load manually....");
|
||||||
|
|
||||||
if ((TryLoad("UnityEngine.InputLegacyModule.dll") || TryLoad("UnityEngine.CoreModule.dll")) && Input != null)
|
if ((TryLoad("UnityEngine.InputLegacyModule.dll") || TryLoad("UnityEngine.CoreModule.dll")) && Input != null)
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Ok!");
|
MelonLogger.Log("Ok!");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MelonLogger.Log("Could not load Input module!");
|
MelonLogger.Log("Could not load Input module!");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryLoad(string module)
|
bool TryLoad(string module)
|
||||||
@ -48,60 +117,4 @@ namespace Explorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type Input => _input ?? (_input = ReflectionHelpers.GetTypeByName("UnityEngine.Input"));
|
|
||||||
private static Type _input;
|
|
||||||
|
|
||||||
private static PropertyInfo MousePosInfo => _mousePosition ?? (_mousePosition = Input?.GetProperty("mousePosition"));
|
|
||||||
private static PropertyInfo _mousePosition;
|
|
||||||
|
|
||||||
private static MethodInfo GetKeyInfo => _getKey ?? (_getKey = Input?.GetMethod("GetKey", new Type[] { typeof(KeyCode) }));
|
|
||||||
private static MethodInfo _getKey;
|
|
||||||
|
|
||||||
private static MethodInfo GetKeyDownInfo => _getKeyDown ?? (_getKeyDown = Input?.GetMethod("GetKeyDown", new Type[] { typeof(KeyCode) }));
|
|
||||||
private static MethodInfo _getKeyDown;
|
|
||||||
|
|
||||||
private static MethodInfo GetMouseButtonInfo => _getMouseButton ?? (_getMouseButton = Input?.GetMethod("GetMouseButton", new Type[] { typeof(int) }));
|
|
||||||
private static MethodInfo _getMouseButton;
|
|
||||||
|
|
||||||
private static MethodInfo GetMouseButtonDownInfo => _getMouseButtonDown ?? (_getMouseButtonDown = Input?.GetMethod("GetMouseButtonDown", new Type[] { typeof(int) }));
|
|
||||||
private static MethodInfo _getMouseButtonDown;
|
|
||||||
|
|
||||||
#pragma warning disable IDE1006 // Camel-case property (Unity style)
|
|
||||||
public static Vector3 mousePosition
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Input == null) return Vector3.zero;
|
|
||||||
return (Vector3)MousePosInfo.GetValue(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore IDE1006
|
|
||||||
|
|
||||||
public static bool GetKeyDown(KeyCode key)
|
|
||||||
{
|
|
||||||
if (Input == null) return false;
|
|
||||||
return (bool)GetKeyDownInfo.Invoke(null, new object[] { key });
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool GetKey(KeyCode key)
|
|
||||||
{
|
|
||||||
if (Input == null) return false;
|
|
||||||
return (bool)GetKeyInfo.Invoke(null, new object[] { key });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param>
|
|
||||||
public static bool GetMouseButtonDown(int btn)
|
|
||||||
{
|
|
||||||
if (Input == null) return false;
|
|
||||||
return (bool)GetMouseButtonDownInfo.Invoke(null, new object[] { btn });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <param name="btn">1 = left, 2 = middle, 3 = right, etc</param>
|
|
||||||
public static bool GetMouseButton(int btn)
|
|
||||||
{
|
|
||||||
if (Input == null) return false;
|
|
||||||
return (bool)GetMouseButtonInfo.Invoke(null, new object[] { btn });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
74
src/Tests/TestClass.cs
Normal file
74
src/Tests/TestClass.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MelonLoader;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer.Tests
|
||||||
|
{
|
||||||
|
public class TestClass
|
||||||
|
{
|
||||||
|
public static TestClass Instance => m_instance ?? (m_instance = new TestClass());
|
||||||
|
private static TestClass m_instance;
|
||||||
|
|
||||||
|
public string this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return $"int indexer: {index}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string this[string stringIndex]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return $"string indexer: {stringIndex}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string this[int arg0, string arg1]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return $"arg0: {arg0}, arg1: {arg1}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<string> TestList = new List<string>
|
||||||
|
{
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"etc..."
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Dictionary<int, List<string>> NestedDictionary = new Dictionary<int, List<string>>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
123,
|
||||||
|
new List<string>
|
||||||
|
{
|
||||||
|
"One",
|
||||||
|
"Two"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
567,
|
||||||
|
new List<string>
|
||||||
|
{
|
||||||
|
"One",
|
||||||
|
"Two"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Color TestMethod(float r, float g, float b, float a)
|
||||||
|
{
|
||||||
|
return new Color(r, g, b, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -162,10 +162,20 @@ namespace Explorer
|
|||||||
name += " (";
|
name += " (";
|
||||||
foreach (var param in mi.GetParameters())
|
foreach (var param in mi.GetParameters())
|
||||||
{
|
{
|
||||||
name += param.ParameterType.Name + ", ";
|
name += $"{param.ParameterType.Name} {param.Name}, ";
|
||||||
}
|
}
|
||||||
name += ")";
|
name += ")";
|
||||||
}
|
}
|
||||||
|
else if (member is PropertyInfo pi)
|
||||||
|
{
|
||||||
|
name += " (";
|
||||||
|
foreach (var param in pi.GetIndexParameters())
|
||||||
|
{
|
||||||
|
name += $"{param.ParameterType.Name} {param.Name}, ";
|
||||||
|
}
|
||||||
|
name += ")";
|
||||||
|
}
|
||||||
|
|
||||||
if (names.Contains(name))
|
if (names.Contains(name))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
Reference in New Issue
Block a user