Compare commits

..

5 Commits
2.0.2 ... 2.0.5

Author SHA1 Message Date
f490203b10 2.0.5
* Added Max Results option to Search (default 5000)
* Fixed a TypeInitializationException which can happen when inspecting some classes with Dictionary members
* Fixed an issue which could prevent Input support from initializating
* Improved and fixed the display of TextAsset objects
* A few other minor fixes
2020-10-12 20:15:41 +11:00
39d9585f1d 2.0.4
* Added ability to see and change the layer of a gameobject from the GameObject inspector more easily, and shows you the actual layer name (where possible).
* Fixed an issue related to the recently-added clickthrough prevention and resize drag
* Fixed write-only properties in the inspector
* A few other minor fixes
2020-10-11 22:57:46 +11:00
2d414e544b Update README.md 2020-10-11 20:52:08 +11:00
513fcaa534 Universal click-through prevention attempt 2020-10-11 20:49:14 +11:00
b41f7211e5 2.0.3
* Fixed a few issues related to the Texture2D support/export.
2020-10-11 20:07:23 +11:00
30 changed files with 893 additions and 521 deletions

View File

@ -78,11 +78,16 @@ There is a simple Mod Config for the Explorer. You can access the settings via t
* Whether or not to show the Bitwise Editing helper when inspecting integers * Whether or not to show the Bitwise Editing helper when inspecting integers
`Enable Tab View` (bool) | Default: `true` `Enable Tab View` (bool) | Default: `true`
* Whether or not all inspector windows a grouped into a single window with tabs. * Whether or not all inspector windows a grouped into a single window with tabs.
`Default Output Path` (string) | Default: `Mods\Explorer`
* Where output is generated to, by default (for Texture PNG saving, etc).
## Mouse Control ## Mouse Control
Explorer can force the mouse to be visible and unlocked when the menu is open, if you have enabled "Force Unlock Mouse" (Left-Alt toggle). However, you may also want to prevent the mouse clicking-through onto the game behind Explorer, this is possible but it requires specific patches for that game. Explorer can force the mouse to be visible and unlocked when the menu is open, if you have enabled "Force Unlock Mouse" (Left-Alt toggle). Explorer also attempts to prevent clicking-through onto the game behind the Explorer menu.
If you need more mouse control:
* For VRChat, use [VRCExplorerMouseControl](https://github.com/sinai-dev/VRCExplorerMouseControl) * For VRChat, use [VRCExplorerMouseControl](https://github.com/sinai-dev/VRCExplorerMouseControl)
* For Hellpoint, use [HPExplorerMouseControl](https://github.com/sinai-dev/Hellpoint-Mods/tree/master/HPExplorerMouseControl/HPExplorerMouseControl) * For Hellpoint, use [HPExplorerMouseControl](https://github.com/sinai-dev/Hellpoint-Mods/tree/master/HPExplorerMouseControl/HPExplorerMouseControl)
@ -93,8 +98,9 @@ For example:
using Explorer; using Explorer;
using Harmony; // or 'using HarmonyLib;' for BepInEx using Harmony; // or 'using HarmonyLib;' for BepInEx
// ... // ...
[HarmonyPatch(typeof(MyGame.MenuClass), nameof(MyGame.MenuClass.CursorUpdate)] // You will need to figure out the relevant Class and Method for your game using dnSpy.
public class MenuClass_CursorUpdate [HarmonyPatch(typeof(MyGame.InputManager), nameof(MyGame.InputManager.Update)]
public class InputManager_Update
{ {
[HarmonyPrefix] [HarmonyPrefix]
public static bool Prefix() public static bool Prefix()

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Reflection; using System.Reflection;
using Explorer.UI;
namespace Explorer.CacheObject namespace Explorer.CacheObject
{ {
@ -21,6 +22,15 @@ namespace Explorer.CacheObject
public override void UpdateValue() public override void UpdateValue()
{ {
if (IValue is InteractiveDictionary iDict)
{
if (!iDict.EnsureDictionaryIsSupported())
{
ReflectionException = "Not supported due to TypeInitializationException";
return;
}
}
try try
{ {
var fi = MemInfo as FieldInfo; var fi = MemInfo as FieldInfo;

View File

@ -37,6 +37,10 @@ namespace Explorer.CacheObject
{ {
interactive = new InteractiveTexture2D(); interactive = new InteractiveTexture2D();
} }
else if (valueType == typeof(Texture))
{
interactive = new InteractiveTexture();
}
else if (valueType == typeof(Sprite)) else if (valueType == typeof(Sprite))
{ {
interactive = new InteractiveSprite(); interactive = new InteractiveSprite();

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Reflection; using System.Reflection;
using Explorer.UI;
namespace Explorer.CacheObject namespace Explorer.CacheObject
{ {
@ -32,14 +33,38 @@ namespace Explorer.CacheObject
return; return;
} }
if (IValue is InteractiveDictionary iDict)
{
if (!iDict.EnsureDictionaryIsSupported())
{
ReflectionException = "Not supported due to TypeInitializationException";
return;
}
}
try try
{ {
var pi = MemInfo as PropertyInfo; var pi = MemInfo as PropertyInfo;
var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance;
IValue.Value = pi.GetValue(target, ParseArguments()); if (pi.CanRead)
{
var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance;
base.UpdateValue(); IValue.Value = pi.GetValue(target, ParseArguments());
base.UpdateValue();
}
else // create a dummy value for Write-Only properties.
{
if (IValue.ValueType == typeof(string))
{
IValue.Value = "";
}
else
{
IValue.Value = Activator.CreateInstance(IValue.ValueType);
}
}
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -208,11 +208,13 @@
<Compile Include="CacheObject\CacheMethod.cs" /> <Compile Include="CacheObject\CacheMethod.cs" />
<Compile Include="CacheObject\CacheProperty.cs" /> <Compile Include="CacheObject\CacheProperty.cs" />
<Compile Include="CacheObject\CacheObjectBase.cs" /> <Compile Include="CacheObject\CacheObjectBase.cs" />
<Compile Include="Helpers\Texture2DHelpers.cs" />
<Compile Include="UI\InteractiveValue\InteractiveValue.cs" /> <Compile Include="UI\InteractiveValue\InteractiveValue.cs" />
<Compile Include="UI\InteractiveValue\Object\InteractiveDictionary.cs" /> <Compile Include="UI\InteractiveValue\Object\InteractiveDictionary.cs" />
<Compile Include="UI\InteractiveValue\Object\InteractiveEnumerable.cs" /> <Compile Include="UI\InteractiveValue\Object\InteractiveEnumerable.cs" />
<Compile Include="UI\InteractiveValue\Object\InteractiveGameObject.cs" /> <Compile Include="UI\InteractiveValue\Object\InteractiveGameObject.cs" />
<Compile Include="UI\InteractiveValue\Object\InteractiveSprite.cs" /> <Compile Include="UI\InteractiveValue\Object\InteractiveSprite.cs" />
<Compile Include="UI\InteractiveValue\Object\InteractiveTexture.cs" />
<Compile Include="UI\InteractiveValue\Object\InteractiveTexture2D.cs" /> <Compile Include="UI\InteractiveValue\Object\InteractiveTexture2D.cs" />
<Compile Include="UI\InteractiveValue\Struct\InteractiveQuaternion.cs" /> <Compile Include="UI\InteractiveValue\Struct\InteractiveQuaternion.cs" />
<Compile Include="UI\InteractiveValue\Struct\InteractiveRect.cs" /> <Compile Include="UI\InteractiveValue\Struct\InteractiveRect.cs" />
@ -229,7 +231,7 @@
<Compile Include="Extensions\UnityExtensions.cs" /> <Compile Include="Extensions\UnityExtensions.cs" />
<Compile Include="Helpers\ReflectionHelpers.cs" /> <Compile Include="Helpers\ReflectionHelpers.cs" />
<Compile Include="Helpers\UnityHelpers.cs" /> <Compile Include="Helpers\UnityHelpers.cs" />
<Compile Include="Input\AbstractInput.cs" /> <Compile Include="Input\IAbstractInput.cs" />
<Compile Include="Tests\TestClass.cs" /> <Compile Include="Tests\TestClass.cs" />
<Compile Include="UI\ForceUnlockCursor.cs" /> <Compile Include="UI\ForceUnlockCursor.cs" />
<Compile Include="Input\InputManager.cs" /> <Compile Include="Input\InputManager.cs" />
@ -260,6 +262,7 @@
<Compile Include="UI\WindowBase.cs" /> <Compile Include="UI\WindowBase.cs" />
<Compile Include="UI\WindowManager.cs" /> <Compile Include="UI\WindowManager.cs" />
<Compile Include="Unstrip\ImageConversion\ImageConversionUnstrip.cs" /> <Compile Include="Unstrip\ImageConversion\ImageConversionUnstrip.cs" />
<Compile Include="Unstrip\LayerMask\LayerMaskUnstrip.cs" />
<Compile Include="Unstrip\Scene\SceneUnstrip.cs" /> <Compile Include="Unstrip\Scene\SceneUnstrip.cs" />
<Compile Include="Unstrip\IMGUI\GUIUnstrip.cs" /> <Compile Include="Unstrip\IMGUI\GUIUnstrip.cs" />
<Compile Include="Unstrip\IMGUI\Internal_LayoutUtility.cs" /> <Compile Include="Unstrip\IMGUI\Internal_LayoutUtility.cs" />

View File

@ -10,7 +10,7 @@ namespace Explorer
public class ExplorerCore public class ExplorerCore
{ {
public const string NAME = "Explorer " + VERSION + " (" + PLATFORM + ", " + MODLOADER + ")"; public const string NAME = "Explorer " + VERSION + " (" + PLATFORM + ", " + MODLOADER + ")";
public const string VERSION = "2.0.2"; public const string VERSION = "2.0.5";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.explorer"; public const string GUID = "com.sinai.explorer";
@ -31,6 +31,12 @@ namespace Explorer
public ExplorerCore() public ExplorerCore()
{ {
if (Instance != null)
{
Log("An instance of Explorer is already active!");
return;
}
Instance = this; Instance = this;
ModConfig.OnLoad(); ModConfig.OnLoad();
@ -87,6 +93,11 @@ namespace Explorer
WindowManager.Instance.OnGUI(); WindowManager.Instance.OnGUI();
InspectUnderMouse.OnGUI(); InspectUnderMouse.OnGUI();
if (!ResizeDrag.IsMouseInResizeArea && WindowManager.IsMouseInWindow)
{
InputManager.ResetInputAxes();
}
GUI.skin = origSkin; GUI.skin = origSkin;
} }
@ -99,27 +110,27 @@ namespace Explorer
public static void Log(object message) public static void Log(object message)
{ {
#if ML #if ML
MelonLoader.MelonLogger.Log(message.ToString()); MelonLoader.MelonLogger.Log(message?.ToString());
#else #else
ExplorerBepInPlugin.Logging?.LogMessage(message.ToString()); ExplorerBepInPlugin.Logging?.LogMessage(message?.ToString());
#endif #endif
} }
public static void LogWarning(object message) public static void LogWarning(object message)
{ {
#if ML #if ML
MelonLoader.MelonLogger.LogWarning(message.ToString()); MelonLoader.MelonLogger.LogWarning(message?.ToString());
#else #else
ExplorerBepInPlugin.Logging?.LogWarning(message.ToString()); ExplorerBepInPlugin.Logging?.LogWarning(message?.ToString());
#endif #endif
} }
public static void LogError(object message) public static void LogError(object message)
{ {
#if ML #if ML
MelonLoader.MelonLogger.LogError(message.ToString()); MelonLoader.MelonLogger.LogError(message?.ToString());
#else #else
ExplorerBepInPlugin.Logging?.LogError(message.ToString()); ExplorerBepInPlugin.Logging?.LogError(message?.ToString());
#endif #endif
} }
} }

View File

@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using System.IO;
using System.Reflection;
#if CPP
using Explorer.Unstrip.ImageConversion;
#endif
namespace Explorer.Helpers
{
public static class Texture2DHelpers
{
#if CPP
#else
private static bool isNewEncodeMethod = false;
private static MethodInfo EncodeToPNGMethod => m_encodeToPNGMethod ?? GetEncodeToPNGMethod();
private static MethodInfo m_encodeToPNGMethod;
private static MethodInfo GetEncodeToPNGMethod()
{
if (ReflectionHelpers.GetTypeByName("UnityEngine.ImageConversion") is Type imageConversion)
{
isNewEncodeMethod = true;
return m_encodeToPNGMethod = imageConversion.GetMethod("EncodeToPNG", ReflectionHelpers.CommonFlags);
}
var method = typeof(Texture2D).GetMethod("EncodeToPNG", ReflectionHelpers.CommonFlags);
if (method != null)
{
return m_encodeToPNGMethod = method;
}
ExplorerCore.Log("ERROR: Cannot get any EncodeToPNG method!");
return null;
}
#endif
public static bool IsReadable(this Texture2D tex)
{
try
{
// This will cause an exception if it's not readable.
// Reason for doing it this way is not all Unity versions
// ship with the 'Texture.isReadable' property.
tex.GetPixel(0, 0);
return true;
}
catch
{
return false;
}
}
public static Texture2D Copy(Texture2D other, Rect rect, bool isDTXnmNormal = false)
{
Color[] pixels;
if (!other.IsReadable())
{
other = ForceReadTexture(other, isDTXnmNormal);
}
pixels = other.GetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
var _newTex = new Texture2D((int)rect.width, (int)rect.height);
_newTex.SetPixels(pixels);
return _newTex;
}
public static Texture2D ForceReadTexture(Texture2D tex, bool isDTXnmNormal = false)
{
try
{
var origFilter = tex.filterMode;
tex.filterMode = FilterMode.Point;
RenderTexture rt = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
rt.filterMode = FilterMode.Point;
RenderTexture.active = rt;
Graphics.Blit(tex, rt);
Texture2D _newTex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
_newTex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
if (isDTXnmNormal)
{
_newTex = DTXnmToRGBA(_newTex);
}
_newTex.Apply(false, false);
RenderTexture.active = null;
tex.filterMode = origFilter;
return _newTex;
}
catch (Exception e)
{
ExplorerCore.Log("Exception on ForceReadTexture: " + e.ToString());
return default;
}
}
public static void SaveTextureAsPNG(Texture2D tex, string dir, string name, bool isDTXnmNormal = false)
{
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
byte[] data;
var savepath = dir + @"\" + name + ".png";
// Fix for non-Readable or Compressed textures.
tex = ForceReadTexture(tex, isDTXnmNormal);
if (isDTXnmNormal)
{
tex = DTXnmToRGBA(tex);
tex.Apply(false, false);
}
#if CPP
data = tex.EncodeToPNG();
#else
var method = EncodeToPNGMethod;
if (isNewEncodeMethod)
{
data = (byte[])method.Invoke(null, new object[] { tex });
}
else
{
data = (byte[])method.Invoke(tex, new object[0]);
}
#endif
if (data == null || data.Length < 1)
{
ExplorerCore.LogWarning("Couldn't get any data for the texture!");
}
else
{
#if CPP
// The IL2CPP method will return invalid byte data.
// However, we can just iterate into safe C# byte[] array.
byte[] safeData = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
{
safeData[i] = (byte)data[i]; // not sure if cast is needed
}
File.WriteAllBytes(savepath, safeData);
#else
File.WriteAllBytes(savepath, data);
#endif
}
}
// Converts DTXnm-format Normal Map to RGBA-format Normal Map.
public static Texture2D DTXnmToRGBA(Texture2D tex)
{
Color[] colors = tex.GetPixels();
for (int i = 0; i < colors.Length; i++)
{
Color c = colors[i];
c.r = c.a * 2 - 1; // red <- alpha
c.g = c.g * 2 - 1; // green is always the same
Vector2 rg = new Vector2(c.r, c.g); //this is the red-green vector
c.b = Mathf.Sqrt(1 - Mathf.Clamp01(Vector2.Dot(rg, rg))); //recalculate the blue channel
colors[i] = new Color(
(c.r * 0.5f) + 0.5f,
(c.g * 0.5f) + 0.25f,
(c.b * 0.5f) + 0.5f
);
}
var newtex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
newtex.SetPixels(colors);
return newtex;
}
}
}

View File

@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Explorer.Input
{
public abstract class AbstractInput
{
public abstract void Init();
public abstract Vector2 MousePosition { get; }
public abstract bool GetKeyDown(KeyCode key);
public abstract bool GetKey(KeyCode key);
public abstract bool GetMouseButtonDown(int btn);
public abstract bool GetMouseButton(int btn);
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Explorer.Input
{
public interface IAbstractInput
{
void Init();
Vector2 MousePosition { get; }
bool GetKeyDown(KeyCode key);
bool GetKey(KeyCode key);
bool GetMouseButtonDown(int btn);
bool GetMouseButton(int btn);
}
}

View File

@ -10,37 +10,45 @@ namespace Explorer
{ {
public static class InputManager public static class InputManager
{ {
private static AbstractInput inputModule; private static IAbstractInput m_inputModule;
public static void Init() public static void Init()
{ {
if (InputSystem.TKeyboard != null || TryLoadModule("Unity.InputSystem", InputSystem.TKeyboard)) if (InputSystem.TKeyboard != null || (ReflectionHelpers.LoadModule("Unity.InputSystem") && InputSystem.TKeyboard != null))
{ {
inputModule = new InputSystem(); m_inputModule = new InputSystem();
} }
else if (LegacyInput.TInput != null || TryLoadModule("UnityEngine.InputLegacyModule", LegacyInput.TInput)) else if (LegacyInput.TInput != null || (ReflectionHelpers.LoadModule("UnityEngine.InputLegacyModule") && LegacyInput.TInput != null))
{ {
inputModule = new LegacyInput(); m_inputModule = new LegacyInput();
} }
if (inputModule == null) if (m_inputModule == null)
{ {
ExplorerCore.LogWarning("Could not find any Input module!"); ExplorerCore.LogWarning("Could not find any Input module!");
inputModule = new NoInput(); m_inputModule = new NoInput();
} }
inputModule.Init(); m_inputModule.Init();
bool TryLoadModule(string dll, Type check) => ReflectionHelpers.LoadModule(dll) && check != null;
} }
public static Vector3 MousePosition => inputModule.MousePosition; public static Vector3 MousePosition => m_inputModule.MousePosition;
public static bool GetKeyDown(KeyCode key) => inputModule.GetKeyDown(key); public static bool GetKeyDown(KeyCode key) => m_inputModule.GetKeyDown(key);
public static bool GetKey(KeyCode key) => inputModule.GetKey(key); public static bool GetKey(KeyCode key) => m_inputModule.GetKey(key);
public static bool GetMouseButtonDown(int btn) => inputModule.GetMouseButtonDown(btn); public static bool GetMouseButtonDown(int btn) => m_inputModule.GetMouseButtonDown(btn);
public static bool GetMouseButton(int btn) => inputModule.GetMouseButton(btn); public static bool GetMouseButton(int btn) => m_inputModule.GetMouseButton(btn);
#if CPP
internal delegate void d_ResetInputAxes();
internal static d_ResetInputAxes ResetInputAxes_iCall =
IL2CPP.ResolveICall<d_ResetInputAxes>("UnityEngine.Input::ResetInputAxes");
public static void ResetInputAxes() => ResetInputAxes_iCall();
#else
public static void ResetInputAxes() => UnityEngine.Input.ResetInputAxes();
#endif
//#if CPP //#if CPP
//#pragma warning disable IDE1006 //#pragma warning disable IDE1006

View File

@ -7,7 +7,7 @@ using UnityEngine;
namespace Explorer.Input namespace Explorer.Input
{ {
public class InputSystem : AbstractInput public class InputSystem : IAbstractInput
{ {
public static Type TKeyboard => _keyboard ?? (_keyboard = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Keyboard")); public static Type TKeyboard => _keyboard ?? (_keyboard = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.Keyboard"));
private static Type _keyboard; private static Type _keyboard;
@ -43,9 +43,9 @@ namespace Explorer.Input
private static PropertyInfo _positionProp; private static PropertyInfo _positionProp;
private static MethodInfo _readVector2InputMethod; private static MethodInfo _readVector2InputMethod;
public override Vector2 MousePosition => (Vector2)_readVector2InputMethod.Invoke(MousePositionInfo, new object[0]); public Vector2 MousePosition => (Vector2)_readVector2InputMethod.Invoke(MousePositionInfo, new object[0]);
public override bool GetKeyDown(KeyCode key) public bool GetKeyDown(KeyCode key)
{ {
var parsedKey = Enum.Parse(TKey, key.ToString()); var parsedKey = Enum.Parse(TKey, key.ToString());
var actualKey = _kbIndexer.GetValue(CurrentKeyboard, new object[] { parsedKey }); var actualKey = _kbIndexer.GetValue(CurrentKeyboard, new object[] { parsedKey });
@ -53,7 +53,7 @@ namespace Explorer.Input
return (bool)_btnWasPressedProp.GetValue(actualKey, null); return (bool)_btnWasPressedProp.GetValue(actualKey, null);
} }
public override bool GetKey(KeyCode key) public bool GetKey(KeyCode key)
{ {
var parsed = Enum.Parse(TKey, key.ToString()); var parsed = Enum.Parse(TKey, key.ToString());
var actualKey = _kbIndexer.GetValue(CurrentKeyboard, new object[] { parsed }); var actualKey = _kbIndexer.GetValue(CurrentKeyboard, new object[] { parsed });
@ -61,7 +61,7 @@ namespace Explorer.Input
return (bool)_btnIsPressedProp.GetValue(actualKey, null); return (bool)_btnIsPressedProp.GetValue(actualKey, null);
} }
public override bool GetMouseButtonDown(int btn) public bool GetMouseButtonDown(int btn)
{ {
switch (btn) switch (btn)
{ {
@ -72,7 +72,7 @@ namespace Explorer.Input
} }
} }
public override bool GetMouseButton(int btn) public bool GetMouseButton(int btn)
{ {
switch (btn) switch (btn)
{ {
@ -83,7 +83,7 @@ namespace Explorer.Input
} }
} }
public override void Init() public void Init()
{ {
ExplorerCore.Log("Initializing new InputSystem support..."); ExplorerCore.Log("Initializing new InputSystem support...");

View File

@ -7,7 +7,7 @@ using UnityEngine;
namespace Explorer.Input namespace Explorer.Input
{ {
public class LegacyInput : AbstractInput public class LegacyInput : IAbstractInput
{ {
public static Type TInput => _input ?? (_input = ReflectionHelpers.GetTypeByName("UnityEngine.Input")); public static Type TInput => _input ?? (_input = ReflectionHelpers.GetTypeByName("UnityEngine.Input"));
private static Type _input; private static Type _input;
@ -18,17 +18,17 @@ namespace Explorer.Input
private static MethodInfo _getMouseButtonMethod; private static MethodInfo _getMouseButtonMethod;
private static MethodInfo _getMouseButtonDownMethod; private static MethodInfo _getMouseButtonDownMethod;
public override Vector2 MousePosition => (Vector3)_mousePositionProp.GetValue(null, null); public Vector2 MousePosition => (Vector3)_mousePositionProp.GetValue(null, null);
public override bool GetKey(KeyCode key) => (bool)_getKeyMethod.Invoke(null, new object[] { key }); public bool GetKey(KeyCode key) => (bool)_getKeyMethod.Invoke(null, new object[] { key });
public override bool GetKeyDown(KeyCode key) => (bool)_getKeyDownMethod.Invoke(null, new object[] { key }); public bool GetKeyDown(KeyCode key) => (bool)_getKeyDownMethod.Invoke(null, new object[] { key });
public override bool GetMouseButton(int btn) => (bool)_getMouseButtonMethod.Invoke(null, new object[] { btn }); public bool GetMouseButton(int btn) => (bool)_getMouseButtonMethod.Invoke(null, new object[] { btn });
public override bool GetMouseButtonDown(int btn) => (bool)_getMouseButtonDownMethod.Invoke(null, new object[] { btn }); public bool GetMouseButtonDown(int btn) => (bool)_getMouseButtonDownMethod.Invoke(null, new object[] { btn });
public override void Init() public void Init()
{ {
ExplorerCore.Log("Initializing Legacy Input support..."); ExplorerCore.Log("Initializing Legacy Input support...");

View File

@ -8,18 +8,16 @@ namespace Explorer.Input
{ {
// Just a stub for games where no Input module was able to load at all. // Just a stub for games where no Input module was able to load at all.
public class NoInput : AbstractInput public class NoInput : IAbstractInput
{ {
public override Vector2 MousePosition => Vector2.zero; public Vector2 MousePosition => Vector2.zero;
public override bool GetKey(KeyCode key) => false; public bool GetKey(KeyCode key) => false;
public bool GetKeyDown(KeyCode key) => false;
public override bool GetKeyDown(KeyCode key) => false; public bool GetMouseButton(int btn) => false;
public bool GetMouseButtonDown(int btn) => false;
public override bool GetMouseButton(int btn) => false; public void Init() { }
public override bool GetMouseButtonDown(int btn) => false;
public override void Init() { }
} }
} }

View File

@ -15,16 +15,13 @@ namespace Explorer.Tests
public static class StaticTestClass public static class StaticTestClass
{ {
public static int StaticProperty => 5; public static int StaticProperty => 5;
public static int StaticField = 69; public static int StaticField = 69;
public static List<string> StaticList = new List<string> public static List<string> StaticList = new List<string>
{ {
"one", "one",
"two", "two",
"three", "three",
}; };
public static void StaticMethod() { } public static void StaticMethod() { }
} }
@ -34,6 +31,14 @@ namespace Explorer.Tests
public static TestClass Instance => m_instance ?? (m_instance = new TestClass()); public static TestClass Instance => m_instance ?? (m_instance = new TestClass());
private static TestClass m_instance; private static TestClass m_instance;
public static bool ReadSetOnlyProperty => m_setOnlyProperty;
public static bool SetOnlyProperty
{
set => m_setOnlyProperty = value;
}
private static bool m_setOnlyProperty;
public Texture2D TestTexture = UIStyles.MakeTex(200, 200, Color.white); public Texture2D TestTexture = UIStyles.MakeTex(200, 200, Color.white);
public static Sprite TestSprite; public static Sprite TestSprite;

View File

@ -17,32 +17,25 @@ namespace Explorer.UI
} }
private static bool m_forceUnlock; private static bool m_forceUnlock;
private static CursorLockMode m_lastLockMode;
private static bool m_lastVisibleState;
private static bool m_currentlySettingCursor = false;
public static bool ShouldForceMouse => ExplorerCore.ShowMenu && Unlock; public static bool ShouldForceMouse => ExplorerCore.ShowMenu && Unlock;
private static Type CursorType => m_cursorType ?? (m_cursorType = ReflectionHelpers.GetTypeByName("UnityEngine.Cursor")); private static CursorLockMode m_lastLockMode;
private static bool m_lastVisibleState;
private static bool m_currentlySettingCursor = false;
private static Type CursorType
=> m_cursorType
?? (m_cursorType = ReflectionHelpers.GetTypeByName("UnityEngine.Cursor"));
private static Type m_cursorType; private static Type m_cursorType;
public static void Init() public static void Init()
{ {
try try
{ {
// Check if Cursor class is loaded
if (CursorType == null) if (CursorType == null)
{ {
ExplorerCore.Log("Trying to manually load Cursor module..."); throw new Exception("Could not find Type 'UnityEngine.Cursor'!");
if (ReflectionHelpers.LoadModule("UnityEngine.CoreModule") && CursorType != null)
{
ExplorerCore.Log("Ok!");
}
else
{
throw new Exception("Could not load UnityEngine.Cursor module!");
}
} }
// Get current cursor state and enable cursor // Get current cursor state and enable cursor
@ -91,7 +84,8 @@ namespace Explorer.UI
} }
catch (Exception e) catch (Exception e)
{ {
ExplorerCore.Log($"[NON-FATAL] Couldn't patch a method: {e.Message}"); string s = setter ? "set_" : "get_" ;
ExplorerCore.Log($"Unable to patch Cursor.{s}{property}: {e.Message}");
} }
} }

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using Explorer.UI.Shared; using Explorer.UI.Shared;
using Explorer.UI.Main; using Explorer.UI.Main;
using Explorer.Unstrip.LayerMasks;
#if CPP #if CPP
using UnhollowerRuntimeLib; using UnhollowerRuntimeLib;
#endif #endif
@ -17,6 +18,8 @@ namespace Explorer.UI.Inspectors
public GameObject TargetGO; public GameObject TargetGO;
public bool pendingDestroy;
private static bool m_hideControls; private static bool m_hideControls;
// gui element holders // gui element holders
@ -43,6 +46,8 @@ namespace Explorer.UI.Inspectors
private bool m_autoUpdateTransform; private bool m_autoUpdateTransform;
private bool m_localContext; private bool m_localContext;
private int m_layer;
private readonly List<Component> m_cachedDestroyList = new List<Component>(); private readonly List<Component> m_cachedDestroyList = new List<Component>();
private string m_addComponentInput = ""; private string m_addComponentInput = "";
@ -104,16 +109,16 @@ namespace Explorer.UI.Inspectors
{ {
try try
{ {
if (pendingDestroy) return;
if (Target == null) if (Target == null)
{ {
ExplorerCore.Log("Target is null!"); DestroyOnException(new Exception("Target was destroyed."));
DestroyWindow();
return; return;
} }
if (!TargetGO && !GetObjectAsGameObject()) if (!TargetGO && !GetObjectAsGameObject())
{ {
ExplorerCore.Log("Target was destroyed!"); DestroyOnException(new Exception("Target was destroyed."));
DestroyWindow();
return; return;
} }
@ -132,6 +137,8 @@ namespace Explorer.UI.Inspectors
TargetGO.transform.localScale = m_frozenScale; TargetGO.transform.localScale = m_frozenScale;
} }
m_layer = TargetGO.layer;
// update child objects // update child objects
var childList = new List<Transform>(); var childList = new List<Transform>();
for (int i = 0; i < TargetGO.transform.childCount; i++) for (int i = 0; i < TargetGO.transform.childCount; i++)
@ -162,7 +169,10 @@ namespace Explorer.UI.Inspectors
private void DestroyOnException(Exception e) private void DestroyOnException(Exception e)
{ {
if (pendingDestroy) return;
ExplorerCore.Log($"Exception drawing GameObject Window: {e.GetType()}, {e.Message}"); ExplorerCore.Log($"Exception drawing GameObject Window: {e.GetType()}, {e.Message}");
pendingDestroy = true;
DestroyWindow(); DestroyWindow();
} }
@ -204,6 +214,8 @@ namespace Explorer.UI.Inspectors
public override void WindowFunction(int windowID) public override void WindowFunction(int windowID)
{ {
if (pendingDestroy) return;
try try
{ {
var rect = WindowManager.TabView ? TabViewWindow.Instance.m_rect : this.m_rect; var rect = WindowManager.TabView ? TabViewWindow.Instance.m_rect : this.m_rect;
@ -250,6 +262,8 @@ namespace Explorer.UI.Inspectors
GUIUnstrip.TextArea(m_name, new GUILayoutOption[0]); GUIUnstrip.TextArea(m_name, new GUILayoutOption[0]);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
LayerControls();
// --- Horizontal Columns section --- // --- Horizontal Columns section ---
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
@ -280,6 +294,34 @@ namespace Explorer.UI.Inspectors
} }
} }
private void LayerControls()
{
GUIUnstrip.BeginHorizontal();
GUILayout.Label("Layer:", new GUILayoutOption[] { GUILayout.Width(50) });
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(30) }))
{
if (m_layer > 0)
{
m_layer--;
if (TargetGO) TargetGO.layer = m_layer;
}
}
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(30) }))
{
if (m_layer < 32)
{
m_layer++;
if (TargetGO) TargetGO.layer = m_layer;
}
}
GUILayout.Label($"{m_layer} (<color=cyan>{LayerMaskUnstrip.LayerToName(m_layer)}</color>)",
new GUILayoutOption[] { GUILayout.Width(200) });
GUILayout.EndHorizontal();
}
private void TransformList(Rect m_rect) private void TransformList(Rect m_rect)
{ {
GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null); GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);

View File

@ -208,16 +208,19 @@ namespace Explorer.UI.Inspectors
continue; continue;
} }
//ExplorerCore.Log($"Trying to cache member {sig}...");
try try
{ {
var cached = CacheFactory.GetCacheObject(member, target); var cached = CacheFactory.GetCacheObject(member, target);
if (cached != null) if (cached != null)
{ {
cachedSigs.Add(sig); cachedSigs.Add(sig);
list.Add(cached); list.Add(cached);
cached.ReflectionException = exception;
if (string.IsNullOrEmpty(cached.ReflectionException))
{
cached.ReflectionException = exception;
}
} }
} }
catch (Exception e) catch (Exception e)

View File

@ -198,31 +198,51 @@ namespace Explorer.UI
return m_toStringMethod; return m_toStringMethod;
} }
private string GetButtonLabel() public string GetButtonLabel()
{ {
if (Value == null) return null; if (Value == null) return null;
string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString(); var valueType = ReflectionHelpers.GetActualType(Value);
var classColor = ValueType.IsAbstract && ValueType.IsSealed string label;
? Syntax.Class_Static
: Syntax.Class_Instance;
string typeLabel = $"<color={classColor}>{ValueType.FullName}</color>"; if (valueType == typeof(TextAsset))
if (Value is UnityEngine.Object)
{ {
label = label.Replace($"({ValueType.FullName})", $"({typeLabel})"); var textAsset = Value as TextAsset;
label = textAsset.text;
if (label.Length > 10)
{
label = $"{label.Substring(0, 10)}...";
}
label = $"\"{label}\" {textAsset.name} (<color={Syntax.Class_Instance}>UnityEngine.TextAsset</color>)";
} }
else else
{ {
if (!label.Contains(ValueType.FullName)) label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
var classColor = valueType.IsAbstract && valueType.IsSealed
? Syntax.Class_Static
: Syntax.Class_Instance;
string typeLabel = $"<color={classColor}>{valueType.FullName}</color>";
if (Value is UnityEngine.Object)
{ {
label += $" ({typeLabel})"; label = label.Replace($"({valueType.FullName})", $"({typeLabel})");
} }
else else
{ {
label = label.Replace(ValueType.FullName, typeLabel); if (!label.Contains(valueType.FullName))
{
label += $" ({typeLabel})";
}
else
{
label = label.Replace(valueType.FullName, typeLabel);
}
} }
} }

View File

@ -10,6 +10,9 @@ using Explorer.CacheObject;
namespace Explorer.UI namespace Explorer.UI
{ {
// TODO: Re-work class using InteractiveEnumerable or maybe InteractiveCollection for the Keys/Value lists.
// Make the keys and values editable.
public class InteractiveDictionary : InteractiveValue, IExpandHeight public class InteractiveDictionary : InteractiveValue, IExpandHeight
{ {
public bool IsExpanded { get; set; } public bool IsExpanded { get; set; }
@ -158,7 +161,7 @@ namespace Explorer.UI
m_cachedValues = values.ToArray(); m_cachedValues = values.ToArray();
} }
private bool EnsureDictionaryIsSupported() public bool EnsureDictionaryIsSupported()
{ {
if (typeof(IDictionary).IsAssignableFrom(ValueType)) if (typeof(IDictionary).IsAssignableFrom(ValueType))
{ {
@ -177,6 +180,11 @@ namespace Explorer.UI
.GetField("NativeClassPtr") .GetField("NativeClassPtr")
.GetValue(null); .GetValue(null);
if (ptr == IntPtr.Zero)
{
return false;
}
return Il2CppSystem.Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(ptr)) is Il2CppSystem.Type; return Il2CppSystem.Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(ptr)) is Il2CppSystem.Type;
} }
} }

View File

@ -2,27 +2,50 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Explorer.Helpers;
using UnityEngine; using UnityEngine;
namespace Explorer.UI namespace Explorer.UI
{ {
public class InteractiveSprite : InteractiveTexture2D public class InteractiveSprite : InteractiveTexture2D
{ {
public override void GetTexture2D() private Sprite refSprite;
public override void UpdateValue()
{ {
#if CPP #if CPP
if (Value != null && Value.Il2CppCast(typeof(Sprite)) is Sprite sprite) if (Value != null && Value.Il2CppCast(typeof(Sprite)) is Sprite sprite)
{
refSprite = sprite;
}
#else #else
if (Value is Sprite sprite) if (Value is Sprite sprite)
#endif
{ {
currentTex = sprite.texture; refSprite = sprite;
texContent = new GUIContent }
{ #endif
image = currentTex
}; base.UpdateValue();
}
public override void GetTexture2D()
{
if (refSprite)
{
currentTex = refSprite.texture;
} }
} }
public override void GetGUIContent()
{
// Check if the Sprite.textureRect is just the entire texture
if (refSprite.textureRect != new Rect(0, 0, currentTex.width, currentTex.height))
{
// It's not, do a sub-copy.
currentTex = Texture2DHelpers.Copy(refSprite.texture, refSprite.textureRect);
}
base.GetGUIContent();
}
} }
} }

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Explorer.UI
{
// This class is possibly unnecessary.
// It's just for CacheMembers that have 'Texture' as the value type, but is actually a Texture2D.
public class InteractiveTexture : InteractiveTexture2D
{
public override void GetTexture2D()
{
#if CPP
if (Value != null && Value.Il2CppCast(typeof(Texture2D)) is Texture2D tex)
#else
if (Value is Texture2D tex)
#endif
{
currentTex = tex;
texContent = new GUIContent
{
image = currentTex
};
}
}
}
}

View File

@ -6,6 +6,7 @@ using Explorer.CacheObject;
using Explorer.Config; using Explorer.Config;
using UnityEngine; using UnityEngine;
using System.IO; using System.IO;
using Explorer.Helpers;
#if CPP #if CPP
using Explorer.Unstrip.ImageConversion; using Explorer.Unstrip.ImageConversion;
#endif #endif
@ -42,35 +43,37 @@ namespace Explorer.UI
if (Value is Texture2D tex) if (Value is Texture2D tex)
#endif #endif
{ {
currentTex = tex; currentTex = tex;
texContent = new GUIContent
{
image = currentTex
};
} }
} }
public virtual void GetGUIContent()
{
texContent = new GUIContent
{
image = currentTex
};
}
public override void DrawValue(Rect window, float width) public override void DrawValue(Rect window, float width)
{ {
GUIUnstrip.BeginVertical(); GUIUnstrip.BeginVertical();
GUIUnstrip.BeginHorizontal(); GUIUnstrip.BeginHorizontal();
if (currentTex) if (currentTex && !IsExpanded)
{ {
if (!IsExpanded) if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
{ {
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) })) IsExpanded = true;
{ GetGUIContent();
IsExpanded = true;
}
} }
else }
else if (currentTex)
{
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
{ {
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) })) IsExpanded = false;
{
IsExpanded = false;
}
} }
} }
@ -112,29 +115,22 @@ namespace Explorer.UI
if (GUILayout.Button("Save to PNG", new GUILayoutOption[] { GUILayout.Width(100f) })) if (GUILayout.Button("Save to PNG", new GUILayoutOption[] { GUILayout.Width(100f) }))
{ {
if (currentTex) var name = RemoveInvalidFilenameChars(currentTex.name ?? "");
if (string.IsNullOrEmpty(name))
{ {
var name = RemoveInvalidFilenameChars(currentTex.name ?? ""); if (OwnerCacheObject is CacheMember cacheMember)
if (string.IsNullOrEmpty(name))
{ {
if (OwnerCacheObject is CacheMember cacheMember) name = cacheMember.MemInfo.Name;
{ }
name = cacheMember.MemInfo.Name; else
} {
else name = "UNTITLED";
{
name = "UNTITLED";
}
} }
SaveTextureAsPNG(currentTex, saveFolder, name, false);
ExplorerCore.Log($@"Saved to {saveFolder}\{name}.png!");
}
else
{
ExplorerCore.Log("Cannot save a null texture!");
} }
Texture2DHelpers.SaveTextureAsPNG(currentTex, saveFolder, name, false);
ExplorerCore.Log($@"Saved to {saveFolder}\{name}.png!");
} }
} }
@ -148,107 +144,6 @@ namespace Explorer.UI
return s; return s;
} }
public static void SaveTextureAsPNG(Texture2D tex, string dir, string name, bool isDTXnmNormal = false)
{
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
byte[] data;
var savepath = dir + @"\" + name + ".png";
try
{
if (isDTXnmNormal)
{
tex = DTXnmToRGBA(tex);
tex.Apply(false, false);
}
data = tex.EncodeToPNG();
if (data == null)
{
ExplorerCore.Log("Couldn't get data with EncodeToPNG (probably ReadOnly?), trying manually...");
throw new Exception();
}
}
catch
{
var origFilter = tex.filterMode;
tex.filterMode = FilterMode.Point;
RenderTexture rt = RenderTexture.GetTemporary(tex.width, tex.height);
rt.filterMode = FilterMode.Point;
RenderTexture.active = rt;
Graphics.Blit(tex, rt);
Texture2D _newTex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
_newTex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
if (isDTXnmNormal)
{
_newTex = DTXnmToRGBA(_newTex);
}
_newTex.Apply(false, false);
RenderTexture.active = null;
tex.filterMode = origFilter;
data = _newTex.EncodeToPNG();
//data = _newTex.GetRawTextureData();
}
if (data == null || data.Length < 1)
{
ExplorerCore.LogWarning("Couldn't get any data for the texture!");
}
else
{
#if CPP
// The IL2CPP method will return invalid byte data.
// However, we can just iterate into safe C# byte[] array.
byte[] safeData = new byte[data.Length];
for (int i = 0; i < data.Length; i++)
{
safeData[i] = (byte)data[i]; // not sure if cast is needed
}
File.WriteAllBytes(savepath, safeData);
#else
File.WriteAllBytes(savepath, data);
#endif
}
}
// Converts DTXnm-format Normal Map to RGBA-format Normal Map.
public static Texture2D DTXnmToRGBA(Texture2D tex)
{
Color[] colors = tex.GetPixels();
for (int i = 0; i < colors.Length; i++)
{
Color c = colors[i];
c.r = c.a * 2 - 1; // red <- alpha
c.g = c.g * 2 - 1; // green is always the same
Vector2 rg = new Vector2(c.r, c.g); //this is the red-green vector
c.b = Mathf.Sqrt(1 - Mathf.Clamp01(Vector2.Dot(rg, rg))); //recalculate the blue channel
colors[i] = new Color(
(c.r * 0.5f) + 0.5f,
(c.g * 0.5f) + 0.25f,
(c.b * 0.5f) + 0.5f
);
}
var newtex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
newtex.SetPixels(colors);
return newtex;
}
} }
} }

View File

@ -80,12 +80,13 @@ namespace Explorer.UI
if (OwnerCacheObject.CanWrite) if (OwnerCacheObject.CanWrite)
{ {
b = GUILayout.Toggle(b, label, new GUILayoutOption[0]); Value = GUILayout.Toggle(b, label, new GUILayoutOption[] { GUILayout.Width(60) });
if (b != (bool)Value) DrawApplyButton();
{ //if (b != (bool)Value)
Value = b; //{
OwnerCacheObject.SetValue(); // Value = b;
} // OwnerCacheObject.SetValue();
//}
} }
else else
{ {
@ -104,13 +105,8 @@ namespace Explorer.UI
GUILayout.Label("<color=#2df7b2><i>" + ValueType.Name + "</i></color>", new GUILayoutOption[] { GUILayout.Width(50) }); GUILayout.Label("<color=#2df7b2><i>" + ValueType.Name + "</i></color>", new GUILayoutOption[] { GUILayout.Width(50) });
m_valueToString = GUIUnstrip.TextArea(m_valueToString, new GUILayoutOption[] { GUILayout.ExpandWidth(true) }); m_valueToString = GUIUnstrip.TextArea(m_valueToString, new GUILayoutOption[] { GUILayout.ExpandWidth(true) });
if (OwnerCacheObject.CanWrite)
{ DrawApplyButton();
if (GUILayout.Button("<color=#00FF00>Apply</color>", new GUILayoutOption[] { GUILayout.Width(60) }))
{
SetValueFromInput();
}
}
if (ModConfig.Instance.Bitwise_Support && m_canBitwiseOperate) if (ModConfig.Instance.Bitwise_Support && m_canBitwiseOperate)
{ {
@ -129,6 +125,24 @@ namespace Explorer.UI
GUILayout.EndVertical(); GUILayout.EndVertical();
} }
private void DrawApplyButton()
{
if (OwnerCacheObject.CanWrite)
{
if (GUILayout.Button("<color=#00FF00>Apply</color>", new GUILayoutOption[] { GUILayout.Width(60) }))
{
if (m_isBool)
{
OwnerCacheObject.SetValue();
}
else
{
SetValueFromInput();
}
}
}
}
private void DrawBitwise() private void DrawBitwise()
{ {
if (OwnerCacheObject.CanWrite) if (OwnerCacheObject.CanWrite)

View File

@ -63,26 +63,36 @@ namespace Explorer.UI.Main
toggleKeyInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); toggleKeyInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
UIStyles.HorizontalLine(Color.black, true);
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label($"Default Window Size:", new GUILayoutOption[] { GUILayout.Width(215f) }); GUILayout.Label($"Default Window Size:", new GUILayoutOption[] { GUILayout.Width(215f) });
defaultSizeInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); defaultSizeInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
UIStyles.HorizontalLine(Color.black, true);
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label($"Default Items per Page:", new GUILayoutOption[] { GUILayout.Width(215f) }); GUILayout.Label($"Default Items per Page:", new GUILayoutOption[] { GUILayout.Width(215f) });
defaultPageLimitInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); defaultPageLimitInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
UIStyles.HorizontalLine(Color.black, true);
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label($"Enable Bitwise Editing:", new GUILayoutOption[] { GUILayout.Width(215f) }); GUILayout.Label($"Enable Bitwise Editing:", new GUILayoutOption[] { GUILayout.Width(215f) });
bitwiseSupportInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); bitwiseSupportInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
UIStyles.HorizontalLine(Color.black, true);
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label($"Enable Tab View:", new GUILayoutOption[] { GUILayout.Width(215f) }); GUILayout.Label($"Enable Tab View:", new GUILayoutOption[] { GUILayout.Width(215f) });
tabViewInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); tabViewInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
UIStyles.HorizontalLine(Color.black, true);
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]); GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label($"Default Output Path:", new GUILayoutOption[] { GUILayout.Width(215f) }); GUILayout.Label($"Default Output Path:", new GUILayoutOption[] { GUILayout.Width(215f) });
defaultOutputPathInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f); defaultOutputPathInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);

View File

@ -6,6 +6,7 @@ using System.Reflection;
using UnityEngine; using UnityEngine;
using Explorer.UI.Shared; using Explorer.UI.Shared;
using Explorer.CacheObject; using Explorer.CacheObject;
using System.Threading;
namespace Explorer.UI.Main namespace Explorer.UI.Main
{ {
@ -15,9 +16,13 @@ namespace Explorer.UI.Main
public override string Name { get => "Search"; } public override string Name { get => "Search"; }
private int MaxSearchResults = 5000;
private string m_searchInput = ""; private string m_searchInput = "";
private string m_typeInput = ""; private string m_typeInput = "";
//private bool m_cachingResults;
private Vector2 resultsScroll = Vector2.zero; private Vector2 resultsScroll = Vector2.zero;
public PageHelper Pages = new PageHelper(); public PageHelper Pages = new PageHelper();
@ -58,6 +63,8 @@ namespace Explorer.UI.Main
private void CacheResults(IEnumerable results, bool isStaticClasses = false) private void CacheResults(IEnumerable results, bool isStaticClasses = false)
{ {
//m_cachingResults = true;
m_searchResults = new List<CacheObjectBase>(); m_searchResults = new List<CacheObjectBase>();
foreach (var obj in results) foreach (var obj in results)
@ -67,6 +74,9 @@ namespace Explorer.UI.Main
#if CPP #if CPP
if (toCache is Il2CppSystem.Object ilObject) if (toCache is Il2CppSystem.Object ilObject)
{ {
var type = ReflectionHelpers.GetActualType(ilObject);
ilObject = (Il2CppSystem.Object)ilObject.Il2CppCast(type);
toCache = ilObject.TryCast<GameObject>() ?? ilObject.TryCast<Transform>()?.gameObject ?? ilObject; toCache = ilObject.TryCast<GameObject>() ?? ilObject.TryCast<Transform>()?.gameObject ?? ilObject;
} }
#else #else
@ -76,6 +86,14 @@ namespace Explorer.UI.Main
} }
#endif #endif
if (toCache is TextAsset textAsset)
{
if (string.IsNullOrEmpty(textAsset.text))
{
continue;
}
}
var cache = CacheFactory.GetCacheObject(toCache); var cache = CacheFactory.GetCacheObject(toCache);
cache.IsStaticClassSearchResult = isStaticClasses; cache.IsStaticClassSearchResult = isStaticClasses;
m_searchResults.Add(cache); m_searchResults.Add(cache);
@ -83,183 +101,25 @@ namespace Explorer.UI.Main
Pages.ItemCount = m_searchResults.Count; Pages.ItemCount = m_searchResults.Count;
Pages.PageOffset = 0; Pages.PageOffset = 0;
results = null;
//m_cachingResults = false;
} }
public override void DrawWindow()
{
try
{
// helpers
GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
GUILayout.Label("<b><color=orange>Helpers</color></b>", new GUILayoutOption[] { GUILayout.Width(70) });
if (GUILayout.Button("Find Static Instances", new GUILayoutOption[] { GUILayout.Width(180) }))
{
CacheResults(GetStaticInstances());
}
if (GUILayout.Button("Find Static Classes", new GUILayoutOption[] { GUILayout.Width(180) }))
{
CacheResults(GetStaticClasses(), true);
}
GUILayout.EndHorizontal();
// search box
SearchBox();
// results
GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label("<b><color=orange>Results </color></b>" + " (" + m_searchResults.Count + ")", new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.UpperLeft;
int count = m_searchResults.Count;
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
Pages.DrawLimitInputArea();
if (count > Pages.ItemsPerPage)
{
// prev/next page buttons
if (Pages.ItemCount > Pages.ItemsPerPage)
{
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
{
Pages.TurnPage(Turn.Left, ref this.resultsScroll);
}
Pages.CurrentPageLabel();
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
{
Pages.TurnPage(Turn.Right, ref this.resultsScroll);
}
}
}
GUILayout.EndHorizontal();
resultsScroll = GUIUnstrip.BeginScrollView(resultsScroll);
var _temprect = new Rect(MainMenu.MainRect.x, MainMenu.MainRect.y, MainMenu.MainRect.width + 160, MainMenu.MainRect.height);
if (m_searchResults.Count > 0)
{
int offset = Pages.CalculateOffsetIndex();
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
{
m_searchResults[i].Draw(MainMenu.MainRect, 0f);
}
}
else
{
GUILayout.Label("<color=red><i>No results found!</i></color>", new GUILayoutOption[0]);
}
GUIUnstrip.EndScrollView();
GUILayout.EndVertical();
}
catch
{
m_searchResults.Clear();
}
}
private void SearchBox()
{
GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
// ----- GameObject Search -----
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label("<b><color=orange>Search</color></b>", new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.UpperLeft;
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Name Contains:", new GUILayoutOption[] { GUILayout.Width(100) });
m_searchInput = GUIUnstrip.TextField(m_searchInput, new GUILayoutOption[] { GUILayout.Width(200) });
GUILayout.EndHorizontal();
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Class Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
ClassFilterToggle(TypeFilter.Object, "Object");
ClassFilterToggle(TypeFilter.GameObject, "GameObject");
ClassFilterToggle(TypeFilter.Component, "Component");
ClassFilterToggle(TypeFilter.Custom, "Custom");
GUILayout.EndHorizontal();
if (TypeMode == TypeFilter.Custom)
{
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.MiddleRight;
GUILayout.Label("Custom Class:", new GUILayoutOption[] { GUILayout.Width(250) });
GUI.skin.label.alignment = TextAnchor.UpperLeft;
m_typeInput = GUIUnstrip.TextField(m_typeInput, new GUILayoutOption[] { GUILayout.Width(250) });
GUILayout.EndHorizontal();
}
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Scene Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
SceneFilterToggle(SceneFilter.Any, "Any", 60);
SceneFilterToggle(SceneFilter.This, "This Scene", 100);
SceneFilterToggle(SceneFilter.DontDestroy, "DontDestroyOnLoad", 140);
SceneFilterToggle(SceneFilter.None, "No Scene", 80);
GUILayout.EndHorizontal();
if (GUILayout.Button("<b><color=cyan>Search</color></b>", new GUILayoutOption[0]))
{
Search();
}
GUILayout.EndVertical();
}
private void ClassFilterToggle(TypeFilter mode, string label)
{
if (TypeMode == mode)
{
GUI.color = Color.green;
}
else
{
GUI.color = Color.white;
}
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
{
TypeMode = mode;
}
GUI.color = Color.white;
}
private void SceneFilterToggle(SceneFilter mode, string label, float width)
{
if (SceneMode == mode)
{
GUI.color = Color.green;
}
else
{
GUI.color = Color.white;
}
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(width) }))
{
SceneMode = mode;
}
GUI.color = Color.white;
}
// -------------- ACTUAL METHODS (not Gui draw) ----------------- //
// ======= search functions =======
private void Search() private void Search()
{ {
//if (m_cachingResults)
//{
// ExplorerCore.Log("Cannot search now, we are already caching results...");
// return;
//}
Pages.PageOffset = 0; Pages.PageOffset = 0;
CacheResults(FindAllObjectsOfType(m_searchInput, m_typeInput));
// Would use Task, but Explorer is .NET 3.5-compatible.
var objectsOfType = FindAllObjectsOfType(m_searchInput, m_typeInput);
CacheResults(objectsOfType);
} }
private List<object> FindAllObjectsOfType(string searchQuery, string typeName) private List<object> FindAllObjectsOfType(string searchQuery, string typeName)
@ -323,7 +183,7 @@ namespace Explorer.UI.Main
int i = 0; int i = 0;
foreach (var obj in allObjectsOfType) foreach (var obj in allObjectsOfType)
{ {
if (i >= 2000) break; if (i >= MaxSearchResults) break;
if (searchQuery != "" && !obj.name.ToLower().Contains(searchQuery.ToLower())) if (searchQuery != "" && !obj.name.ToLower().Contains(searchQuery.ToLower()))
{ {
@ -355,6 +215,10 @@ namespace Explorer.UI.Main
i++; i++;
} }
allObjectsOfType = null;
searchType = null;
searchQuery = null;
return matches; return matches;
} }
@ -394,8 +258,6 @@ namespace Explorer.UI.Main
return false; return false;
} }
// ====== other ========
private static bool FilterName(string name) private static bool FilterName(string name)
{ {
// Don't really want these instances. // Don't really want these instances.
@ -497,5 +359,202 @@ namespace Explorer.UI.Main
return list; return list;
} }
// =========== GUI DRAW ============= //
public override void DrawWindow()
{
try
{
// helpers
GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
GUILayout.Label("<b><color=orange>Helpers</color></b>", new GUILayoutOption[] { GUILayout.Width(70) });
if (GUILayout.Button("Find Static Instances", new GUILayoutOption[] { GUILayout.Width(180) }))
{
CacheResults(GetStaticInstances());
}
if (GUILayout.Button("Find Static Classes", new GUILayoutOption[] { GUILayout.Width(180) }))
{
CacheResults(GetStaticClasses(), true);
}
GUILayout.EndHorizontal();
// search box
SearchBox();
// results
GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label("<b><color=orange>Results </color></b>" + " (" + m_searchResults.Count + ")", new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.UpperLeft;
int count = m_searchResults.Count;
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
Pages.DrawLimitInputArea();
if (count > Pages.ItemsPerPage)
{
// prev/next page buttons
if (Pages.ItemCount > Pages.ItemsPerPage)
{
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
{
Pages.TurnPage(Turn.Left, ref this.resultsScroll);
}
Pages.CurrentPageLabel();
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
{
Pages.TurnPage(Turn.Right, ref this.resultsScroll);
}
}
}
GUILayout.EndHorizontal();
resultsScroll = GUIUnstrip.BeginScrollView(resultsScroll);
var _temprect = new Rect(MainMenu.MainRect.x, MainMenu.MainRect.y, MainMenu.MainRect.width + 160, MainMenu.MainRect.height);
if (m_searchResults.Count > 0)
{
int offset = Pages.CalculateOffsetIndex();
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
{
if (i >= m_searchResults.Count) break;
m_searchResults[i].Draw(MainMenu.MainRect, 0f);
}
}
else
{
GUILayout.Label("<color=red><i>No results found!</i></color>", new GUILayoutOption[0]);
}
GUIUnstrip.EndScrollView();
GUILayout.EndVertical();
}
catch (Exception e)
{
if (!e.Message.Contains("in a group with only"))
{
ExplorerCore.Log("Exception drawing search results!");
while (e != null)
{
ExplorerCore.Log(e);
e = e.InnerException;
}
m_searchResults.Clear();
}
}
}
private void SearchBox()
{
GUIUnstrip.BeginVertical(GUIContent.none, GUI.skin.box, null);
// ----- GameObject Search -----
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label("<b><color=orange>Search</color></b>", new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.UpperLeft;
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Name Contains:", new GUILayoutOption[] { GUILayout.Width(100) });
m_searchInput = GUIUnstrip.TextField(m_searchInput, new GUILayoutOption[] { GUILayout.Width(200) });
GUILayout.Label("Max Results:", new GUILayoutOption[] { GUILayout.Width(100) });
var s = MaxSearchResults.ToString();
s = GUIUnstrip.TextField(s, new GUILayoutOption[] { GUILayout.Width(80) });
if (int.TryParse(s, out int i))
{
MaxSearchResults = i;
}
GUILayout.EndHorizontal();
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Class Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
ClassFilterToggle(TypeFilter.Object, "Object");
ClassFilterToggle(TypeFilter.GameObject, "GameObject");
ClassFilterToggle(TypeFilter.Component, "Component");
ClassFilterToggle(TypeFilter.Custom, "Custom");
GUILayout.EndHorizontal();
if (TypeMode == TypeFilter.Custom)
{
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUI.skin.label.alignment = TextAnchor.MiddleRight;
GUILayout.Label("Custom Class:", new GUILayoutOption[] { GUILayout.Width(250) });
GUI.skin.label.alignment = TextAnchor.UpperLeft;
m_typeInput = GUIUnstrip.TextField(m_typeInput, new GUILayoutOption[] { GUILayout.Width(250) });
GUILayout.EndHorizontal();
}
GUIUnstrip.BeginHorizontal(new GUILayoutOption[0]);
GUILayout.Label("Scene Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
SceneFilterToggle(SceneFilter.Any, "Any", 60);
SceneFilterToggle(SceneFilter.This, "This Scene", 100);
SceneFilterToggle(SceneFilter.DontDestroy, "DontDestroyOnLoad", 140);
SceneFilterToggle(SceneFilter.None, "No Scene", 80);
GUILayout.EndHorizontal();
if (GUILayout.Button("<b><color=cyan>Search</color></b>", new GUILayoutOption[0]))
{
Search();
}
//if (m_cachingResults)
//{
// GUILayout.Label("Searching...", new GUILayoutOption[0]);
//}
//else
//{
// if (GUILayout.Button("<b><color=cyan>Search</color></b>", new GUILayoutOption[0]))
// {
// Search();
// }
//}
GUILayout.EndVertical();
}
private void ClassFilterToggle(TypeFilter mode, string label)
{
if (TypeMode == mode)
{
GUI.color = Color.green;
}
else
{
GUI.color = Color.white;
}
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
{
TypeMode = mode;
}
GUI.color = Color.white;
}
private void SceneFilterToggle(SceneFilter mode, string label, float width)
{
if (SceneMode == mode)
{
GUI.color = Color.green;
}
else
{
GUI.color = Color.white;
}
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(width) }))
{
SceneMode = mode;
}
GUI.color = Color.white;
}
} }
} }

