mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-03 20:12:33 +08:00
Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
a80cef4c1d | |||
450bb77f2e | |||
0479102db6 | |||
93181f02be | |||
371054d6df | |||
427f23b80a | |||
a0d5ab8792 | |||
297034e38b | |||
57f59d1295 | |||
fbdb84eefa | |||
6989ea1b19 | |||
fcdfeb2dec | |||
a1d0b6432e | |||
0b84405e57 | |||
c31e0949d3 | |||
5f0495a7ea | |||
28de6779d8 |
23
README.md
23
README.md
@ -8,14 +8,13 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
✔️ Supports most Unity versions from 5.2 to 2021+ (IL2CPP and Mono).
|
✔️ Supports most Unity versions from 5.2 to 2021+ (IL2CPP and Mono).
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
|
||||||
⚡ UnityExplorer is on <a href="https://thunderstore.io/package/sinai-dev/UnityExplorer/">Thunderstore</a>! (and as <a href="https://gtfo.thunderstore.io/package/sinai-dev/UnityExplorer_IL2CPP/">IL2CPP</a>)
|
|
||||||
</p>
|
|
||||||
|
|
||||||
# Releases [](../../releases)
|
# Releases [](../../releases)
|
||||||
|
|
||||||
[](../../releases/latest) [](https://github.com/sinai-dev/UnityExplorer/actions) [](../../releases/latest)
|
[](../../releases/latest) [](https://github.com/sinai-dev/UnityExplorer/actions) [](../../releases/latest)
|
||||||
|
|
||||||
|
⚡ Thunderstore releases: [BepInEx Mono](https://thunderstore.io/package/sinai-dev/UnityExplorer) | [BepInEx IL2CPP](https://gtfo.thunderstore.io/package/sinai-dev/UnityExplorer_IL2CPP) | [MelonLoader IL2CPP](https://boneworks.thunderstore.io/package/sinai-dev/UnityExplorer_IL2CPP_ML)
|
||||||
|
|
||||||
## BepInEx
|
## BepInEx
|
||||||
|
|
||||||
| Release | IL2CPP | Mono |
|
| Release | IL2CPP | Mono |
|
||||||
@ -85,6 +84,12 @@ The inspector is used to see detailed information on objects of any type and man
|
|||||||
* You can execute a script automatically on startup by naming it `startup.cs` and placing it in the `UnityExplorer\Scripts\` folder (this folder will be created where you placed the DLL file).
|
* You can execute a script automatically on startup by naming it `startup.cs` and placing it in the `UnityExplorer\Scripts\` folder (this folder will be created where you placed the DLL file).
|
||||||
* See the "Help" dropdown in the C# console menu for more detailed information.
|
* See the "Help" dropdown in the C# console menu for more detailed information.
|
||||||
|
|
||||||
|
### Hook Manager
|
||||||
|
|
||||||
|
* The Hooks panel allows you to hook methods at the click of a button for debugging purposes.
|
||||||
|
* Simply enter any class (generic types not yet supported) and hook the methods you want from the menu.
|
||||||
|
* You can edit the source code of the generated hook with the "Edit Hook Source" button. Accepted method names are `Prefix` (which can return `bool` or `void`), `Postfix`, `Finalizer` (which can return `Exception` or `void`), and `Transpiler` (which must return `IEnumerable<HarmonyLib.CodeInstruction>`). You can define multiple patches if you wish.
|
||||||
|
|
||||||
### Mouse-Inspect
|
### Mouse-Inspect
|
||||||
|
|
||||||
* The "Mouse Inspect" dropdown on the main UnityExplorer navbar allows you to inspect objects under the mouse.
|
* The "Mouse Inspect" dropdown on the main UnityExplorer navbar allows you to inspect objects under the mouse.
|
||||||
@ -100,12 +105,6 @@ The inspector is used to see detailed information on objects of any type and man
|
|||||||
|
|
||||||
# Building
|
# Building
|
||||||
|
|
||||||
If you fork the repository on GitHub you can build using the [dotnet workflow](https://github.com/sinai-dev/UnityExplorer/blob/master/.github/workflows/dotnet.yml):
|
|
||||||
|
|
||||||
0. Click on the Actions tab and enable workflows in your repository
|
|
||||||
1. Click on the "Build UnityExplorer" workflow, then click "Run Workflow" and run it manually, or make a new commit to trigger the workflow.
|
|
||||||
2. Take the artifact from the completed run.
|
|
||||||
|
|
||||||
For Visual Studio:
|
For Visual Studio:
|
||||||
|
|
||||||
0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
|
0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
|
||||||
@ -113,6 +112,12 @@ For Visual Studio:
|
|||||||
2. Build `mcs` (Release/AnyCPU, you may need to run `nuget restore mcs.sln`), and if using IL2CPP then build `Il2CppAssemblyUnhollower` (Release/AnyCPU) as well.
|
2. Build `mcs` (Release/AnyCPU, you may need to run `nuget restore mcs.sln`), and if using IL2CPP then build `Il2CppAssemblyUnhollower` (Release/AnyCPU) as well.
|
||||||
3. Build the UnityExplorer release(s) you want to use, either by selecting the config as the Active Config, or batch-building.
|
3. Build the UnityExplorer release(s) you want to use, either by selecting the config as the Active Config, or batch-building.
|
||||||
|
|
||||||
|
If you fork the repository on GitHub you can build using the [dotnet workflow](https://github.com/sinai-dev/UnityExplorer/blob/master/.github/workflows/dotnet.yml):
|
||||||
|
|
||||||
|
0. Click on the Actions tab and enable workflows in your repository
|
||||||
|
1. Click on the "Build UnityExplorer" workflow, then click "Run Workflow" and run it manually, or make a new commit to trigger the workflow.
|
||||||
|
2. Take the artifact from the completed run.
|
||||||
|
|
||||||
# Acknowledgments
|
# Acknowledgments
|
||||||
|
|
||||||
* [ManlyMarco](https://github.com/ManlyMarco) for [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor) \[[license](THIRDPARTY_LICENSES.md#runtimeunityeditor-license)\], the ScriptEvaluator from RUE's REPL console was used as the base for UnityExplorer's C# console.
|
* [ManlyMarco](https://github.com/ManlyMarco) for [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor) \[[license](THIRDPARTY_LICENSES.md#runtimeunityeditor-license)\], the ScriptEvaluator from RUE's REPL console was used as the base for UnityExplorer's C# console.
|
||||||
|
@ -202,7 +202,7 @@ namespace UnityExplorer.CSConsole
|
|||||||
{
|
{
|
||||||
// The compiled code was not REPL, so it was a using directive or it defined classes.
|
// The compiled code was not REPL, so it was a using directive or it defined classes.
|
||||||
|
|
||||||
string output = ScriptEvaluator._textWriter.ToString();
|
string output = Evaluator._textWriter.ToString();
|
||||||
var outputSplit = output.Split('\n');
|
var outputSplit = output.Split('\n');
|
||||||
if (outputSplit.Length >= 2)
|
if (outputSplit.Length >= 2)
|
||||||
output = outputSplit[outputSplit.Length - 2];
|
output = outputSplit[outputSplit.Length - 2];
|
||||||
|
@ -16,7 +16,7 @@ namespace UnityExplorer.CSConsole
|
|||||||
"mscorlib", "System.Core", "System", "System.Xml"
|
"mscorlib", "System.Core", "System", "System.Xml"
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static TextWriter _textWriter;
|
internal TextWriter _textWriter;
|
||||||
internal static StreamReportPrinter _reportPrinter;
|
internal static StreamReportPrinter _reportPrinter;
|
||||||
|
|
||||||
public ScriptEvaluator(TextWriter tw) : base(BuildContext(tw))
|
public ScriptEvaluator(TextWriter tw) : base(BuildContext(tw))
|
||||||
@ -51,8 +51,13 @@ namespace UnityExplorer.CSConsole
|
|||||||
ReferenceAssembly(asm);
|
ReferenceAssembly(asm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static CompilerContext context;
|
||||||
|
|
||||||
private static CompilerContext BuildContext(TextWriter tw)
|
private static CompilerContext BuildContext(TextWriter tw)
|
||||||
{
|
{
|
||||||
|
if (context != null)
|
||||||
|
return context;
|
||||||
|
|
||||||
_reportPrinter = new StreamReportPrinter(tw);
|
_reportPrinter = new StreamReportPrinter(tw);
|
||||||
|
|
||||||
var settings = new CompilerSettings
|
var settings = new CompilerSettings
|
||||||
@ -65,7 +70,7 @@ namespace UnityExplorer.CSConsole
|
|||||||
EnhancedWarnings = false
|
EnhancedWarnings = false
|
||||||
};
|
};
|
||||||
|
|
||||||
return new CompilerContext(settings, _reportPrinter);
|
return context = new CompilerContext(settings, _reportPrinter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ImportAppdomainAssemblies(Action<Assembly> import)
|
private static void ImportAppdomainAssemblies(Action<Assembly> import)
|
||||||
|
@ -14,9 +14,6 @@ namespace UnityExplorer.CacheObject
|
|||||||
{
|
{
|
||||||
public abstract class CacheMember : CacheObjectBase
|
public abstract class CacheMember : CacheObjectBase
|
||||||
{
|
{
|
||||||
//public ReflectionInspector ParentInspector { get; internal set; }
|
|
||||||
//public bool AutoUpdateWanted { get; internal set; }
|
|
||||||
|
|
||||||
public abstract Type DeclaringType { get; }
|
public abstract Type DeclaringType { get; }
|
||||||
public string NameForFiltering { get; protected set; }
|
public string NameForFiltering { get; protected set; }
|
||||||
public object DeclaringInstance => IsStatic ? null : (m_declaringInstance ?? (m_declaringInstance = Owner.Target.TryCast(DeclaringType)));
|
public object DeclaringInstance => IsStatic ? null : (m_declaringInstance ?? (m_declaringInstance = Owner.Target.TryCast(DeclaringType)));
|
||||||
@ -61,6 +58,17 @@ namespace UnityExplorer.CacheObject
|
|||||||
|
|
||||||
protected abstract void TrySetValue(object value);
|
protected abstract void TrySetValue(object value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluate is called when first shown (if ShouldAutoEvaluate), or else when Evaluate button is clicked, or auto-updated.
|
||||||
|
/// </summary>
|
||||||
|
public void Evaluate()
|
||||||
|
{
|
||||||
|
SetValueFromSource(TryEvaluate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when user presses the Evaluate button.
|
||||||
|
/// </summary>
|
||||||
public void EvaluateAndSetCell()
|
public void EvaluateAndSetCell()
|
||||||
{
|
{
|
||||||
Evaluate();
|
Evaluate();
|
||||||
@ -68,27 +76,15 @@ namespace UnityExplorer.CacheObject
|
|||||||
SetDataToCell(CellView);
|
SetDataToCell(CellView);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Evaluate when first shown (if ShouldAutoEvaluate), or else when Evaluate button is clicked, or auto-updated.
|
|
||||||
/// </summary>
|
|
||||||
public void Evaluate()
|
|
||||||
{
|
|
||||||
SetValueFromSource(TryEvaluate());
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void TrySetUserValue(object value)
|
public override void TrySetUserValue(object value)
|
||||||
{
|
{
|
||||||
TrySetValue(value);
|
TrySetValue(value);
|
||||||
|
|
||||||
Evaluate();
|
Evaluate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void SetValueState(CacheObjectCell cell, ValueStateArgs args)
|
protected override void SetValueState(CacheObjectCell cell, ValueStateArgs args)
|
||||||
{
|
{
|
||||||
base.SetValueState(cell, args);
|
base.SetValueState(cell, args);
|
||||||
|
|
||||||
//var memCell = cell as CacheMemberCell;
|
|
||||||
//memCell.UpdateToggle.gameObject.SetActive(ShouldAutoEvaluate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Color evalEnabledColor = new Color(0.15f, 0.25f, 0.15f);
|
private static readonly Color evalEnabledColor = new Color(0.15f, 0.25f, 0.15f);
|
||||||
@ -101,7 +97,6 @@ namespace UnityExplorer.CacheObject
|
|||||||
cell.EvaluateHolder.SetActive(!ShouldAutoEvaluate);
|
cell.EvaluateHolder.SetActive(!ShouldAutoEvaluate);
|
||||||
if (!ShouldAutoEvaluate)
|
if (!ShouldAutoEvaluate)
|
||||||
{
|
{
|
||||||
//cell.UpdateToggle.gameObject.SetActive(false);
|
|
||||||
cell.EvaluateButton.Component.gameObject.SetActive(true);
|
cell.EvaluateButton.Component.gameObject.SetActive(true);
|
||||||
if (HasArguments)
|
if (HasArguments)
|
||||||
{
|
{
|
||||||
@ -120,11 +115,6 @@ namespace UnityExplorer.CacheObject
|
|||||||
if (!Evaluating)
|
if (!Evaluating)
|
||||||
RuntimeProvider.Instance.SetColorBlock(cell.EvaluateButton.Component, evalDisabledColor, evalDisabledColor * 1.3f);
|
RuntimeProvider.Instance.SetColorBlock(cell.EvaluateButton.Component, evalDisabledColor, evalDisabledColor * 1.3f);
|
||||||
}
|
}
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// cell.UpdateToggle.gameObject.SetActive(true);
|
|
||||||
// cell.UpdateToggle.isOn = AutoUpdateWanted;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (State == ValueState.NotEvaluated && !ShouldAutoEvaluate)
|
if (State == ValueState.NotEvaluated && !ShouldAutoEvaluate)
|
||||||
{
|
{
|
||||||
@ -140,7 +130,6 @@ namespace UnityExplorer.CacheObject
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnEvaluateClicked()
|
public void OnEvaluateClicked()
|
||||||
{
|
{
|
||||||
if (!HasArguments)
|
if (!HasArguments)
|
||||||
@ -246,7 +235,7 @@ namespace UnityExplorer.CacheObject
|
|||||||
|
|
||||||
var sig = GetSig(member);
|
var sig = GetSig(member);
|
||||||
|
|
||||||
//ExplorerCore.Log($"Trying to cache member {sig}...");
|
//ExplorerCore.Log($"Trying to cache member {sig}... ({member.MemberType})");
|
||||||
|
|
||||||
CacheMember cached;
|
CacheMember cached;
|
||||||
Type returnType;
|
Type returnType;
|
||||||
@ -311,7 +300,6 @@ namespace UnityExplorer.CacheObject
|
|||||||
|
|
||||||
cachedSigs.Add(sig);
|
cachedSigs.Add(sig);
|
||||||
|
|
||||||
//cached.Initialize(_inspector, declaringType, member, returnType);
|
|
||||||
cached.SetFallbackType(returnType);
|
cached.SetFallbackType(returnType);
|
||||||
cached.SetInspectorOwner(_inspector, member);
|
cached.SetInspectorOwner(_inspector, member);
|
||||||
|
|
||||||
|
@ -169,7 +169,6 @@ namespace UnityExplorer.CacheObject.IValues
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int AdjustedWidth => (int)UIRect.rect.width - 80;
|
public int AdjustedWidth => (int)UIRect.rect.width - 80;
|
||||||
//public int AdjustedKeyWidth => HalfWidth - 50;
|
|
||||||
|
|
||||||
public override void SetLayout()
|
public override void SetLayout()
|
||||||
{
|
{
|
||||||
|
@ -37,6 +37,7 @@ namespace UnityExplorer.Core.Config
|
|||||||
public static ConfigElement<string> CSConsoleData;
|
public static ConfigElement<string> CSConsoleData;
|
||||||
public static ConfigElement<string> OptionsPanelData;
|
public static ConfigElement<string> OptionsPanelData;
|
||||||
public static ConfigElement<string> ConsoleLogData;
|
public static ConfigElement<string> ConsoleLogData;
|
||||||
|
public static ConfigElement<string> HookManagerData;
|
||||||
|
|
||||||
internal static readonly Dictionary<string, IConfigElement> ConfigElements = new Dictionary<string, IConfigElement>();
|
internal static readonly Dictionary<string, IConfigElement> ConfigElements = new Dictionary<string, IConfigElement>();
|
||||||
internal static readonly Dictionary<string, IConfigElement> InternalConfigs = new Dictionary<string, IConfigElement>();
|
internal static readonly Dictionary<string, IConfigElement> InternalConfigs = new Dictionary<string, IConfigElement>();
|
||||||
@ -126,6 +127,7 @@ namespace UnityExplorer.Core.Config
|
|||||||
CSConsoleData = new ConfigElement<string>("CSConsole", "", "", true);
|
CSConsoleData = new ConfigElement<string>("CSConsole", "", "", true);
|
||||||
OptionsPanelData = new ConfigElement<string>("OptionsPanel", "", "", true);
|
OptionsPanelData = new ConfigElement<string>("OptionsPanel", "", "", true);
|
||||||
ConsoleLogData = new ConfigElement<string>("ConsoleLog", "", "", true);
|
ConsoleLogData = new ConfigElement<string>("ConsoleLog", "", "", true);
|
||||||
|
HookManagerData = new ConfigElement<string>("HookManager", "", "", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,6 @@ namespace UnityExplorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HashSet<Type> GetImplementationsOf(this Type baseType, bool allowAbstract, bool allowGeneric)
|
|
||||||
=> ReflectionUtility.GetImplementationsOf(baseType, allowAbstract, allowGeneric);
|
|
||||||
|
|
||||||
// ------- Misc extensions --------
|
// ------- Misc extensions --------
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -14,7 +14,6 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using UnityExplorer.Core;
|
using UnityExplorer.Core;
|
||||||
using CppType = Il2CppSystem.Type;
|
using CppType = Il2CppSystem.Type;
|
||||||
using BF = System.Reflection.BindingFlags;
|
using BF = System.Reflection.BindingFlags;
|
||||||
using UnityExplorer.Core.Config;
|
|
||||||
using UnhollowerBaseLib.Attributes;
|
using UnhollowerBaseLib.Attributes;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -562,6 +561,7 @@ namespace UnityExplorer
|
|||||||
"UnityEngine.Audio.AudioMixerPlayable.Create",
|
"UnityEngine.Audio.AudioMixerPlayable.Create",
|
||||||
"UnityEngine.BoxcastCommand.ScheduleBatch",
|
"UnityEngine.BoxcastCommand.ScheduleBatch",
|
||||||
"UnityEngine.Camera.CalculateProjectionMatrixFromPhysicalProperties",
|
"UnityEngine.Camera.CalculateProjectionMatrixFromPhysicalProperties",
|
||||||
|
"UnityEngine.Canvas.renderingDisplaySize",
|
||||||
"UnityEngine.CapsulecastCommand.ScheduleBatch",
|
"UnityEngine.CapsulecastCommand.ScheduleBatch",
|
||||||
"UnityEngine.Collider2D.Cast",
|
"UnityEngine.Collider2D.Cast",
|
||||||
"UnityEngine.Collider2D.Raycast",
|
"UnityEngine.Collider2D.Raycast",
|
||||||
|
@ -251,27 +251,25 @@ namespace UnityExplorer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="baseType">The base type, which can optionally be abstract / interface.</param>
|
/// <param name="baseType">The base type, which can optionally be abstract / interface.</param>
|
||||||
/// <returns>All implementations of the type in the current AppDomain.</returns>
|
/// <returns>All implementations of the type in the current AppDomain.</returns>
|
||||||
public static HashSet<Type> GetImplementationsOf(Type baseType, bool allowAbstract, bool allowGeneric, bool allowRecursive = true)
|
public static HashSet<Type> GetImplementationsOf(Type baseType, bool allowAbstract, bool allowGeneric, bool allowEnum, bool allowRecursive = true)
|
||||||
{
|
{
|
||||||
var key = GetImplementationKey(baseType);
|
var key = GetImplementationKey(baseType);
|
||||||
|
|
||||||
int count = AllTypes.Count;
|
int count = AllTypes.Count;
|
||||||
HashSet<Type> ret;
|
HashSet<Type> ret;
|
||||||
if (!baseType.IsGenericParameter)
|
if (!baseType.IsGenericParameter)
|
||||||
ret = GetImplementations(key, baseType, allowAbstract, allowGeneric);
|
ret = GetImplementations(key, baseType, allowAbstract, allowGeneric, allowEnum);
|
||||||
else
|
else
|
||||||
ret = GetGenericParameterImplementations(key, baseType, allowAbstract, allowGeneric);
|
ret = GetGenericParameterImplementations(key, baseType, allowAbstract, allowGeneric);
|
||||||
|
|
||||||
// types were resolved during the parse, do it again if we're not already rebuilding.
|
// types were resolved during the parse, do it again if we're not already rebuilding.
|
||||||
if (allowRecursive && AllTypes.Count != count)
|
if (allowRecursive && AllTypes.Count != count)
|
||||||
{
|
|
||||||
ret = GetImplementationsOf(baseType, allowAbstract, allowGeneric, false);
|
ret = GetImplementationsOf(baseType, allowAbstract, allowGeneric, false);
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HashSet<Type> GetImplementations(string key, Type baseType, bool allowAbstract, bool allowGeneric)
|
private static HashSet<Type> GetImplementations(string key, Type baseType, bool allowAbstract, bool allowGeneric, bool allowEnum)
|
||||||
{
|
{
|
||||||
if (!typeInheritance.ContainsKey(key))
|
if (!typeInheritance.ContainsKey(key))
|
||||||
{
|
{
|
||||||
@ -287,7 +285,8 @@ namespace UnityExplorer
|
|||||||
if (set.Contains(type)
|
if (set.Contains(type)
|
||||||
|| (type.IsAbstract && type.IsSealed) // ignore static classes
|
|| (type.IsAbstract && type.IsSealed) // ignore static classes
|
||||||
|| (!allowAbstract && type.IsAbstract)
|
|| (!allowAbstract && type.IsAbstract)
|
||||||
|| (!allowGeneric && (type.IsGenericType || type.IsGenericTypeDefinition)))
|
|| (!allowGeneric && (type.IsGenericType || type.IsGenericTypeDefinition))
|
||||||
|
|| (!allowEnum && type.IsEnum))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (type.FullName.Contains("PrivateImplementationDetails")
|
if (type.FullName.Contains("PrivateImplementationDetails")
|
||||||
|
@ -56,6 +56,9 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
public abstract int GetRootCount(Scene scene);
|
public abstract int GetRootCount(Scene scene);
|
||||||
|
|
||||||
|
public void SetColorBlockAuto(Selectable selectable, Color baseColor)
|
||||||
|
=> SetColorBlock(selectable, baseColor, baseColor * 1.2f, baseColor * 0.8f);
|
||||||
|
|
||||||
public abstract void SetColorBlock(Selectable selectable, ColorBlock colors);
|
public abstract void SetColorBlock(Selectable selectable, ColorBlock colors);
|
||||||
|
|
||||||
public abstract void SetColorBlock(Selectable selectable, Color? normal = null, Color? highlighted = null, Color? pressed = null,
|
public abstract void SetColorBlock(Selectable selectable, Color? normal = null, Color? highlighted = null, Color? pressed = null,
|
||||||
|
@ -20,7 +20,7 @@ namespace UnityExplorer
|
|||||||
public static class ExplorerCore
|
public static class ExplorerCore
|
||||||
{
|
{
|
||||||
public const string NAME = "UnityExplorer";
|
public const string NAME = "UnityExplorer";
|
||||||
public const string VERSION = "4.2.1";
|
public const string VERSION = "4.3.2";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
public const string GUID = "com.sinai.unityexplorer";
|
public const string GUID = "com.sinai.unityexplorer";
|
||||||
|
|
||||||
@ -66,14 +66,13 @@ namespace UnityExplorer
|
|||||||
private static IEnumerator SetupCoroutine()
|
private static IEnumerator SetupCoroutine()
|
||||||
{
|
{
|
||||||
yield return null;
|
yield return null;
|
||||||
|
float prevRealTime = Time.realtimeSinceStartup;
|
||||||
float start = Time.realtimeSinceStartup;
|
|
||||||
float delay = ConfigManager.Startup_Delay_Time.Value;
|
float delay = ConfigManager.Startup_Delay_Time.Value;
|
||||||
|
|
||||||
while (delay > 0)
|
while (delay > 0)
|
||||||
{
|
{
|
||||||
float diff = Math.Max(Time.deltaTime, Time.realtimeSinceStartup - start);
|
float diff = Math.Max(Time.deltaTime, Time.realtimeSinceStartup - prevRealTime);
|
||||||
delay -= diff;
|
delay -= diff;
|
||||||
|
prevRealTime = Time.realtimeSinceStartup;
|
||||||
yield return null;
|
yield return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
63
src/Hooks/AddHookCell.cs
Normal file
63
src/Hooks/AddHookCell.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
|
namespace UnityExplorer.Hooks
|
||||||
|
{
|
||||||
|
public class AddHookCell : ICell
|
||||||
|
{
|
||||||
|
public bool Enabled => UIRoot.activeSelf;
|
||||||
|
|
||||||
|
public RectTransform Rect { get; set; }
|
||||||
|
public GameObject UIRoot { get; set; }
|
||||||
|
|
||||||
|
public float DefaultHeight => 30;
|
||||||
|
|
||||||
|
public Text MethodNameLabel;
|
||||||
|
public Text HookedLabel;
|
||||||
|
public ButtonRef HookButton;
|
||||||
|
|
||||||
|
public int CurrentDisplayedIndex;
|
||||||
|
|
||||||
|
private void OnHookClicked()
|
||||||
|
{
|
||||||
|
HookManager.Instance.AddHookClicked(CurrentDisplayedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enable()
|
||||||
|
{
|
||||||
|
this.UIRoot.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disable()
|
||||||
|
{
|
||||||
|
this.UIRoot.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameObject CreateContent(GameObject parent)
|
||||||
|
{
|
||||||
|
UIRoot = UIFactory.CreateUIObject(this.GetType().Name, parent, new Vector2(100, 30));
|
||||||
|
Rect = UIRoot.GetComponent<RectTransform>();
|
||||||
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(UIRoot, false, false, true, true, 5, childAlignment: TextAnchor.UpperLeft);
|
||||||
|
UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600);
|
||||||
|
UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||||
|
|
||||||
|
HookedLabel = UIFactory.CreateLabel(UIRoot, "HookedLabel", "✓", TextAnchor.MiddleCenter, Color.green);
|
||||||
|
UIFactory.SetLayoutElement(HookedLabel.gameObject, minHeight: 25, minWidth: 100);
|
||||||
|
|
||||||
|
HookButton = UIFactory.CreateButton(UIRoot, "HookButton", "Hook", new Color(0.2f, 0.25f, 0.2f));
|
||||||
|
UIFactory.SetLayoutElement(HookButton.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||||
|
HookButton.OnClick += OnHookClicked;
|
||||||
|
|
||||||
|
MethodNameLabel = UIFactory.CreateLabel(UIRoot, "MethodName", "NOT SET", TextAnchor.MiddleLeft);
|
||||||
|
UIFactory.SetLayoutElement(MethodNameLabel.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
return UIRoot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
src/Hooks/HookCell.cs
Normal file
79
src/Hooks/HookCell.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
|
namespace UnityExplorer.Hooks
|
||||||
|
{
|
||||||
|
public class HookCell : ICell
|
||||||
|
{
|
||||||
|
public bool Enabled => UIRoot.activeSelf;
|
||||||
|
|
||||||
|
public RectTransform Rect { get; set; }
|
||||||
|
public GameObject UIRoot { get; set; }
|
||||||
|
|
||||||
|
public float DefaultHeight => 30;
|
||||||
|
|
||||||
|
public Text MethodNameLabel;
|
||||||
|
public ButtonRef EditPatchButton;
|
||||||
|
public ButtonRef ToggleActiveButton;
|
||||||
|
public ButtonRef DeleteButton;
|
||||||
|
|
||||||
|
public int CurrentDisplayedIndex;
|
||||||
|
|
||||||
|
private void OnToggleActiveClicked()
|
||||||
|
{
|
||||||
|
HookManager.Instance.EnableOrDisableHookClicked(CurrentDisplayedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDeleteClicked()
|
||||||
|
{
|
||||||
|
HookManager.Instance.DeleteHookClicked(CurrentDisplayedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEditPatchClicked()
|
||||||
|
{
|
||||||
|
HookManager.Instance.EditPatchClicked(CurrentDisplayedIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameObject CreateContent(GameObject parent)
|
||||||
|
{
|
||||||
|
UIRoot = UIFactory.CreateUIObject(this.GetType().Name, parent, new Vector2(100, 30));
|
||||||
|
Rect = UIRoot.GetComponent<RectTransform>();
|
||||||
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(UIRoot, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
|
||||||
|
UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600);
|
||||||
|
UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||||
|
|
||||||
|
MethodNameLabel = UIFactory.CreateLabel(UIRoot, "MethodName", "NOT SET", TextAnchor.MiddleLeft);
|
||||||
|
UIFactory.SetLayoutElement(MethodNameLabel.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
ToggleActiveButton = UIFactory.CreateButton(UIRoot, "ToggleActiveBtn", "Enabled", new Color(0.15f, 0.2f, 0.15f));
|
||||||
|
UIFactory.SetLayoutElement(ToggleActiveButton.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||||
|
ToggleActiveButton.OnClick += OnToggleActiveClicked;
|
||||||
|
|
||||||
|
DeleteButton = UIFactory.CreateButton(UIRoot, "DeleteButton", "Delete", new Color(0.2f, 0.15f, 0.15f));
|
||||||
|
UIFactory.SetLayoutElement(DeleteButton.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||||
|
DeleteButton.OnClick += OnDeleteClicked;
|
||||||
|
|
||||||
|
EditPatchButton = UIFactory.CreateButton(UIRoot, "EditButton", "Edit Hook Source", new Color(0.15f, 0.15f, 0.15f));
|
||||||
|
UIFactory.SetLayoutElement(EditPatchButton.Component.gameObject, minHeight: 25, minWidth: 150);
|
||||||
|
EditPatchButton.OnClick += OnEditPatchClicked;
|
||||||
|
|
||||||
|
return UIRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disable()
|
||||||
|
{
|
||||||
|
UIRoot.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Enable()
|
||||||
|
{
|
||||||
|
UIRoot.SetActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
235
src/Hooks/HookInstance.cs
Normal file
235
src/Hooks/HookInstance.cs
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Mono.CSharp;
|
||||||
|
using UnityExplorer.CSConsole;
|
||||||
|
|
||||||
|
namespace UnityExplorer.Hooks
|
||||||
|
{
|
||||||
|
public class HookInstance
|
||||||
|
{
|
||||||
|
// Static
|
||||||
|
|
||||||
|
private static readonly StringBuilder evalOutput = new StringBuilder();
|
||||||
|
private static readonly ScriptEvaluator scriptEvaluator = new ScriptEvaluator(new StringWriter(evalOutput));
|
||||||
|
|
||||||
|
static HookInstance()
|
||||||
|
{
|
||||||
|
scriptEvaluator.Run("using System;");
|
||||||
|
scriptEvaluator.Run("using System.Reflection;");
|
||||||
|
scriptEvaluator.Run("using System.Collections;");
|
||||||
|
scriptEvaluator.Run("using System.Collections.Generic;");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
|
||||||
|
public bool Enabled;
|
||||||
|
public MethodInfo TargetMethod;
|
||||||
|
public string PatchSourceCode;
|
||||||
|
|
||||||
|
private readonly string shortSignature;
|
||||||
|
private PatchProcessor patchProcessor;
|
||||||
|
|
||||||
|
private MethodInfo postfix;
|
||||||
|
private MethodInfo prefix;
|
||||||
|
private MethodInfo finalizer;
|
||||||
|
private MethodInfo transpiler;
|
||||||
|
|
||||||
|
public HookInstance(MethodInfo targetMethod)
|
||||||
|
{
|
||||||
|
this.TargetMethod = targetMethod;
|
||||||
|
this.shortSignature = $"{targetMethod.DeclaringType.Name}.{targetMethod.Name}";
|
||||||
|
|
||||||
|
GenerateDefaultPatchSourceCode(targetMethod);
|
||||||
|
|
||||||
|
if (CompileAndGenerateProcessor(PatchSourceCode))
|
||||||
|
Patch();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluator.source_file
|
||||||
|
private static readonly FieldInfo fi_sourceFile = ReflectionUtility.GetFieldInfo(typeof(Evaluator), "source_file");
|
||||||
|
// TypeDefinition.Definition
|
||||||
|
private static readonly PropertyInfo pi_Definition = ReflectionUtility.GetPropertyInfo(typeof(TypeDefinition), "Definition");
|
||||||
|
|
||||||
|
public bool CompileAndGenerateProcessor(string patchSource)
|
||||||
|
{
|
||||||
|
Unpatch();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
patchProcessor = ExplorerCore.Harmony.CreateProcessor(TargetMethod);
|
||||||
|
|
||||||
|
// Dynamically compile the patch method
|
||||||
|
|
||||||
|
var codeBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
codeBuilder.AppendLine($"public class DynamicPatch_{DateTime.Now.Ticks}");
|
||||||
|
codeBuilder.AppendLine("{");
|
||||||
|
codeBuilder.AppendLine(patchSource);
|
||||||
|
codeBuilder.AppendLine("}");
|
||||||
|
|
||||||
|
scriptEvaluator.Run(codeBuilder.ToString());
|
||||||
|
|
||||||
|
if (ScriptEvaluator._reportPrinter.ErrorsCount > 0)
|
||||||
|
throw new FormatException($"Unable to compile the generated patch!");
|
||||||
|
|
||||||
|
// TODO: Publicize MCS to avoid this reflection
|
||||||
|
// Get the most recent Patch type in the source file
|
||||||
|
var typeContainer = ((CompilationSourceFile)fi_sourceFile.GetValue(scriptEvaluator))
|
||||||
|
.Containers
|
||||||
|
.Last(it => it.MemberName.Name.StartsWith("DynamicPatch_"));
|
||||||
|
// Get the TypeSpec from the TypeDefinition, then get its "MetaInfo" (System.Type)
|
||||||
|
var patchClass = ((TypeSpec)pi_Definition.GetValue((Class)typeContainer, null)).GetMetaInfo();
|
||||||
|
|
||||||
|
// Create the harmony patches as defined
|
||||||
|
|
||||||
|
postfix = patchClass.GetMethod("Postfix", ReflectionUtility.FLAGS);
|
||||||
|
if (postfix != null)
|
||||||
|
patchProcessor.AddPostfix(new HarmonyMethod(postfix));
|
||||||
|
|
||||||
|
prefix = patchClass.GetMethod("Prefix", ReflectionUtility.FLAGS);
|
||||||
|
if (prefix != null)
|
||||||
|
patchProcessor.AddPrefix(new HarmonyMethod(prefix));
|
||||||
|
|
||||||
|
finalizer = patchClass.GetMethod("Finalizer", ReflectionUtility.FLAGS);
|
||||||
|
if (finalizer != null)
|
||||||
|
patchProcessor.AddFinalizer(new HarmonyMethod(finalizer));
|
||||||
|
|
||||||
|
transpiler = patchClass.GetMethod("Transpiler", ReflectionUtility.FLAGS);
|
||||||
|
if (transpiler != null)
|
||||||
|
patchProcessor.AddTranspiler(new HarmonyMethod(transpiler));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception creating patch processor for target method {TargetMethod.FullDescription()}!\r\n{ex}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateDefaultPatchSourceCode(MethodInfo targetMethod)
|
||||||
|
{
|
||||||
|
var codeBuilder = new StringBuilder();
|
||||||
|
// Arguments
|
||||||
|
|
||||||
|
codeBuilder.Append("public static void Postfix(System.Reflection.MethodBase __originalMethod");
|
||||||
|
|
||||||
|
if (!targetMethod.IsStatic)
|
||||||
|
codeBuilder.Append($", {targetMethod.DeclaringType.FullName} __instance");
|
||||||
|
|
||||||
|
if (targetMethod.ReturnType != typeof(void))
|
||||||
|
codeBuilder.Append($", {targetMethod.ReturnType.FullName} __result");
|
||||||
|
|
||||||
|
var parameters = targetMethod.GetParameters();
|
||||||
|
|
||||||
|
int paramIdx = 0;
|
||||||
|
foreach (var param in parameters)
|
||||||
|
{
|
||||||
|
codeBuilder.Append($", {param.ParameterType.FullDescription().Replace("&", "")} __{paramIdx}");
|
||||||
|
paramIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
codeBuilder.Append(")\n");
|
||||||
|
|
||||||
|
// Patch body
|
||||||
|
|
||||||
|
codeBuilder.AppendLine("{");
|
||||||
|
|
||||||
|
codeBuilder.AppendLine(" try {");
|
||||||
|
|
||||||
|
// Log message
|
||||||
|
|
||||||
|
var logMessage = new StringBuilder();
|
||||||
|
logMessage.Append($"Patch called: {shortSignature}\\n");
|
||||||
|
|
||||||
|
if (!targetMethod.IsStatic)
|
||||||
|
logMessage.Append("__instance: {__instance.ToString()}\\n");
|
||||||
|
|
||||||
|
paramIdx = 0;
|
||||||
|
foreach (var param in parameters)
|
||||||
|
{
|
||||||
|
logMessage.Append($"Parameter {paramIdx} {param.Name}: ");
|
||||||
|
Type pType = param.ParameterType;
|
||||||
|
if (pType.IsByRef) pType = pType.GetElementType();
|
||||||
|
if (pType.IsValueType)
|
||||||
|
logMessage.Append($"{{__{paramIdx}.ToString()}}");
|
||||||
|
else
|
||||||
|
logMessage.Append($"{{__{paramIdx}?.ToString() ?? \"null\"}}");
|
||||||
|
logMessage.Append("\\n");
|
||||||
|
paramIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetMethod.ReturnType != typeof(void))
|
||||||
|
{
|
||||||
|
logMessage.Append("Return value: ");
|
||||||
|
if (targetMethod.ReturnType.IsValueType)
|
||||||
|
logMessage.Append("{__result.ToString()}");
|
||||||
|
else
|
||||||
|
logMessage.Append("{__result?.ToString() ?? \"null\"}");
|
||||||
|
logMessage.Append("\\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.Log($\"{logMessage}\");");
|
||||||
|
codeBuilder.AppendLine(" }");
|
||||||
|
codeBuilder.AppendLine(" catch (System.Exception ex) {");
|
||||||
|
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.LogWarning($\"Exception in patch of {shortSignature}:\\n{{ex}}\");");
|
||||||
|
codeBuilder.AppendLine(" }");
|
||||||
|
|
||||||
|
// End patch body
|
||||||
|
|
||||||
|
codeBuilder.AppendLine("}");
|
||||||
|
|
||||||
|
//ExplorerCore.Log(codeBuilder.ToString());
|
||||||
|
|
||||||
|
return PatchSourceCode = codeBuilder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TogglePatch()
|
||||||
|
{
|
||||||
|
if (!Enabled)
|
||||||
|
Patch();
|
||||||
|
else
|
||||||
|
Unpatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Patch()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
patchProcessor.Patch();
|
||||||
|
|
||||||
|
Enabled = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception hooking method!\r\n{ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unpatch()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (prefix != null)
|
||||||
|
patchProcessor.Unpatch(prefix);
|
||||||
|
if (postfix != null)
|
||||||
|
patchProcessor.Unpatch(postfix);
|
||||||
|
if (finalizer != null)
|
||||||
|
patchProcessor.Unpatch(finalizer);
|
||||||
|
if (transpiler != null)
|
||||||
|
patchProcessor.Unpatch(transpiler);
|
||||||
|
|
||||||
|
Enabled = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception unpatching method: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
272
src/Hooks/HookManager.cs
Normal file
272
src/Hooks/HookManager.cs
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityExplorer.CSConsole;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
using UnityExplorer.UI.Panels;
|
||||||
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
|
namespace UnityExplorer.Hooks
|
||||||
|
{
|
||||||
|
public class HookManager : ICellPoolDataSource<HookCell>, ICellPoolDataSource<AddHookCell>
|
||||||
|
{
|
||||||
|
private static HookManager s_instance;
|
||||||
|
public static HookManager Instance => s_instance ?? (s_instance = new HookManager());
|
||||||
|
|
||||||
|
public HookManagerPanel Panel => UIManager.GetPanel<HookManagerPanel>(UIManager.Panels.HookManager);
|
||||||
|
|
||||||
|
// This class acts as the data source for both current hooks and eligable methods when adding hooks.
|
||||||
|
// 'isAddingMethods' keeps track of which pool is currently the displayed one, so our ItemCount reflects the
|
||||||
|
// correct pool cells.
|
||||||
|
private bool isAddingMethods;
|
||||||
|
public int ItemCount => isAddingMethods ? filteredEligableMethods.Count : currentHooks.Count;
|
||||||
|
|
||||||
|
// current hooks
|
||||||
|
private readonly HashSet<string> hookedSignatures = new HashSet<string>();
|
||||||
|
private readonly OrderedDictionary currentHooks = new OrderedDictionary();
|
||||||
|
|
||||||
|
// adding hooks
|
||||||
|
private readonly List<MethodInfo> currentAddEligableMethods = new List<MethodInfo>();
|
||||||
|
private readonly List<MethodInfo> filteredEligableMethods = new List<MethodInfo>();
|
||||||
|
|
||||||
|
// hook editor
|
||||||
|
private readonly LexerBuilder Lexer = new LexerBuilder();
|
||||||
|
private HookInstance currentEditedHook;
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~ Main Current Hooks window ~~~~~~~~~~~
|
||||||
|
|
||||||
|
public void EnableOrDisableHookClicked(int index)
|
||||||
|
{
|
||||||
|
var hook = (HookInstance)currentHooks[index];
|
||||||
|
hook.TogglePatch();
|
||||||
|
|
||||||
|
Panel.HooksScrollPool.Refresh(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteHookClicked(int index)
|
||||||
|
{
|
||||||
|
var hook = (HookInstance)currentHooks[index];
|
||||||
|
hook.Unpatch();
|
||||||
|
currentHooks.RemoveAt(index);
|
||||||
|
hookedSignatures.Remove(hook.TargetMethod.FullDescription());
|
||||||
|
|
||||||
|
Panel.HooksScrollPool.Refresh(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EditPatchClicked(int index)
|
||||||
|
{
|
||||||
|
Panel.SetPage(HookManagerPanel.Pages.HookSourceEditor);
|
||||||
|
var hook = (HookInstance)currentHooks[index];
|
||||||
|
currentEditedHook = hook;
|
||||||
|
Panel.EditorInput.Text = hook.PatchSourceCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set current hook cell
|
||||||
|
|
||||||
|
public void SetCell(HookCell cell, int index)
|
||||||
|
{
|
||||||
|
if (index >= this.currentHooks.Count)
|
||||||
|
{
|
||||||
|
cell.Disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.CurrentDisplayedIndex = index;
|
||||||
|
var hook = (HookInstance)this.currentHooks[index];
|
||||||
|
|
||||||
|
cell.MethodNameLabel.text = HighlightMethod(hook.TargetMethod);
|
||||||
|
|
||||||
|
cell.ToggleActiveButton.ButtonText.text = hook.Enabled ? "Enabled" : "Disabled";
|
||||||
|
RuntimeProvider.Instance.SetColorBlockAuto(cell.ToggleActiveButton.Component,
|
||||||
|
hook.Enabled ? new Color(0.15f, 0.2f, 0.15f) : new Color(0.2f, 0.2f, 0.15f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~ Add Hooks window ~~~~~~~~~~~
|
||||||
|
|
||||||
|
public void OnClassSelectedForHooks(string typeFullName)
|
||||||
|
{
|
||||||
|
var type = ReflectionUtility.GetTypeByName(typeFullName);
|
||||||
|
if (type == null)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Could not find any type by name {typeFullName}!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Panel.SetAddHooksLabelType(SignatureHighlighter.Parse(type, true));
|
||||||
|
|
||||||
|
Panel.ResetMethodFilter();
|
||||||
|
filteredEligableMethods.Clear();
|
||||||
|
currentAddEligableMethods.Clear();
|
||||||
|
foreach (var method in type.GetMethods(ReflectionUtility.FLAGS))
|
||||||
|
{
|
||||||
|
if (method.IsGenericMethod /* || method.IsAbstract */ || ReflectionUtility.IsBlacklisted(method))
|
||||||
|
continue;
|
||||||
|
currentAddEligableMethods.Add(method);
|
||||||
|
filteredEligableMethods.Add(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
isAddingMethods = true;
|
||||||
|
Panel.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
||||||
|
Panel.AddHooksScrollPool.Refresh(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DoneAddingHooks()
|
||||||
|
{
|
||||||
|
isAddingMethods = false;
|
||||||
|
Panel.SetPage(HookManagerPanel.Pages.CurrentHooks);
|
||||||
|
Panel.HooksScrollPool.Refresh(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddHookClicked(int index)
|
||||||
|
{
|
||||||
|
if (index >= this.filteredEligableMethods.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AddHook(filteredEligableMethods[index]);
|
||||||
|
Panel.AddHooksScrollPool.Refresh(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddHook(MethodInfo method)
|
||||||
|
{
|
||||||
|
var sig = method.FullDescription();
|
||||||
|
if (hookedSignatures.Contains(sig))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var hook = new HookInstance(method);
|
||||||
|
if (hook.Enabled)
|
||||||
|
{
|
||||||
|
hookedSignatures.Add(sig);
|
||||||
|
currentHooks.Add(sig, hook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnAddHookFilterInputChanged(string input)
|
||||||
|
{
|
||||||
|
filteredEligableMethods.Clear();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
filteredEligableMethods.AddRange(currentAddEligableMethods);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var method in currentAddEligableMethods)
|
||||||
|
{
|
||||||
|
if (method.Name.ContainsIgnoreCase(input))
|
||||||
|
filteredEligableMethods.Add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Panel.AddHooksScrollPool.Refresh(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~ Hook source editor window ~~~~~~~~~~~
|
||||||
|
|
||||||
|
public void OnEditorInputChanged(string value)
|
||||||
|
{
|
||||||
|
Panel.EditorHighlightText.text = Lexer.BuildHighlightedString(value, 0, value.Length - 1, 0,
|
||||||
|
Panel.EditorInput.Component.caretPosition, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EditorInputCancel()
|
||||||
|
{
|
||||||
|
currentEditedHook = null;
|
||||||
|
Panel.SetPage(HookManagerPanel.Pages.CurrentHooks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EditorInputSave()
|
||||||
|
{
|
||||||
|
var input = Panel.EditorInput.Text;
|
||||||
|
bool wasEnabled = currentEditedHook.Enabled;
|
||||||
|
if (currentEditedHook.CompileAndGenerateProcessor(input))
|
||||||
|
{
|
||||||
|
if (wasEnabled)
|
||||||
|
currentEditedHook.Patch();
|
||||||
|
currentEditedHook.PatchSourceCode = input;
|
||||||
|
currentEditedHook = null;
|
||||||
|
Panel.SetPage(HookManagerPanel.Pages.CurrentHooks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnBorrow methods not needed
|
||||||
|
public void OnCellBorrowed(HookCell cell) { }
|
||||||
|
public void OnCellBorrowed(AddHookCell cell) { }
|
||||||
|
|
||||||
|
|
||||||
|
// Set eligable method cell
|
||||||
|
|
||||||
|
public void SetCell(AddHookCell cell, int index)
|
||||||
|
{
|
||||||
|
if (index >= this.filteredEligableMethods.Count)
|
||||||
|
{
|
||||||
|
cell.Disable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.CurrentDisplayedIndex = index;
|
||||||
|
var method = this.filteredEligableMethods[index];
|
||||||
|
|
||||||
|
cell.MethodNameLabel.text = HighlightMethod(method);
|
||||||
|
|
||||||
|
var sig = method.FullDescription();
|
||||||
|
if (hookedSignatures.Contains(sig))
|
||||||
|
{
|
||||||
|
cell.HookButton.Component.gameObject.SetActive(false);
|
||||||
|
cell.HookedLabel.gameObject.SetActive(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cell.HookButton.Component.gameObject.SetActive(true);
|
||||||
|
cell.HookedLabel.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private static readonly string VOID_HIGHLIGHT = $"<color=#{SignatureHighlighter.keywordBlueHex}>void</color> ";
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> highlightedMethods = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
private string HighlightMethod(MethodInfo method)
|
||||||
|
{
|
||||||
|
var sig = method.FullDescription();
|
||||||
|
if (highlightedMethods.ContainsKey(sig))
|
||||||
|
return highlightedMethods[sig];
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
// declaring type
|
||||||
|
sb.Append(SignatureHighlighter.Parse(method.DeclaringType, false));
|
||||||
|
sb.Append('.');
|
||||||
|
|
||||||
|
// method name
|
||||||
|
var color = !method.IsStatic
|
||||||
|
? SignatureHighlighter.METHOD_INSTANCE
|
||||||
|
: SignatureHighlighter.METHOD_STATIC;
|
||||||
|
sb.Append($"<color={color}>{method.Name}</color>");
|
||||||
|
|
||||||
|
// arguments
|
||||||
|
sb.Append('(');
|
||||||
|
var args = method.GetParameters();
|
||||||
|
if (args != null && args.Any())
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
foreach (var param in args)
|
||||||
|
{
|
||||||
|
sb.Append(SignatureHighlighter.Parse(param.ParameterType, false));
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append($"<color={SignatureHighlighter.LOCAL_ARG}>{param.Name}</color>");
|
||||||
|
i++;
|
||||||
|
if (i < args.Length)
|
||||||
|
sb.Append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.Append(')');
|
||||||
|
|
||||||
|
var ret = sb.ToString();
|
||||||
|
highlightedMethods.Add(sig, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ using UnityEngine.UI;
|
|||||||
using UnityExplorer.Core;
|
using UnityExplorer.Core;
|
||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
using UnityExplorer.Core.Runtime;
|
using UnityExplorer.Core.Runtime;
|
||||||
|
using UnityExplorer.Inspectors.MouseInspectors;
|
||||||
using UnityExplorer.UI;
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
|
|
||||||
@ -23,17 +24,27 @@ namespace UnityExplorer.Inspectors
|
|||||||
{
|
{
|
||||||
public static InspectUnderMouse Instance { get; private set; }
|
public static InspectUnderMouse Instance { get; private set; }
|
||||||
|
|
||||||
public InspectUnderMouse() { Instance = this; }
|
private readonly WorldInspector worldInspector;
|
||||||
|
private readonly UiInspector uiInspector;
|
||||||
|
|
||||||
public static void OnDropdownSelect(int index)
|
public static bool Inspecting { get; set; }
|
||||||
|
public static MouseInspectMode Mode { get; set; }
|
||||||
|
|
||||||
|
private static Vector3 lastMousePos;
|
||||||
|
|
||||||
|
public MouseInspectorBase CurrentInspector
|
||||||
{
|
{
|
||||||
switch (index)
|
get
|
||||||
{
|
{
|
||||||
case 0: return;
|
switch (Mode)
|
||||||
case 1: Instance.StartInspect(MouseInspectMode.World); break;
|
{
|
||||||
case 2: Instance.StartInspect(MouseInspectMode.UI); break;
|
case MouseInspectMode.UI:
|
||||||
|
return uiInspector;
|
||||||
|
case MouseInspectMode.World:
|
||||||
|
return worldInspector;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
UIManager.MouseInspectDropdown.value = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UIPanel
|
// UIPanel
|
||||||
@ -46,56 +57,54 @@ namespace UnityExplorer.Inspectors
|
|||||||
public override bool ShouldSaveActiveState => false;
|
public override bool ShouldSaveActiveState => false;
|
||||||
public override bool ShowByDefault => false;
|
public override bool ShowByDefault => false;
|
||||||
|
|
||||||
internal static Text objNameLabel;
|
internal Text objNameLabel;
|
||||||
internal static Text objPathLabel;
|
internal Text objPathLabel;
|
||||||
internal static Text mousePosLabel;
|
internal Text mousePosLabel;
|
||||||
|
|
||||||
// Mouse Inspector
|
public InspectUnderMouse()
|
||||||
public static bool Inspecting { get; set; }
|
{
|
||||||
public static MouseInspectMode Mode { get; set; }
|
Instance = this;
|
||||||
|
worldInspector = new WorldInspector();
|
||||||
|
uiInspector = new UiInspector();
|
||||||
|
}
|
||||||
|
|
||||||
private static GameObject lastHitObject;
|
public static void OnDropdownSelect(int index)
|
||||||
private static Vector3 lastMousePos;
|
{
|
||||||
|
switch (index)
|
||||||
private static readonly List<Graphic> wasDisabledGraphics = new List<Graphic>();
|
{
|
||||||
private static readonly List<CanvasGroup> wasDisabledCanvasGroups = new List<CanvasGroup>();
|
case 0: return;
|
||||||
private static readonly List<GameObject> objectsAddedCastersTo = new List<GameObject>();
|
case 1: Instance.StartInspect(MouseInspectMode.World); break;
|
||||||
|
case 2: Instance.StartInspect(MouseInspectMode.UI); break;
|
||||||
internal static Camera MainCamera;
|
}
|
||||||
internal static GraphicRaycaster[] graphicRaycasters;
|
UIManager.MouseInspectDropdown.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void StartInspect(MouseInspectMode mode)
|
public void StartInspect(MouseInspectMode mode)
|
||||||
{
|
{
|
||||||
MainCamera = Camera.main;
|
|
||||||
|
|
||||||
if (!MainCamera && mode == MouseInspectMode.World)
|
|
||||||
{
|
|
||||||
ExplorerCore.LogWarning("No MainCamera found! Cannot inspect world!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PanelDragger.ForceEnd();
|
|
||||||
|
|
||||||
Mode = mode;
|
Mode = mode;
|
||||||
Inspecting = true;
|
Inspecting = true;
|
||||||
|
|
||||||
|
CurrentInspector.OnBeginMouseInspect();
|
||||||
|
|
||||||
|
PanelDragger.ForceEnd();
|
||||||
UIManager.NavBarRect.gameObject.SetActive(false);
|
UIManager.NavBarRect.gameObject.SetActive(false);
|
||||||
UIManager.PanelHolder.SetActive(false);
|
UIManager.PanelHolder.SetActive(false);
|
||||||
|
|
||||||
UIRoot.SetActive(true);
|
UIRoot.SetActive(true);
|
||||||
|
|
||||||
if (mode == MouseInspectMode.UI)
|
|
||||||
SetupUIRaycast();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ClearHitData()
|
internal void ClearHitData()
|
||||||
{
|
{
|
||||||
lastHitObject = null;
|
CurrentInspector.ClearHitData();
|
||||||
|
|
||||||
objNameLabel.text = "No hits...";
|
objNameLabel.text = "No hits...";
|
||||||
objPathLabel.text = "";
|
objPathLabel.text = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopInspect()
|
public void StopInspect()
|
||||||
{
|
{
|
||||||
|
CurrentInspector.OnEndInspect();
|
||||||
|
ClearHitData();
|
||||||
Inspecting = false;
|
Inspecting = false;
|
||||||
|
|
||||||
UIManager.NavBarRect.gameObject.SetActive(true);
|
UIManager.NavBarRect.gameObject.SetActive(true);
|
||||||
@ -106,11 +115,6 @@ namespace UnityExplorer.Inspectors
|
|||||||
drop.DestroyDropdownList(list.gameObject);
|
drop.DestroyDropdownList(list.gameObject);
|
||||||
|
|
||||||
UIRoot.SetActive(false);
|
UIRoot.SetActive(false);
|
||||||
|
|
||||||
if (Mode == MouseInspectMode.UI)
|
|
||||||
StopUIInspect();
|
|
||||||
|
|
||||||
ClearHitData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float timeOfLastRaycast;
|
private static float timeOfLastRaycast;
|
||||||
@ -123,33 +127,22 @@ namespace UnityExplorer.Inspectors
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastHitObject && InputManager.GetMouseButtonDown(0))
|
if (InputManager.GetMouseButtonDown(0))
|
||||||
{
|
{
|
||||||
var target = lastHitObject;
|
CurrentInspector.OnSelectMouseInspect();
|
||||||
StopInspect();
|
StopInspect();
|
||||||
InspectorManager.Inspect(target);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mousePos = InputManager.MousePosition;
|
var mousePos = InputManager.MousePosition;
|
||||||
|
|
||||||
if (mousePos != lastMousePos)
|
if (mousePos != lastMousePos)
|
||||||
UpdatePosition(mousePos);
|
UpdatePosition(mousePos);
|
||||||
|
|
||||||
if (!timeOfLastRaycast.OccuredEarlierThan(0.1f))
|
if (!timeOfLastRaycast.OccuredEarlierThan(0.1f))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
timeOfLastRaycast = Time.realtimeSinceStartup;
|
timeOfLastRaycast = Time.realtimeSinceStartup;
|
||||||
|
|
||||||
// actual inspect raycast
|
CurrentInspector.UpdateMouseInspect(mousePos);
|
||||||
|
|
||||||
switch (Mode)
|
|
||||||
{
|
|
||||||
case MouseInspectMode.UI:
|
|
||||||
RaycastUI(mousePos); break;
|
|
||||||
case MouseInspectMode.World:
|
|
||||||
RaycastWorld(mousePos); break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void UpdatePosition(Vector2 mousePos)
|
internal void UpdatePosition(Vector2 mousePos)
|
||||||
@ -171,181 +164,9 @@ namespace UnityExplorer.Inspectors
|
|||||||
|
|
||||||
// calculate and set our UI position
|
// calculate and set our UI position
|
||||||
var inversePos = UIManager.CanvasRoot.transform.InverseTransformPoint(mousePos);
|
var inversePos = UIManager.CanvasRoot.transform.InverseTransformPoint(mousePos);
|
||||||
|
|
||||||
UIRoot.transform.localPosition = new Vector3(inversePos.x, inversePos.y, 0);
|
UIRoot.transform.localPosition = new Vector3(inversePos.x, inversePos.y, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnHitGameObject(GameObject obj)
|
|
||||||
{
|
|
||||||
if (obj != lastHitObject)
|
|
||||||
{
|
|
||||||
lastHitObject = obj;
|
|
||||||
objNameLabel.text = $"<b>Click to Inspect:</b> <color=cyan>{obj.name}</color>";
|
|
||||||
objPathLabel.text = $"Path: {obj.transform.GetTransformPath(true)}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collider raycasting
|
|
||||||
|
|
||||||
internal void RaycastWorld(Vector2 mousePos)
|
|
||||||
{
|
|
||||||
var ray = MainCamera.ScreenPointToRay(mousePos);
|
|
||||||
Physics.Raycast(ray, out RaycastHit hit, 1000f);
|
|
||||||
|
|
||||||
if (hit.transform)
|
|
||||||
{
|
|
||||||
var obj = hit.transform.gameObject;
|
|
||||||
OnHitGameObject(obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (lastHitObject)
|
|
||||||
ClearHitData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI Graphic raycasting
|
|
||||||
|
|
||||||
private static void SetupUIRaycast()
|
|
||||||
{
|
|
||||||
foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(Canvas)))
|
|
||||||
{
|
|
||||||
var canvas = obj.TryCast<Canvas>();
|
|
||||||
if (!canvas || !canvas.enabled || !canvas.gameObject.activeInHierarchy)
|
|
||||||
continue;
|
|
||||||
if (!canvas.GetComponent<GraphicRaycaster>())
|
|
||||||
{
|
|
||||||
canvas.gameObject.AddComponent<GraphicRaycaster>();
|
|
||||||
//ExplorerCore.Log("Added raycaster to " + canvas.name);
|
|
||||||
objectsAddedCastersTo.Add(canvas.gameObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// recache Graphic Raycasters each time we start
|
|
||||||
var casters = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GraphicRaycaster));
|
|
||||||
graphicRaycasters = new GraphicRaycaster[casters.Length];
|
|
||||||
for (int i = 0; i < casters.Length; i++)
|
|
||||||
{
|
|
||||||
graphicRaycasters[i] = casters[i].TryCast<GraphicRaycaster>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable raycastTarget on Graphics
|
|
||||||
foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(Graphic)))
|
|
||||||
{
|
|
||||||
var graphic = obj.TryCast<Graphic>();
|
|
||||||
if (!graphic || !graphic.enabled || graphic.raycastTarget || !graphic.gameObject.activeInHierarchy)
|
|
||||||
continue;
|
|
||||||
graphic.raycastTarget = true;
|
|
||||||
//ExplorerCore.Log("Enabled raycastTarget on " + graphic.name);
|
|
||||||
wasDisabledGraphics.Add(graphic);
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable blocksRaycasts on CanvasGroups
|
|
||||||
foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(CanvasGroup)))
|
|
||||||
{
|
|
||||||
var canvas = obj.TryCast<CanvasGroup>();
|
|
||||||
if (!canvas || !canvas.gameObject.activeInHierarchy || canvas.blocksRaycasts)
|
|
||||||
continue;
|
|
||||||
canvas.blocksRaycasts = true;
|
|
||||||
//ExplorerCore.Log("Enabled raycasts on " + canvas.name);
|
|
||||||
wasDisabledCanvasGroups.Add(canvas);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void RaycastUI(Vector2 mousePos)
|
|
||||||
{
|
|
||||||
var ped = new PointerEventData(null)
|
|
||||||
{
|
|
||||||
position = mousePos
|
|
||||||
};
|
|
||||||
|
|
||||||
//ExplorerCore.Log("~~~~~~~~~ begin raycast ~~~~~~~~");
|
|
||||||
GameObject hitObject = null;
|
|
||||||
int highestLayer = int.MinValue;
|
|
||||||
int highestOrder = int.MinValue;
|
|
||||||
int highestDepth = int.MinValue;
|
|
||||||
foreach (var gr in graphicRaycasters)
|
|
||||||
{
|
|
||||||
if (!gr || !gr.canvas)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var list = new List<RaycastResult>();
|
|
||||||
RuntimeProvider.Instance.GraphicRaycast(gr, ped, list);
|
|
||||||
|
|
||||||
if (list.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var hit in list)
|
|
||||||
{
|
|
||||||
// Manualy trying to determine which object is "on top".
|
|
||||||
// Could be improved, but seems to work pretty well and isn't as laggy as you would expect.
|
|
||||||
|
|
||||||
if (!hit.gameObject)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (hit.gameObject.GetComponent<CanvasGroup>() is CanvasGroup group && group.alpha == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (hit.gameObject.GetComponent<Graphic>() is Graphic graphic && graphic.color.a == 0f)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (hit.sortingLayer < highestLayer)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (hit.sortingLayer > highestLayer)
|
|
||||||
{
|
|
||||||
highestLayer = hit.sortingLayer;
|
|
||||||
highestDepth = int.MinValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit.depth < highestDepth)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (hit.depth > highestDepth)
|
|
||||||
{
|
|
||||||
highestDepth = hit.depth;
|
|
||||||
highestOrder = int.MinValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit.sortingOrder <= highestOrder)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
highestOrder = hit.sortingOrder;
|
|
||||||
hitObject = hit.gameObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (lastHitObject)
|
|
||||||
ClearHitData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hitObject)
|
|
||||||
OnHitGameObject(hitObject);
|
|
||||||
|
|
||||||
//ExplorerCore.Log("~~~~~~~~~ end raycast ~~~~~~~~");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void StopUIInspect()
|
|
||||||
{
|
|
||||||
foreach (var obj in objectsAddedCastersTo)
|
|
||||||
{
|
|
||||||
if (obj.GetComponent<GraphicRaycaster>() is GraphicRaycaster raycaster)
|
|
||||||
GameObject.Destroy(raycaster);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var graphic in wasDisabledGraphics)
|
|
||||||
graphic.raycastTarget = false;
|
|
||||||
|
|
||||||
foreach (var canvas in wasDisabledCanvasGroups)
|
|
||||||
canvas.blocksRaycasts = false;
|
|
||||||
|
|
||||||
objectsAddedCastersTo.Clear();
|
|
||||||
wasDisabledCanvasGroups.Clear();
|
|
||||||
wasDisabledGraphics.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// UI Construction
|
// UI Construction
|
||||||
|
|
||||||
protected internal override void DoSetDefaultPosAndAnchors()
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
@ -367,7 +188,10 @@ namespace UnityExplorer.Inspectors
|
|||||||
|
|
||||||
// Title text
|
// Title text
|
||||||
|
|
||||||
var title = UIFactory.CreateLabel(inspectContent, "InspectLabel", "<b>Mouse Inspector</b> (press <b>ESC</b> to cancel)", TextAnchor.MiddleCenter);
|
var title = UIFactory.CreateLabel(inspectContent,
|
||||||
|
"InspectLabel",
|
||||||
|
"<b>Mouse Inspector</b> (press <b>ESC</b> to cancel)",
|
||||||
|
TextAnchor.MiddleCenter);
|
||||||
UIFactory.SetLayoutElement(title.gameObject, flexibleWidth: 9999);
|
UIFactory.SetLayoutElement(title.gameObject, flexibleWidth: 9999);
|
||||||
|
|
||||||
mousePosLabel = UIFactory.CreateLabel(inspectContent, "MousePosLabel", "Mouse Position:", TextAnchor.MiddleCenter);
|
mousePosLabel = UIFactory.CreateLabel(inspectContent, "MousePosLabel", "Mouse Position:", TextAnchor.MiddleCenter);
|
||||||
|
@ -21,19 +21,6 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
public static float PanelWidth;
|
public static float PanelWidth;
|
||||||
|
|
||||||
internal static void CloseAllTabs()
|
|
||||||
{
|
|
||||||
if (Inspectors.Any())
|
|
||||||
{
|
|
||||||
for (int i = Inspectors.Count - 1; i >= 0; i--)
|
|
||||||
Inspectors[i].CloseInspector();
|
|
||||||
|
|
||||||
Inspectors.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
UIManager.SetPanelActive(UIManager.Panels.Inspector, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Inspect(object obj, CacheObjectBase sourceCache = null)
|
public static void Inspect(object obj, CacheObjectBase sourceCache = null)
|
||||||
{
|
{
|
||||||
if (obj.IsNullOrDestroyed())
|
if (obj.IsNullOrDestroyed())
|
||||||
@ -50,6 +37,11 @@ namespace UnityExplorer
|
|||||||
CreateInspector<ReflectionInspector>(obj, false, sourceCache);
|
CreateInspector<ReflectionInspector>(obj, false, sourceCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Inspect(Type type)
|
||||||
|
{
|
||||||
|
CreateInspector<ReflectionInspector>(type, true);
|
||||||
|
}
|
||||||
|
|
||||||
private static bool TryFocusActiveInspector(object target)
|
private static bool TryFocusActiveInspector(object target)
|
||||||
{
|
{
|
||||||
foreach (var inspector in Inspectors)
|
foreach (var inspector in Inspectors)
|
||||||
@ -64,11 +56,6 @@ namespace UnityExplorer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Inspect(Type type)
|
|
||||||
{
|
|
||||||
CreateInspector<ReflectionInspector>(type, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetInspectorActive(InspectorBase inspector)
|
public static void SetInspectorActive(InspectorBase inspector)
|
||||||
{
|
{
|
||||||
UnsetActiveInspector();
|
UnsetActiveInspector();
|
||||||
@ -87,6 +74,19 @@ namespace UnityExplorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void CloseAllTabs()
|
||||||
|
{
|
||||||
|
if (Inspectors.Any())
|
||||||
|
{
|
||||||
|
for (int i = Inspectors.Count - 1; i >= 0; i--)
|
||||||
|
Inspectors[i].CloseInspector();
|
||||||
|
|
||||||
|
Inspectors.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
UIManager.SetPanelActive(UIManager.Panels.Inspector, false);
|
||||||
|
}
|
||||||
|
|
||||||
private static void CreateInspector<T>(object target, bool staticReflection = false,
|
private static void CreateInspector<T>(object target, bool staticReflection = false,
|
||||||
CacheObjectBase sourceCache = null) where T : InspectorBase
|
CacheObjectBase sourceCache = null) where T : InspectorBase
|
||||||
{
|
{
|
||||||
|
21
src/Inspectors/MouseInspectors/MouseInspectorBase.cs
Normal file
21
src/Inspectors/MouseInspectors/MouseInspectorBase.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace UnityExplorer.Inspectors.MouseInspectors
|
||||||
|
{
|
||||||
|
public abstract class MouseInspectorBase
|
||||||
|
{
|
||||||
|
public abstract void OnBeginMouseInspect();
|
||||||
|
|
||||||
|
public abstract void UpdateMouseInspect(Vector2 mousePos);
|
||||||
|
|
||||||
|
public abstract void OnSelectMouseInspect();
|
||||||
|
|
||||||
|
public abstract void ClearHitData();
|
||||||
|
|
||||||
|
public abstract void OnEndInspect();
|
||||||
|
}
|
||||||
|
}
|
142
src/Inspectors/MouseInspectors/UiInspector.cs
Normal file
142
src/Inspectors/MouseInspectors/UiInspector.cs
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
using UnityExplorer.UI.Panels;
|
||||||
|
|
||||||
|
namespace UnityExplorer.Inspectors.MouseInspectors
|
||||||
|
{
|
||||||
|
public class UiInspector : MouseInspectorBase
|
||||||
|
{
|
||||||
|
public static readonly List<GameObject> LastHitObjects = new List<GameObject>();
|
||||||
|
|
||||||
|
private static GraphicRaycaster[] graphicRaycasters;
|
||||||
|
|
||||||
|
private static readonly List<GameObject> currentHitObjects = new List<GameObject>();
|
||||||
|
|
||||||
|
private static readonly List<Graphic> wasDisabledGraphics = new List<Graphic>();
|
||||||
|
private static readonly List<CanvasGroup> wasDisabledCanvasGroups = new List<CanvasGroup>();
|
||||||
|
private static readonly List<GameObject> objectsAddedCastersTo = new List<GameObject>();
|
||||||
|
|
||||||
|
public override void OnBeginMouseInspect()
|
||||||
|
{
|
||||||
|
SetupUIRaycast();
|
||||||
|
InspectUnderMouse.Instance.objPathLabel.text = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ClearHitData()
|
||||||
|
{
|
||||||
|
currentHitObjects.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSelectMouseInspect()
|
||||||
|
{
|
||||||
|
LastHitObjects.Clear();
|
||||||
|
LastHitObjects.AddRange(currentHitObjects);
|
||||||
|
var panel = UIManager.GetPanel<UiInspectorResultsPanel>(UIManager.Panels.UIInspectorResults);
|
||||||
|
panel.SetActive(true);
|
||||||
|
panel.ShowResults();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateMouseInspect(Vector2 mousePos)
|
||||||
|
{
|
||||||
|
currentHitObjects.Clear();
|
||||||
|
|
||||||
|
var ped = new PointerEventData(null)
|
||||||
|
{
|
||||||
|
position = mousePos
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var gr in graphicRaycasters)
|
||||||
|
{
|
||||||
|
if (!gr || !gr.canvas)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var list = new List<RaycastResult>();
|
||||||
|
RuntimeProvider.Instance.GraphicRaycast(gr, ped, list);
|
||||||
|
if (list.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var hit in list)
|
||||||
|
{
|
||||||
|
if (hit.gameObject)
|
||||||
|
currentHitObjects.Add(hit.gameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentHitObjects.Any())
|
||||||
|
InspectUnderMouse.Instance.objNameLabel.text = $"Click to view UI Objects under mouse: {currentHitObjects.Count}";
|
||||||
|
else
|
||||||
|
InspectUnderMouse.Instance.objNameLabel.text = $"No UI objects under mouse.";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetupUIRaycast()
|
||||||
|
{
|
||||||
|
foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(Canvas)))
|
||||||
|
{
|
||||||
|
var canvas = obj.TryCast<Canvas>();
|
||||||
|
if (!canvas || !canvas.enabled || !canvas.gameObject.activeInHierarchy)
|
||||||
|
continue;
|
||||||
|
if (!canvas.GetComponent<GraphicRaycaster>())
|
||||||
|
{
|
||||||
|
canvas.gameObject.AddComponent<GraphicRaycaster>();
|
||||||
|
//ExplorerCore.Log("Added raycaster to " + canvas.name);
|
||||||
|
objectsAddedCastersTo.Add(canvas.gameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recache Graphic Raycasters each time we start
|
||||||
|
var casters = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GraphicRaycaster));
|
||||||
|
graphicRaycasters = new GraphicRaycaster[casters.Length];
|
||||||
|
for (int i = 0; i < casters.Length; i++)
|
||||||
|
{
|
||||||
|
graphicRaycasters[i] = casters[i].TryCast<GraphicRaycaster>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable raycastTarget on Graphics
|
||||||
|
foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(Graphic)))
|
||||||
|
{
|
||||||
|
var graphic = obj.TryCast<Graphic>();
|
||||||
|
if (!graphic || !graphic.enabled || graphic.raycastTarget || !graphic.gameObject.activeInHierarchy)
|
||||||
|
continue;
|
||||||
|
graphic.raycastTarget = true;
|
||||||
|
//ExplorerCore.Log("Enabled raycastTarget on " + graphic.name);
|
||||||
|
wasDisabledGraphics.Add(graphic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable blocksRaycasts on CanvasGroups
|
||||||
|
foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(CanvasGroup)))
|
||||||
|
{
|
||||||
|
var canvas = obj.TryCast<CanvasGroup>();
|
||||||
|
if (!canvas || !canvas.gameObject.activeInHierarchy || canvas.blocksRaycasts)
|
||||||
|
continue;
|
||||||
|
canvas.blocksRaycasts = true;
|
||||||
|
//ExplorerCore.Log("Enabled raycasts on " + canvas.name);
|
||||||
|
wasDisabledCanvasGroups.Add(canvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnEndInspect()
|
||||||
|
{
|
||||||
|
foreach (var obj in objectsAddedCastersTo)
|
||||||
|
{
|
||||||
|
if (obj.GetComponent<GraphicRaycaster>() is GraphicRaycaster raycaster)
|
||||||
|
GameObject.Destroy(raycaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var graphic in wasDisabledGraphics)
|
||||||
|
graphic.raycastTarget = false;
|
||||||
|
|
||||||
|
foreach (var canvas in wasDisabledCanvasGroups)
|
||||||
|
canvas.blocksRaycasts = false;
|
||||||
|
|
||||||
|
objectsAddedCastersTo.Clear();
|
||||||
|
wasDisabledCanvasGroups.Clear();
|
||||||
|
wasDisabledGraphics.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
61
src/Inspectors/MouseInspectors/WorldInspector.cs
Normal file
61
src/Inspectors/MouseInspectors/WorldInspector.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace UnityExplorer.Inspectors.MouseInspectors
|
||||||
|
{
|
||||||
|
public class WorldInspector : MouseInspectorBase
|
||||||
|
{
|
||||||
|
private static Camera MainCamera;
|
||||||
|
private static GameObject lastHitObject;
|
||||||
|
|
||||||
|
public override void OnBeginMouseInspect()
|
||||||
|
{
|
||||||
|
MainCamera = Camera.main;
|
||||||
|
|
||||||
|
if (!MainCamera)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning("No MainCamera found! Cannot inspect world!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ClearHitData()
|
||||||
|
{
|
||||||
|
lastHitObject = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnSelectMouseInspect()
|
||||||
|
{
|
||||||
|
InspectorManager.Inspect(lastHitObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateMouseInspect(Vector2 mousePos)
|
||||||
|
{
|
||||||
|
var ray = MainCamera.ScreenPointToRay(mousePos);
|
||||||
|
Physics.Raycast(ray, out RaycastHit hit, 1000f);
|
||||||
|
|
||||||
|
if (hit.transform)
|
||||||
|
OnHitGameObject(hit.transform.gameObject);
|
||||||
|
else if (lastHitObject)
|
||||||
|
InspectUnderMouse.Instance.ClearHitData();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void OnHitGameObject(GameObject obj)
|
||||||
|
{
|
||||||
|
if (obj != lastHitObject)
|
||||||
|
{
|
||||||
|
lastHitObject = obj;
|
||||||
|
InspectUnderMouse.Instance.objNameLabel.text = $"<b>Click to Inspect:</b> <color=cyan>{obj.name}</color>";
|
||||||
|
InspectUnderMouse.Instance.objPathLabel.text = $"Path: {obj.transform.GetTransformPath(true)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnEndInspect()
|
||||||
|
{
|
||||||
|
// not needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,16 +2,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.EventSystems;
|
|
||||||
using UnityExplorer;
|
using UnityExplorer;
|
||||||
using UnityExplorer.Core;
|
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.Core.Input;
|
|
||||||
using UnityExplorer.Loader.ML;
|
using UnityExplorer.Loader.ML;
|
||||||
using HarmonyLib;
|
|
||||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
|
|
||||||
|
|
||||||
|
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
|
||||||
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
|
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
|
||||||
[assembly: MelonGame(null, null)]
|
[assembly: MelonGame(null, null)]
|
||||||
[assembly: MelonColor(ConsoleColor.DarkCyan)]
|
[assembly: MelonColor(ConsoleColor.DarkCyan)]
|
||||||
@ -22,7 +17,7 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
public static ExplorerMelonMod Instance;
|
public static ExplorerMelonMod Instance;
|
||||||
|
|
||||||
public string ExplorerFolder => Path.Combine("Mods", ExplorerCore.NAME);
|
public string ExplorerFolder => Path.Combine(MelonHandler.ModsDirectory, ExplorerCore.NAME);
|
||||||
|
|
||||||
public string UnhollowedModulesFolder => Path.Combine(
|
public string UnhollowedModulesFolder => Path.Combine(
|
||||||
Path.GetDirectoryName(MelonHandler.ModsDirectory),
|
Path.GetDirectoryName(MelonHandler.ModsDirectory),
|
||||||
|
203
src/UI/Panels/HookManagerPanel.cs
Normal file
203
src/UI/Panels/HookManagerPanel.cs
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using UnityExplorer.Core.Config;
|
||||||
|
using UnityExplorer.Hooks;
|
||||||
|
using UnityExplorer.UI.Widgets;
|
||||||
|
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||||
|
|
||||||
|
namespace UnityExplorer.UI.Panels
|
||||||
|
{
|
||||||
|
public class HookManagerPanel : UIPanel
|
||||||
|
{
|
||||||
|
public enum Pages
|
||||||
|
{
|
||||||
|
CurrentHooks,
|
||||||
|
ClassMethodSelector,
|
||||||
|
HookSourceEditor
|
||||||
|
}
|
||||||
|
|
||||||
|
public override UIManager.Panels PanelType => UIManager.Panels.HookManager;
|
||||||
|
|
||||||
|
public override string Name => "Hooks";
|
||||||
|
public override int MinWidth => 500;
|
||||||
|
public override int MinHeight => 600;
|
||||||
|
public override bool ShowByDefault => false;
|
||||||
|
|
||||||
|
public Pages CurrentPage { get; private set; } = Pages.CurrentHooks;
|
||||||
|
|
||||||
|
private GameObject currentHooksPanel;
|
||||||
|
public ScrollPool<HookCell> HooksScrollPool;
|
||||||
|
private InputFieldRef classSelectorInputField;
|
||||||
|
|
||||||
|
private GameObject addHooksPanel;
|
||||||
|
public ScrollPool<AddHookCell> AddHooksScrollPool;
|
||||||
|
private Text addHooksLabel;
|
||||||
|
private InputFieldRef AddHooksMethodFilterInput;
|
||||||
|
|
||||||
|
private GameObject editorPanel;
|
||||||
|
public InputFieldScroller EditorInputScroller { get; private set; }
|
||||||
|
public InputFieldRef EditorInput => EditorInputScroller.InputField;
|
||||||
|
public Text EditorInputText { get; private set; }
|
||||||
|
public Text EditorHighlightText { get; private set; }
|
||||||
|
|
||||||
|
public override string GetSaveDataFromConfigManager() => ConfigManager.HookManagerData.Value;
|
||||||
|
|
||||||
|
public override void DoSaveToConfigElement() => ConfigManager.HookManagerData.Value = this.ToSaveData();
|
||||||
|
|
||||||
|
private void OnClassInputAddClicked()
|
||||||
|
{
|
||||||
|
HookManager.Instance.OnClassSelectedForHooks(this.classSelectorInputField.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAddHooksLabelType(string typeText) => addHooksLabel.text = $"Adding hooks to: {typeText}";
|
||||||
|
|
||||||
|
public void SetPage(Pages page)
|
||||||
|
{
|
||||||
|
switch (page)
|
||||||
|
{
|
||||||
|
case Pages.CurrentHooks:
|
||||||
|
currentHooksPanel.SetActive(true);
|
||||||
|
addHooksPanel.SetActive(false);
|
||||||
|
editorPanel.SetActive(false);
|
||||||
|
break;
|
||||||
|
case Pages.ClassMethodSelector:
|
||||||
|
currentHooksPanel.SetActive(false);
|
||||||
|
addHooksPanel.SetActive(true);
|
||||||
|
editorPanel.SetActive(false);
|
||||||
|
break;
|
||||||
|
case Pages.HookSourceEditor:
|
||||||
|
currentHooksPanel.SetActive(false);
|
||||||
|
addHooksPanel.SetActive(false);
|
||||||
|
editorPanel.SetActive(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetMethodFilter() => AddHooksMethodFilterInput.Text = string.Empty;
|
||||||
|
|
||||||
|
public override void ConstructPanelContent()
|
||||||
|
{
|
||||||
|
// ~~~~~~~~~ Active hooks scroll pool
|
||||||
|
|
||||||
|
currentHooksPanel = UIFactory.CreateUIObject("CurrentHooksPanel", this.content);
|
||||||
|
UIFactory.SetLayoutElement(currentHooksPanel, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||||
|
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(currentHooksPanel, true, true, true, true);
|
||||||
|
|
||||||
|
var addRow = UIFactory.CreateHorizontalGroup(currentHooksPanel, "AddRow", false, true, true, true, 4,
|
||||||
|
new Vector4(2, 2, 2, 2), new Color(0.2f, 0.2f, 0.2f));
|
||||||
|
UIFactory.SetLayoutElement(addRow, minHeight: 30, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
classSelectorInputField = UIFactory.CreateInputField(addRow, "ClassInput", "Enter a class to add hooks to...");
|
||||||
|
UIFactory.SetLayoutElement(classSelectorInputField.Component.gameObject, flexibleWidth: 9999);
|
||||||
|
new TypeCompleter(typeof(object), classSelectorInputField, true, false);
|
||||||
|
|
||||||
|
var addButton = UIFactory.CreateButton(addRow, "AddButton", "Add Hooks");
|
||||||
|
UIFactory.SetLayoutElement(addButton.Component.gameObject, minWidth: 100, minHeight: 25);
|
||||||
|
addButton.OnClick += OnClassInputAddClicked;
|
||||||
|
|
||||||
|
var hooksLabel = UIFactory.CreateLabel(currentHooksPanel, "HooksLabel", "Current Hooks", TextAnchor.MiddleCenter);
|
||||||
|
UIFactory.SetLayoutElement(hooksLabel.gameObject, minHeight: 30, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
HooksScrollPool = UIFactory.CreateScrollPool<HookCell>(currentHooksPanel, "HooksScrollPool",
|
||||||
|
out GameObject hooksScroll, out GameObject hooksContent);
|
||||||
|
UIFactory.SetLayoutElement(hooksScroll, flexibleHeight: 9999);
|
||||||
|
HooksScrollPool.Initialize(HookManager.Instance);
|
||||||
|
|
||||||
|
// ~~~~~~~~~ Add hooks panel
|
||||||
|
|
||||||
|
addHooksPanel = UIFactory.CreateUIObject("AddHooksPanel", this.content);
|
||||||
|
UIFactory.SetLayoutElement(addHooksPanel, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||||
|
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(addHooksPanel, true, true, true, true);
|
||||||
|
|
||||||
|
addHooksLabel = UIFactory.CreateLabel(addHooksPanel, "AddLabel", "NOT SET", TextAnchor.MiddleCenter);
|
||||||
|
UIFactory.SetLayoutElement(addHooksLabel.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
var buttonRow = UIFactory.CreateHorizontalGroup(addHooksPanel, "ButtonRow", false, false, true, true, 5);
|
||||||
|
UIFactory.SetLayoutElement(buttonRow, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
var doneButton = UIFactory.CreateButton(buttonRow, "DoneButton", "Done", new Color(0.2f, 0.3f, 0.2f));
|
||||||
|
UIFactory.SetLayoutElement(doneButton.Component.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
doneButton.OnClick += HookManager.Instance.DoneAddingHooks;
|
||||||
|
|
||||||
|
AddHooksMethodFilterInput = UIFactory.CreateInputField(addHooksPanel, "FilterInputField", "Filter method names...");
|
||||||
|
UIFactory.SetLayoutElement(AddHooksMethodFilterInput.Component.gameObject, minHeight: 30, flexibleWidth: 9999);
|
||||||
|
AddHooksMethodFilterInput.OnValueChanged += HookManager.Instance.OnAddHookFilterInputChanged;
|
||||||
|
|
||||||
|
AddHooksScrollPool = UIFactory.CreateScrollPool<AddHookCell>(addHooksPanel, "MethodAddScrollPool",
|
||||||
|
out GameObject addScrollRoot, out GameObject addContent);
|
||||||
|
UIFactory.SetLayoutElement(addScrollRoot, flexibleHeight: 9999);
|
||||||
|
AddHooksScrollPool.Initialize(HookManager.Instance);
|
||||||
|
|
||||||
|
addHooksPanel.gameObject.SetActive(false);
|
||||||
|
|
||||||
|
// ~~~~~~~~~ Hook source editor panel
|
||||||
|
|
||||||
|
editorPanel = UIFactory.CreateUIObject("HookSourceEditor", this.content);
|
||||||
|
UIFactory.SetLayoutElement(editorPanel, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||||
|
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(editorPanel, true, true, true, true);
|
||||||
|
|
||||||
|
var editorLabel = UIFactory.CreateLabel(editorPanel,
|
||||||
|
"EditorLabel",
|
||||||
|
"Edit Harmony patch source as desired. Accepted method names are Prefix, Postfix, Finalizer and Transpiler (can define multiple).\n\n" +
|
||||||
|
"Hooks are temporary! Please copy the source into your IDE to avoid losing work if you wish to keep it!",
|
||||||
|
TextAnchor.MiddleLeft);
|
||||||
|
UIFactory.SetLayoutElement(editorLabel.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
var editorButtonRow = UIFactory.CreateHorizontalGroup(editorPanel, "ButtonRow", false, false, true, true, 5);
|
||||||
|
UIFactory.SetLayoutElement(editorButtonRow, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
var editorSaveButton = UIFactory.CreateButton(editorButtonRow, "DoneButton", "Save and Return", new Color(0.2f, 0.3f, 0.2f));
|
||||||
|
UIFactory.SetLayoutElement(editorSaveButton.Component.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
editorSaveButton.OnClick += HookManager.Instance.EditorInputSave;
|
||||||
|
|
||||||
|
var editorDoneButton = UIFactory.CreateButton(editorButtonRow, "DoneButton", "Cancel and Return", new Color(0.2f, 0.2f, 0.2f));
|
||||||
|
UIFactory.SetLayoutElement(editorDoneButton.Component.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
editorDoneButton.OnClick += HookManager.Instance.EditorInputCancel;
|
||||||
|
|
||||||
|
int fontSize = 16;
|
||||||
|
var inputObj = UIFactory.CreateScrollInputField(editorPanel, "EditorInput", "", out var inputScroller, fontSize);
|
||||||
|
EditorInputScroller = inputScroller;
|
||||||
|
EditorInput.OnValueChanged += HookManager.Instance.OnEditorInputChanged;
|
||||||
|
|
||||||
|
EditorInputText = EditorInput.Component.textComponent;
|
||||||
|
EditorInputText.supportRichText = false;
|
||||||
|
EditorInputText.color = Color.clear;
|
||||||
|
EditorInput.Component.customCaretColor = true;
|
||||||
|
EditorInput.Component.caretColor = Color.white;
|
||||||
|
EditorInput.PlaceholderText.fontSize = fontSize;
|
||||||
|
|
||||||
|
// Lexer highlight text overlay
|
||||||
|
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", EditorInputText.gameObject);
|
||||||
|
var highlightTextRect = highlightTextObj.GetComponent<RectTransform>();
|
||||||
|
highlightTextRect.pivot = new Vector2(0, 1);
|
||||||
|
highlightTextRect.anchorMin = Vector2.zero;
|
||||||
|
highlightTextRect.anchorMax = Vector2.one;
|
||||||
|
highlightTextRect.offsetMin = Vector2.zero;
|
||||||
|
highlightTextRect.offsetMax = Vector2.zero;
|
||||||
|
|
||||||
|
EditorHighlightText = highlightTextObj.AddComponent<Text>();
|
||||||
|
EditorHighlightText.color = Color.white;
|
||||||
|
EditorHighlightText.supportRichText = true;
|
||||||
|
EditorHighlightText.fontSize = fontSize;
|
||||||
|
|
||||||
|
// Set fonts
|
||||||
|
EditorInputText.font = UIManager.ConsoleFont;
|
||||||
|
EditorInput.PlaceholderText.font = UIManager.ConsoleFont;
|
||||||
|
EditorHighlightText.font = UIManager.ConsoleFont;
|
||||||
|
|
||||||
|
editorPanel.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
|
{
|
||||||
|
this.Rect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||||
|
this.Rect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||||
|
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth);
|
||||||
|
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -102,7 +102,6 @@ namespace UnityExplorer.UI.Panels
|
|||||||
Rect.pivot = new Vector2(0f, 1f);
|
Rect.pivot = new Vector2(0f, 1f);
|
||||||
Rect.anchorMin = new Vector2(0.125f, 0.175f);
|
Rect.anchorMin = new Vector2(0.125f, 0.175f);
|
||||||
Rect.anchorMax = new Vector2(0.325f, 0.925f);
|
Rect.anchorMax = new Vector2(0.325f, 0.925f);
|
||||||
//mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 350);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ConstructPanelContent()
|
public override void ConstructPanelContent()
|
||||||
|
@ -11,8 +11,6 @@ using UnityExplorer.UI.Widgets;
|
|||||||
|
|
||||||
namespace UnityExplorer.UI.Panels
|
namespace UnityExplorer.UI.Panels
|
||||||
{
|
{
|
||||||
// TODO move the logic out of this class into ConfigManager
|
|
||||||
|
|
||||||
public class OptionsPanel : UIPanel, ICacheObjectController, ICellPoolDataSource<ConfigEntryCell>
|
public class OptionsPanel : UIPanel, ICacheObjectController, ICellPoolDataSource<ConfigEntryCell>
|
||||||
{
|
{
|
||||||
public override string Name => "Options";
|
public override string Name => "Options";
|
||||||
|
@ -116,10 +116,8 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
if (NavButtonWanted)
|
if (NavButtonWanted)
|
||||||
{
|
{
|
||||||
if (active)
|
var color = active ? UIManager.enabledButtonColor : UIManager.disabledButtonColor;
|
||||||
RuntimeProvider.Instance.SetColorBlock(NavButton.Component, UIManager.enabledButtonColor, UIManager.enabledButtonColor * 1.2f);
|
RuntimeProvider.Instance.SetColorBlock(NavButton.Component, color, color * 1.2f);
|
||||||
else
|
|
||||||
RuntimeProvider.Instance.SetColorBlock(NavButton.Component, UIManager.disabledButtonColor, UIManager.disabledButtonColor * 1.2f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!active)
|
if (!active)
|
||||||
|
76
src/UI/Panels/UiInspectorResultsPanel.cs
Normal file
76
src/UI/Panels/UiInspectorResultsPanel.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityExplorer.Inspectors.MouseInspectors;
|
||||||
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
|
namespace UnityExplorer.UI.Panels
|
||||||
|
{
|
||||||
|
public class UiInspectorResultsPanel : UIPanel
|
||||||
|
{
|
||||||
|
public override UIManager.Panels PanelType => UIManager.Panels.UIInspectorResults;
|
||||||
|
|
||||||
|
public override string Name => "UI Inspector Results";
|
||||||
|
|
||||||
|
public override int MinWidth => 500;
|
||||||
|
public override int MinHeight => 500;
|
||||||
|
public override bool CanDragAndResize => true;
|
||||||
|
public override bool NavButtonWanted => false;
|
||||||
|
public override bool ShouldSaveActiveState => false;
|
||||||
|
public override bool ShowByDefault => false;
|
||||||
|
|
||||||
|
private ButtonListHandler<GameObject, ButtonCell> dataHandler;
|
||||||
|
private ScrollPool<ButtonCell> buttonScrollPool;
|
||||||
|
|
||||||
|
public override void ConstructPanelContent()
|
||||||
|
{
|
||||||
|
dataHandler = new ButtonListHandler<GameObject, ButtonCell>(buttonScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked);
|
||||||
|
|
||||||
|
buttonScrollPool = UIFactory.CreateScrollPool<ButtonCell>(this.content, "ResultsList", out GameObject scrollObj,
|
||||||
|
out GameObject scrollContent);
|
||||||
|
|
||||||
|
buttonScrollPool.Initialize(dataHandler);
|
||||||
|
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowResults()
|
||||||
|
{
|
||||||
|
dataHandler.RefreshData();
|
||||||
|
buttonScrollPool.Refresh(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<GameObject> GetEntries() => UiInspector.LastHitObjects;
|
||||||
|
|
||||||
|
private bool ShouldDisplayCell(object cell, string filter) => true;
|
||||||
|
|
||||||
|
private void OnCellClicked(int index)
|
||||||
|
{
|
||||||
|
if (index >= UiInspector.LastHitObjects.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
InspectorManager.Inspect(UiInspector.LastHitObjects[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetCell(ButtonCell cell, int index)
|
||||||
|
{
|
||||||
|
if (index >= UiInspector.LastHitObjects.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var obj = UiInspector.LastHitObjects[index];
|
||||||
|
cell.Button.ButtonText.text = $"<color=cyan>{obj.name}</color> ({obj.transform.GetTransformPath(true)})";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
|
{
|
||||||
|
this.Rect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||||
|
this.Rect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||||
|
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 500f);
|
||||||
|
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 500f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DoSaveToConfigElement() { }
|
||||||
|
public override string GetSaveDataFromConfigManager() => null;
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,9 @@ namespace UnityExplorer.UI
|
|||||||
Options,
|
Options,
|
||||||
ConsoleLog,
|
ConsoleLog,
|
||||||
AutoCompleter,
|
AutoCompleter,
|
||||||
MouseInspector
|
MouseInspector,
|
||||||
|
UIInspectorResults,
|
||||||
|
HookManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum VerticalAnchor
|
public enum VerticalAnchor
|
||||||
@ -106,8 +108,10 @@ namespace UnityExplorer.UI
|
|||||||
UIPanels.Add(Panels.ObjectExplorer, new ObjectExplorerPanel());
|
UIPanels.Add(Panels.ObjectExplorer, new ObjectExplorerPanel());
|
||||||
UIPanels.Add(Panels.Inspector, new InspectorPanel());
|
UIPanels.Add(Panels.Inspector, new InspectorPanel());
|
||||||
UIPanels.Add(Panels.CSConsole, new CSConsolePanel());
|
UIPanels.Add(Panels.CSConsole, new CSConsolePanel());
|
||||||
|
UIPanels.Add(Panels.HookManager, new HookManagerPanel());
|
||||||
UIPanels.Add(Panels.ConsoleLog, new LogPanel());
|
UIPanels.Add(Panels.ConsoleLog, new LogPanel());
|
||||||
UIPanels.Add(Panels.Options, new OptionsPanel());
|
UIPanels.Add(Panels.Options, new OptionsPanel());
|
||||||
|
UIPanels.Add(Panels.UIInspectorResults, new UiInspectorResultsPanel());
|
||||||
UIPanels.Add(Panels.MouseInspector, new InspectUnderMouse());
|
UIPanels.Add(Panels.MouseInspector, new InspectUnderMouse());
|
||||||
|
|
||||||
foreach (var panel in UIPanels.Values)
|
foreach (var panel in UIPanels.Values)
|
||||||
@ -240,14 +244,14 @@ namespace UnityExplorer.UI
|
|||||||
NavBarRect.anchorMin = new Vector2(0.5f, 1f);
|
NavBarRect.anchorMin = new Vector2(0.5f, 1f);
|
||||||
NavBarRect.anchorMax = new Vector2(0.5f, 1f);
|
NavBarRect.anchorMax = new Vector2(0.5f, 1f);
|
||||||
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 0);
|
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 0);
|
||||||
NavBarRect.sizeDelta = new Vector2(1000f, 35f);
|
NavBarRect.sizeDelta = new Vector2(1080f, 35f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VerticalAnchor.Bottom:
|
case VerticalAnchor.Bottom:
|
||||||
NavBarRect.anchorMin = new Vector2(0.5f, 0f);
|
NavBarRect.anchorMin = new Vector2(0.5f, 0f);
|
||||||
NavBarRect.anchorMax = new Vector2(0.5f, 0f);
|
NavBarRect.anchorMax = new Vector2(0.5f, 0f);
|
||||||
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 35);
|
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 35);
|
||||||
NavBarRect.sizeDelta = new Vector2(1000f, 35f);
|
NavBarRect.sizeDelta = new Vector2(1080f, 35f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
|||||||
|
|
||||||
public Type BaseType { get; set; }
|
public Type BaseType { get; set; }
|
||||||
public Type[] GenericConstraints { get; set; }
|
public Type[] GenericConstraints { get; set; }
|
||||||
|
private bool allowAbstract;
|
||||||
|
private bool allowEnum;
|
||||||
|
|
||||||
public InputFieldRef InputField { get; }
|
public InputFieldRef InputField { get; }
|
||||||
public bool AnchorToCaretPosition => false;
|
public bool AnchorToCaretPosition => false;
|
||||||
@ -33,11 +35,16 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
|||||||
|
|
||||||
bool ISuggestionProvider.AllowNavigation => false;
|
bool ISuggestionProvider.AllowNavigation => false;
|
||||||
|
|
||||||
public TypeCompleter(Type baseType, InputFieldRef inputField)
|
public TypeCompleter(Type baseType, InputFieldRef inputField) : this(baseType, inputField, true, true) { }
|
||||||
|
|
||||||
|
public TypeCompleter(Type baseType, InputFieldRef inputField, bool allowAbstract, bool allowEnum)
|
||||||
{
|
{
|
||||||
BaseType = baseType;
|
BaseType = baseType;
|
||||||
InputField = inputField;
|
InputField = inputField;
|
||||||
|
|
||||||
|
this.allowAbstract = allowAbstract;
|
||||||
|
this.allowEnum = allowEnum;
|
||||||
|
|
||||||
inputField.OnValueChanged += OnInputFieldChanged;
|
inputField.OnValueChanged += OnInputFieldChanged;
|
||||||
|
|
||||||
if (BaseType != null)
|
if (BaseType != null)
|
||||||
@ -46,7 +53,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
|||||||
|
|
||||||
public void CacheTypes()
|
public void CacheTypes()
|
||||||
{
|
{
|
||||||
allowedTypes = ReflectionUtility.GetImplementationsOf(BaseType, true, false);
|
allowedTypes = ReflectionUtility.GetImplementationsOf(BaseType, allowAbstract, allowEnum, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnSuggestionClicked(Suggestion suggestion)
|
public void OnSuggestionClicked(Suggestion suggestion)
|
||||||
|
@ -215,6 +215,9 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Hooks\HookCell.cs" />
|
||||||
|
<Compile Include="Hooks\HookInstance.cs" />
|
||||||
|
<Compile Include="Hooks\HookManager.cs" />
|
||||||
<Compile Include="Core\Config\InternalConfigHandler.cs" />
|
<Compile Include="Core\Config\InternalConfigHandler.cs" />
|
||||||
<Compile Include="CacheObject\CacheConfigEntry.cs" />
|
<Compile Include="CacheObject\CacheConfigEntry.cs" />
|
||||||
<Compile Include="CacheObject\Views\CacheConfigCell.cs" />
|
<Compile Include="CacheObject\Views\CacheConfigCell.cs" />
|
||||||
@ -235,6 +238,7 @@
|
|||||||
<Compile Include="Core\Utility\ArgumentUtility.cs" />
|
<Compile Include="Core\Utility\ArgumentUtility.cs" />
|
||||||
<Compile Include="Core\Utility\MiscUtility.cs" />
|
<Compile Include="Core\Utility\MiscUtility.cs" />
|
||||||
<Compile Include="Core\Utility\ParseUtility.cs" />
|
<Compile Include="Core\Utility\ParseUtility.cs" />
|
||||||
|
<Compile Include="Hooks\AddHookCell.cs" />
|
||||||
<Compile Include="Inspectors\GameObjectWidgets\ComponentCell.cs" />
|
<Compile Include="Inspectors\GameObjectWidgets\ComponentCell.cs" />
|
||||||
<Compile Include="Inspectors\GameObjectWidgets\ComponentList.cs" />
|
<Compile Include="Inspectors\GameObjectWidgets\ComponentList.cs" />
|
||||||
<Compile Include="Inspectors\GameObjectWidgets\GameObjectControls.cs" />
|
<Compile Include="Inspectors\GameObjectWidgets\GameObjectControls.cs" />
|
||||||
@ -263,9 +267,14 @@
|
|||||||
<Compile Include="CacheObject\IValues\InteractiveList.cs" />
|
<Compile Include="CacheObject\IValues\InteractiveList.cs" />
|
||||||
<Compile Include="CacheObject\IValues\InteractiveString.cs" />
|
<Compile Include="CacheObject\IValues\InteractiveString.cs" />
|
||||||
<Compile Include="CacheObject\IValues\InteractiveValue.cs" />
|
<Compile Include="CacheObject\IValues\InteractiveValue.cs" />
|
||||||
|
<Compile Include="Inspectors\MouseInspectors\MouseInspectorBase.cs" />
|
||||||
|
<Compile Include="Inspectors\MouseInspectors\UiInspector.cs" />
|
||||||
|
<Compile Include="Inspectors\MouseInspectors\WorldInspector.cs" />
|
||||||
<Compile Include="Inspectors\ReflectionInspector.cs" />
|
<Compile Include="Inspectors\ReflectionInspector.cs" />
|
||||||
<Compile Include="CacheObject\IValues\InteractiveValueStruct.cs" />
|
<Compile Include="CacheObject\IValues\InteractiveValueStruct.cs" />
|
||||||
<Compile Include="UI\Models\InputFieldRef.cs" />
|
<Compile Include="UI\Models\InputFieldRef.cs" />
|
||||||
|
<Compile Include="UI\Panels\HookManagerPanel.cs" />
|
||||||
|
<Compile Include="UI\Panels\UiInspectorResultsPanel.cs" />
|
||||||
<Compile Include="UI\Pool.cs" />
|
<Compile Include="UI\Pool.cs" />
|
||||||
<Compile Include="UI\Panels\LogPanel.cs" />
|
<Compile Include="UI\Panels\LogPanel.cs" />
|
||||||
<Compile Include="UI\Panels\CSConsolePanel.cs" />
|
<Compile Include="UI\Panels\CSConsolePanel.cs" />
|
||||||
|
Reference in New Issue
Block a user