View File

@ -8,18 +8,17 @@ namespace Explorer.UI.Shared
{ {
public class ResizeDrag public class ResizeDrag
{ {
#if CPP
private static bool RESIZE_FAILED = false; private static bool RESIZE_FAILED = false;
#endif
public static bool IsResizing = false;
public static bool IsMouseInResizeArea = false;
private static readonly GUIContent gcDrag = new GUIContent("<-- Drag to resize -->"); private static readonly GUIContent gcDrag = new GUIContent("<-- Drag to resize -->");
private static bool isResizing = false;
private static Rect m_currentResize; private static Rect m_currentResize;
private static int m_currentWindow; private static int m_currentWindow;
public static Rect ResizeWindow(Rect _rect, int ID) public static Rect ResizeWindow(Rect _rect, int ID)
{ {
#if CPP
if (!RESIZE_FAILED) if (!RESIZE_FAILED)
{ {
var origRect = _rect; var origRect = _rect;
@ -29,31 +28,40 @@ namespace Explorer.UI.Shared
GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null); GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
GUI.skin.label.alignment = TextAnchor.MiddleCenter; GUI.skin.label.alignment = TextAnchor.MiddleCenter;
#if ML #if BIE
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) }); #if CPP // Temporary for BepInEx IL2CPP
GUILayout.Button("<-- Drag to resize -->", new GUILayoutOption[] { GUILayout.Height(15) });
#else #else
GUILayout.Button("<-- Drag to resize -->", new GUILayoutOption[] { GUILayout.Height(15) }); GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
#endif
#else
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
#endif #endif
var r = GUIUnstrip.GetLastRect(); var resizeDragArea = GUIUnstrip.GetLastRect();
var mousePos = InputManager.MousePosition; var mousePos = InputManager.MousePosition;
try try
{ {
var mouse = GUIUnstrip.ScreenToGUIPoint(new Vector2(mousePos.x, Screen.height - mousePos.y)); var mouse = GUIUnstrip.ScreenToGUIPoint(new Vector2(mousePos.x, Screen.height - mousePos.y));
if (r.Contains(mouse) && InputManager.GetMouseButtonDown(0)) if (resizeDragArea.Contains(mouse))
{ {
isResizing = true; IsMouseInResizeArea = true;
m_currentWindow = ID;
m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height); if (InputManager.GetMouseButton(0))
{
IsResizing = true;
m_currentWindow = ID;
m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height);
}
} }
else if (!InputManager.GetMouseButton(0)) else if (!InputManager.GetMouseButton(0))
{ {
isResizing = false; IsMouseInResizeArea = false;
IsResizing = false;
} }
if (isResizing && ID == m_currentWindow) if (IsResizing && ID == m_currentWindow)
{ {
_rect.width = Mathf.Max(100, m_currentResize.width + (mouse.x - m_currentResize.x)); _rect.width = Mathf.Max(100, m_currentResize.width + (mouse.x - m_currentResize.x));
_rect.height = Mathf.Max(100, m_currentResize.height + (mouse.y - m_currentResize.y)); _rect.height = Mathf.Max(100, m_currentResize.height + (mouse.y - m_currentResize.y));
@ -81,8 +89,6 @@ namespace Explorer.UI.Shared
//ExplorerCore.Log(e.StackTrace); //ExplorerCore.Log(e.StackTrace);
return origRect; return origRect;
} }
GUI.skin.label.alignment = TextAnchor.UpperLeft;
} }
else else
{ {
@ -111,44 +117,8 @@ namespace Explorer.UI.Shared
} }
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
GUI.skin.label.alignment = TextAnchor.UpperLeft;
} }
#else // mono
GUIUnstrip.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
//var r = GUILayoutUtility.GetLastRect();
var r = GUILayoutUtility.GetLastRect();
var mousePos = InputManager.MousePosition;
var mouse = GUIUnstrip.ScreenToGUIPoint(new Vector2(mousePos.x, Screen.height - mousePos.y));
if (r.Contains(mouse) && InputManager.GetMouseButtonDown(0))
{
isResizing = true;
m_currentWindow = ID;
m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height);
}
else if (!InputManager.GetMouseButton(0))
{
isResizing = false;
}
if (isResizing && ID == m_currentWindow)
{
_rect.width = Mathf.Max(100, m_currentResize.width + (mouse.x - m_currentResize.x));
_rect.height = Mathf.Max(100, m_currentResize.height + (mouse.y - m_currentResize.y));
_rect.xMax = Mathf.Min(Screen.width, _rect.xMax); // modifying xMax affects width, not x
_rect.yMax = Mathf.Min(Screen.height, _rect.yMax); // modifying yMax affects height, not y
}
GUILayout.EndHorizontal();
#endif
GUI.skin.label.alignment = TextAnchor.MiddleLeft; GUI.skin.label.alignment = TextAnchor.MiddleLeft;
return _rect; return _rect;

View File

@ -70,6 +70,15 @@ namespace Explorer.UI
int rowCount = 0; int rowCount = 0;
for (int i = 0; i < WindowManager.Windows.Count; i++) for (int i = 0; i < WindowManager.Windows.Count; i++)
{ {
var window = WindowManager.Windows[i];
// Prevent trying to draw destroyed UnityEngine.Objects
// before the WindowManager removes them.
if (window.Target is UnityEngine.Object uObj && !uObj)
{
continue;
}
if (rowCount >= tabPerRow) if (rowCount >= tabPerRow)
{ {
rowCount = 0; rowCount = 0;
@ -82,7 +91,6 @@ namespace Explorer.UI
string color = focused ? "<color=lime>" : "<color=orange>"; string color = focused ? "<color=lime>" : "<color=orange>";
GUI.color = focused ? Color.green : Color.white; GUI.color = focused ? Color.green : Color.white;
var window = WindowManager.Windows[i];
if (GUILayout.Button(color + window.Title + "</color>", new GUILayoutOption[] { GUILayout.Width(200) })) if (GUILayout.Button(color + window.Title + "</color>", new GUILayoutOption[] { GUILayout.Width(200) }))
{ {
TargetTabID = i; TargetTabID = i;

View File

@ -11,6 +11,26 @@ namespace Explorer.UI
public static bool TabView = Config.ModConfig.Instance.Tab_View; public static bool TabView = Config.ModConfig.Instance.Tab_View;
public static bool IsMouseInWindow
{
get
{
if (!ExplorerCore.ShowMenu)
{
return false;
}
foreach (var window in Windows)
{
if (RectContainsMouse(window.m_rect))
{
return true;
}
}
return RectContainsMouse(MainMenu.MainRect);
}
}
public static List<WindowBase> Windows = new List<WindowBase>(); public static List<WindowBase> Windows = new List<WindowBase>();
public static int CurrentWindowID { get; set; } = 500000; public static int CurrentWindowID { get; set; } = 500000;
private static Rect m_lastWindowRect; private static Rect m_lastWindowRect;
@ -123,26 +143,6 @@ namespace Explorer.UI
return new_window; return new_window;
} }
public static bool IsMouseInWindow
{
get
{
if (!ExplorerCore.ShowMenu)
{
return false;
}
foreach (var window in Windows)
{
if (RectContainsMouse(window.m_rect))
{
return true;
}
}
return RectContainsMouse(MainMenu.MainRect);
}
}
private static bool RectContainsMouse(Rect rect) private static bool RectContainsMouse(Rect rect)
{ {
var mousePos = InputManager.MousePosition; var mousePos = InputManager.MousePosition;

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
#if CPP
using UnhollowerBaseLib;
#endif
namespace Explorer.Unstrip.LayerMasks
{
public static class LayerMaskUnstrip
{
#if CPP
internal delegate IntPtr d_LayerToName(int layer);
internal static d_LayerToName LayerToName_iCall =
IL2CPP.ResolveICall<d_LayerToName>("UnityEngine.LayerMask::LayerToName");
public static string LayerToName(int layer)
{
var ptr = LayerToName_iCall(layer);
return IL2CPP.Il2CppStringToManaged(ptr);
}
#else
public static string LayerToName(int layer)
{
return LayerMask.LayerToName(layer);
}
#endif
}
}

View File

@ -26,7 +26,7 @@ namespace Explorer.Unstrip.Scenes
IL2CPP.ResolveICall<GetRootGameObjectsInternal_delegate>("UnityEngine.SceneManagement.Scene::GetRootGameObjectsInternal"); IL2CPP.ResolveICall<GetRootGameObjectsInternal_delegate>("UnityEngine.SceneManagement.Scene::GetRootGameObjectsInternal");
//Scene.rootCount; //Scene.rootCount;
public static int GetRootCount_Internal(UnityEngine.SceneManagement.Scene scene) public static int GetRootCount_Internal(Scene scene)
{ {
return GetRootCountInternal_iCall(scene.handle); return GetRootCountInternal_iCall(scene.handle);
} }