mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-23 00:52:31 +08:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
d4dac58fc8 | |||
77b97cbe17 | |||
c6f0f34ac0 | |||
d1f4f74d32 | |||
f13068bf01 | |||
dfc288a101 | |||
544009dc21 | |||
fdfaaadd89 | |||
58d60a10d4 | |||
0432c6d56c | |||
8c34aa2be5 | |||
4a1c54fac1 | |||
190467fa5c | |||
44f54d9190 | |||
3b4ea31b50 | |||
ad7b05f721 | |||
852ca8e9eb | |||
7386eca0c2 | |||
97325a5f3a | |||
82e52de557 | |||
28181e2266 | |||
6dfa4806ce | |||
27f6a6ca52 | |||
cd7b260ea7 | |||
ba986274be | |||
d181c0bee9 | |||
a9faec8cf9 | |||
a6bf91b7af |
23
README.md
23
README.md
@ -17,7 +17,6 @@
|
||||
- [Features](#features)
|
||||
- [How to install](#how-to-install)
|
||||
- [Mod Config](#mod-config)
|
||||
- [Mouse Control](#mouse-control)
|
||||
- [Building](#building)
|
||||
- [Credits](#credits)
|
||||
|
||||
@ -25,11 +24,9 @@
|
||||
|
||||
| Mod Loader | IL2CPP | Mono |
|
||||
| ----------- | ------ | ---- |
|
||||
| [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Mono.zip) |
|
||||
| [BepInEx](https://github.com/BepInEx/BepInEx) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx.Mono.zip) |
|
||||
|
||||
<b>IL2CPP Issues:</b>
|
||||
* Some methods may still fail with a `MissingMethodException`, please let me know if you experience this (with full debug log please).
|
||||
| [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Mono.zip) |
|
||||
| Standalone | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Mono.zip) |
|
||||
|
||||
## Features
|
||||
|
||||
@ -52,15 +49,21 @@
|
||||
|
||||
0. Install [BepInEx](https://github.com/BepInEx/BepInEx) for your game.
|
||||
1. Download the UnityExplorer release for BepInEx IL2CPP or Mono above.
|
||||
2. Take the `UnityExplorer.dll` file and put it in `[GameFolder]\BepInEx\plugins\`
|
||||
3. Take the `UnityExplorer\` folder (with `explorerui.bundle`) and put it in `[GameFolder]\Mods\`, so it looks like `[GameFolder]\Mods\UnityExplorer\explorerui.bundle`.
|
||||
4. In IL2CPP, it is highly recommended to get the base Unity libs for the game's Unity version and put them in the `BepInEx\unhollowed\base\` folder.
|
||||
2. Take the `UnityExplorer.BIE.___.dll` file and put it in `[GameFolder]\BepInEx\plugins\`
|
||||
3. In IL2CPP, it is highly recommended to get the base Unity libs for the game's Unity version and put them in the `BepInEx\unity-libs\` folder.
|
||||
|
||||
### MelonLoader
|
||||
|
||||
0. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) for your game.
|
||||
1. Download the UnityExplorer release for MelonLoader IL2CPP or Mono above.
|
||||
2. Take the contents of the release and put it in the `[GameFolder]\Mods\` folder. It should look like `[GameFolder]\Mods\UnityExplorer.dll` and `[GameFolder]\Mods\UnityExplorer\explorerui.bundle`.
|
||||
2. Take the contents of the release and put it in the `[GameFolder]\Mods\` folder. It should look like `[GameFolder]\Mods\UnityExplorer.ML.___.dll`
|
||||
|
||||
### Standalone
|
||||
|
||||
0. Load the DLL from your mod or inject it.
|
||||
1. Create an instance of Unity Explorer with `new ExplorerCore();`
|
||||
2. You will need to call ExplorerCore.Update() (static method) from your Update method.
|
||||
3. Subscribe to the `ExplorerCore.OnLog__` methods for logging.
|
||||
|
||||
## Mod Config
|
||||
|
||||
@ -92,7 +95,7 @@ You can access the settings via the "Options" page of the main menu, or directly
|
||||
|
||||
If you'd like to build this yourself, you will need to have installed BepInEx and/or MelonLoader for at least one Unity game. If you want to build all 4 versions, you will need at least one IL2CPP and one Mono game, with BepInEx and MelonLoader installed for both.
|
||||
|
||||
1. Install BepInEx or MelonLoader for your game.
|
||||
1. Install BepInEx or MelonLoader for your game, or use the standalone build.
|
||||
2. Open the `src\UnityExplorer.csproj` file in a text editor.
|
||||
3. For IL2CPP builds, make sure you set `BIECppGameFolder` (for BepInEx) and/or `MLCppGameFolder` (for MelonLoader) so the project can locate the necessary references.
|
||||
4. Open the `src\UnityExplorer.sln` project.
|
||||
|
Binary file not shown.
@ -11,7 +11,7 @@ namespace UnityExplorer.Config
|
||||
public static ModConfig Instance;
|
||||
|
||||
internal static readonly IniDataParser _parser = new IniDataParser();
|
||||
internal const string INI_PATH = ExplorerCore.EXPLORER_FOLDER + @"\config.ini";
|
||||
internal static readonly string INI_PATH = Path.Combine(ExplorerCore.EXPLORER_FOLDER, "config.ini");
|
||||
|
||||
static ModConfig()
|
||||
{
|
||||
@ -22,7 +22,7 @@ namespace UnityExplorer.Config
|
||||
public KeyCode Main_Menu_Toggle = KeyCode.F7;
|
||||
public bool Force_Unlock_Mouse = true;
|
||||
public int Default_Page_Limit = 25;
|
||||
public string Default_Output_Path = ExplorerCore.EXPLORER_FOLDER;
|
||||
public string Default_Output_Path = ExplorerCore.EXPLORER_FOLDER + @"\Output";
|
||||
public bool Log_Unity_Debug = false;
|
||||
public bool Save_Logs_To_Disk = true;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityExplorer.Config;
|
||||
@ -16,10 +17,31 @@ namespace UnityExplorer
|
||||
public class ExplorerCore
|
||||
{
|
||||
public const string NAME = "UnityExplorer";
|
||||
public const string VERSION = "3.0.5";
|
||||
public const string VERSION = "3.1.8";
|
||||
public const string AUTHOR = "Sinai";
|
||||
public const string GUID = "com.sinai.unityexplorer";
|
||||
|
||||
#if ML
|
||||
public const string EXPLORER_FOLDER = @"Mods\UnityExplorer";
|
||||
#elif BIE
|
||||
public static string EXPLORER_FOLDER = Path.Combine(BepInEx.Paths.ConfigPath, "UnityExplorer");
|
||||
#elif STANDALONE
|
||||
public static string EXPLORER_FOLDER
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_explorerFolder == null)
|
||||
{
|
||||
s_explorerFolder = (new Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath;
|
||||
s_explorerFolder = Uri.UnescapeDataString(s_explorerFolder);
|
||||
s_explorerFolder = Path.GetDirectoryName(s_explorerFolder);
|
||||
}
|
||||
|
||||
return s_explorerFolder;
|
||||
}
|
||||
}
|
||||
private static string s_explorerFolder;
|
||||
#endif
|
||||
|
||||
public static ExplorerCore Instance { get; private set; }
|
||||
|
||||
@ -90,6 +112,7 @@ namespace UnityExplorer
|
||||
{
|
||||
UIManager.Init();
|
||||
Log("Initialized UnityExplorer UI.");
|
||||
// InspectorManager.Instance.Inspect(Tests.TestClass.Instance);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -160,6 +183,12 @@ namespace UnityExplorer
|
||||
}
|
||||
}
|
||||
|
||||
#if STANDALONE
|
||||
public static Action<string> OnLogMessage;
|
||||
public static Action<string> OnLogWarning;
|
||||
public static Action<string> OnLogError;
|
||||
#endif
|
||||
|
||||
public static void Log(object message, bool unity = false)
|
||||
{
|
||||
DebugConsole.Log(message?.ToString());
|
||||
@ -169,8 +198,10 @@ namespace UnityExplorer
|
||||
|
||||
#if ML
|
||||
MelonLoader.MelonLogger.Log(message?.ToString());
|
||||
#else
|
||||
#elif BIE
|
||||
ExplorerBepInPlugin.Logging?.LogMessage(message?.ToString());
|
||||
#elif STANDALONE
|
||||
OnLogMessage?.Invoke(message?.ToString());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -183,8 +214,10 @@ namespace UnityExplorer
|
||||
|
||||
#if ML
|
||||
MelonLoader.MelonLogger.LogWarning(message?.ToString());
|
||||
#else
|
||||
ExplorerBepInPlugin.Logging?.LogWarning(message?.ToString());
|
||||
#elif BIE
|
||||
ExplorerBepInPlugin.Logging?.LogWarning(message?.ToString());
|
||||
#elif STANDALONE
|
||||
OnLogWarning?.Invoke(message?.ToString());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -197,8 +230,10 @@ namespace UnityExplorer
|
||||
|
||||
#if ML
|
||||
MelonLoader.MelonLogger.LogError(message?.ToString());
|
||||
#else
|
||||
ExplorerBepInPlugin.Logging?.LogError(message?.ToString());
|
||||
#elif BIE
|
||||
ExplorerBepInPlugin.Logging?.LogError(message?.ToString());
|
||||
#elif STANDALONE
|
||||
OnLogError?.Invoke(message?.ToString());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
11
src/ExplorerStandalone.cs
Normal file
11
src/ExplorerStandalone.cs
Normal file
@ -0,0 +1,11 @@
|
||||
#if STANDALONE
|
||||
using HarmonyLib;
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
public class ExplorerStandalone
|
||||
{
|
||||
public static readonly Harmony HarmonyInstance = new Harmony(ExplorerCore.GUID);
|
||||
}
|
||||
}
|
||||
#endif
|
@ -52,7 +52,7 @@ namespace UnityExplorer.Helpers
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
public static Type GetActualType(object obj)
|
||||
public static Type GetActualType(this object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return null;
|
||||
@ -101,12 +101,41 @@ namespace UnityExplorer.Helpers
|
||||
return Il2CppToMonoType[cppType];
|
||||
|
||||
var getType = Type.GetType(cppType.AssemblyQualifiedName);
|
||||
Il2CppToMonoType.Add(cppType, getType);
|
||||
return getType;
|
||||
|
||||
if (getType != null)
|
||||
{
|
||||
Il2CppToMonoType.Add(cppType, getType);
|
||||
return getType;
|
||||
}
|
||||
else
|
||||
{
|
||||
string baseName = cppType.FullName;
|
||||
string baseAssembly = cppType.Assembly.GetName().name;
|
||||
|
||||
Type unhollowedType = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == baseAssembly)?.GetTypes().FirstOrDefault(t =>
|
||||
t.CustomAttributes.Any(ca =>
|
||||
ca.AttributeType.Name == "ObfuscatedNameAttribute" && (string)ca.ConstructorArguments[0].Value == baseName));
|
||||
|
||||
Il2CppToMonoType.Add(cppType, unhollowedType);
|
||||
return unhollowedType;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Type, IntPtr> CppClassPointers = new Dictionary<Type, IntPtr>();
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to cast the object to its underlying type.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object you want to cast.</param>
|
||||
/// <returns>The object, as the underlying type if successful or the input value if not.</returns>
|
||||
public static object Il2CppCast(this object obj) => Il2CppCast(obj, GetActualType(obj));
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to cast the object to the provided type.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object you want to cast.</param>
|
||||
/// <param name="castTo">The Type you want to cast to.</param>
|
||||
/// <returns>The object, as the type (or a normal C# object) if successful or the input value if not.</returns>
|
||||
public static object Il2CppCast(this object obj, Type castTo)
|
||||
{
|
||||
if (!(obj is Il2CppSystem.Object ilObj))
|
||||
@ -126,6 +155,39 @@ namespace UnityExplorer.Helpers
|
||||
return Activator.CreateInstance(castTo, ilObj.Pointer);
|
||||
}
|
||||
|
||||
internal static readonly Dictionary<Type, MethodInfo> s_unboxMethods = new Dictionary<Type, MethodInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to unbox the object to the underlying struct type.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object which is a struct underneath.</param>
|
||||
/// <returns>The struct if successful, otherwise null.</returns>
|
||||
public static object Unbox(this object obj) => Unbox(obj, GetActualType(obj));
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to unbox the object to the struct type.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object which is a struct underneath.</param>
|
||||
/// <param name="type">The type of the struct you want to unbox to.</param>
|
||||
/// <returns>The struct if successful, otherwise null.</returns>
|
||||
public static object Unbox(this object obj, Type type)
|
||||
{
|
||||
if (!type.IsValueType)
|
||||
return null;
|
||||
|
||||
if (!(obj is Il2CppSystem.Object))
|
||||
return obj;
|
||||
|
||||
if (!s_unboxMethods.ContainsKey(type))
|
||||
{
|
||||
s_unboxMethods.Add(type, typeof(Il2CppObjectBase)
|
||||
.GetMethod("Unbox")
|
||||
.MakeGenericMethod(type));
|
||||
}
|
||||
|
||||
return s_unboxMethods[type].Invoke(obj, new object[0]);
|
||||
}
|
||||
|
||||
public static bool Il2CppTypeNotNull(Type type) => Il2CppTypeNotNull(type, out _);
|
||||
|
||||
public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
|
||||
@ -215,50 +277,56 @@ namespace UnityExplorer.Helpers
|
||||
public static bool LoadModule(string module) => true;
|
||||
#endif
|
||||
|
||||
#if CPP
|
||||
internal static IntPtr s_cppEnumerableClassPtr;
|
||||
#endif
|
||||
|
||||
public static bool IsEnumerable(Type t)
|
||||
{
|
||||
if (typeof(IEnumerable).IsAssignableFrom(t))
|
||||
{
|
||||
return true;
|
||||
#if CPP
|
||||
try
|
||||
{
|
||||
if (s_cppEnumerableClassPtr == IntPtr.Zero)
|
||||
Il2CppTypeNotNull(typeof(Il2CppSystem.Collections.IEnumerable), out s_cppEnumerableClassPtr);
|
||||
|
||||
if (s_cppEnumerableClassPtr != IntPtr.Zero
|
||||
&& Il2CppTypeNotNull(t, out IntPtr classPtr)
|
||||
&& il2cpp_class_is_assignable_from(s_cppEnumerableClassPtr, classPtr))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#if CPP
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
|
||||
{
|
||||
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
|
||||
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
|
||||
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
|
||||
}
|
||||
else
|
||||
{
|
||||
return typeof(Il2CppSystem.Collections.IList).IsAssignableFrom(t);
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
internal static IntPtr s_cppDictionaryClassPtr;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool IsDictionary(Type t)
|
||||
{
|
||||
if (typeof(IDictionary).IsAssignableFrom(t))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#if CPP
|
||||
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
|
||||
try
|
||||
{
|
||||
return typeof(Il2CppSystem.Collections.Generic.Dictionary<,>).IsAssignableFrom(g)
|
||||
|| typeof(Il2CppSystem.Collections.Generic.IDictionary<,>).IsAssignableFrom(g);
|
||||
if (s_cppDictionaryClassPtr == IntPtr.Zero)
|
||||
if (!Il2CppTypeNotNull(typeof(Il2CppSystem.Collections.IDictionary), out s_cppDictionaryClassPtr))
|
||||
return false;
|
||||
|
||||
if (Il2CppTypeNotNull(t, out IntPtr classPtr))
|
||||
{
|
||||
if (il2cpp_class_is_assignable_from(s_cppDictionaryClassPtr, classPtr))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return typeof(Il2CppSystem.Collections.IDictionary).IsAssignableFrom(t)
|
||||
|| typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(t);
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
catch { }
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string ExceptionToString(Exception e, bool innerMost = false)
|
||||
|
@ -15,6 +15,16 @@ namespace UnityExplorer.Helpers
|
||||
private static MethodInfo EncodeToPNGMethod => m_encodeToPNGMethod ?? GetEncodeToPNGMethod();
|
||||
private static MethodInfo m_encodeToPNGMethod;
|
||||
|
||||
public static byte[] EncodeToPNGSafe(this Texture2D tex)
|
||||
{
|
||||
var method = EncodeToPNGMethod;
|
||||
|
||||
if (method.IsStatic)
|
||||
return (byte[])method.Invoke(null, new object[] { tex });
|
||||
else
|
||||
return (byte[])method.Invoke(tex, new object[0]);
|
||||
}
|
||||
|
||||
private static MethodInfo GetEncodeToPNGMethod()
|
||||
{
|
||||
if (ReflectionHelpers.GetTypeByName("UnityEngine.ImageConversion") is Type imageConversion)
|
||||
@ -60,7 +70,12 @@ namespace UnityExplorer.Helpers
|
||||
|
||||
pixels = orig.GetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
|
||||
|
||||
// use full constructor for better compatibility
|
||||
#if CPP
|
||||
var _newTex = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGBA32, Texture.GenerateAllMips, false, IntPtr.Zero);
|
||||
#else
|
||||
var _newTex = new Texture2D((int)rect.width, (int)rect.height);
|
||||
#endif
|
||||
_newTex.SetPixels(pixels);
|
||||
|
||||
return _newTex;
|
||||
|
@ -80,7 +80,11 @@ namespace UnityExplorer.Inspectors.GameObjects
|
||||
text.text = UISyntaxHighlight.ParseFullSyntax(ReflectionHelpers.GetActualType(comp), true);
|
||||
|
||||
var toggle = s_compToggles[i];
|
||||
#if CPP
|
||||
if (comp.TryCast<Behaviour>() is Behaviour behaviour)
|
||||
#else
|
||||
if (comp is Behaviour behaviour)
|
||||
#endif
|
||||
{
|
||||
if (!toggle.gameObject.activeSelf)
|
||||
toggle.gameObject.SetActive(true);
|
||||
@ -107,8 +111,11 @@ namespace UnityExplorer.Inspectors.GameObjects
|
||||
internal static void OnCompToggleClicked(int index, bool value)
|
||||
{
|
||||
var comp = s_compShortlist[index];
|
||||
|
||||
#if CPP
|
||||
comp.TryCast<Behaviour>().enabled = value;
|
||||
#else
|
||||
(comp as Behaviour).enabled = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void OnCompListObjectClicked(int index)
|
||||
@ -130,7 +137,7 @@ namespace UnityExplorer.Inspectors.GameObjects
|
||||
}
|
||||
|
||||
|
||||
#region UI CONSTRUCTION
|
||||
#region UI CONSTRUCTION
|
||||
|
||||
internal void ConstructCompList(GameObject parent)
|
||||
{
|
||||
@ -168,34 +175,34 @@ namespace UnityExplorer.Inspectors.GameObjects
|
||||
{
|
||||
int thisIndex = s_compListTexts.Count;
|
||||
|
||||
GameObject btnGroupObj = UIFactory.CreateHorizontalGroup(s_compListContent, new Color(0.07f, 0.07f, 0.07f));
|
||||
HorizontalLayoutGroup btnGroup = btnGroupObj.GetComponent<HorizontalLayoutGroup>();
|
||||
btnGroup.childForceExpandWidth = true;
|
||||
btnGroup.childControlWidth = true;
|
||||
btnGroup.childForceExpandHeight = false;
|
||||
btnGroup.childControlHeight = true;
|
||||
btnGroup.childAlignment = TextAnchor.MiddleLeft;
|
||||
LayoutElement btnLayout = btnGroupObj.AddComponent<LayoutElement>();
|
||||
btnLayout.minWidth = 25;
|
||||
btnLayout.flexibleWidth = 999;
|
||||
btnLayout.minHeight = 25;
|
||||
btnLayout.flexibleHeight = 0;
|
||||
btnGroupObj.AddComponent<Mask>();
|
||||
GameObject groupObj = UIFactory.CreateHorizontalGroup(s_compListContent, new Color(0.07f, 0.07f, 0.07f));
|
||||
HorizontalLayoutGroup group = groupObj.GetComponent<HorizontalLayoutGroup>();
|
||||
group.childForceExpandWidth = true;
|
||||
group.childControlWidth = true;
|
||||
group.childForceExpandHeight = false;
|
||||
group.childControlHeight = true;
|
||||
group.childAlignment = TextAnchor.MiddleLeft;
|
||||
LayoutElement groupLayout = groupObj.AddComponent<LayoutElement>();
|
||||
groupLayout.minWidth = 25;
|
||||
groupLayout.flexibleWidth = 999;
|
||||
groupLayout.minHeight = 25;
|
||||
groupLayout.flexibleHeight = 0;
|
||||
groupObj.AddComponent<Mask>();
|
||||
|
||||
// Behaviour enabled toggle
|
||||
|
||||
var toggleObj = UIFactory.CreateToggle(btnGroupObj, out Toggle toggle, out Text toggleText, new Color(0.3f, 0.3f, 0.3f));
|
||||
var toggleObj = UIFactory.CreateToggle(groupObj, out Toggle toggle, out Text toggleText, new Color(0.3f, 0.3f, 0.3f));
|
||||
var toggleLayout = toggleObj.AddComponent<LayoutElement>();
|
||||
toggleLayout.minHeight = 25;
|
||||
toggleLayout.minWidth = 25;
|
||||
toggleText.text = "";
|
||||
toggle.isOn = false;
|
||||
toggle.isOn = true;
|
||||
s_compToggles.Add(toggle);
|
||||
toggle.onValueChanged.AddListener((bool val) => { OnCompToggleClicked(thisIndex, val); });
|
||||
|
||||
// Main component button
|
||||
|
||||
GameObject mainButtonObj = UIFactory.CreateButton(btnGroupObj);
|
||||
GameObject mainButtonObj = UIFactory.CreateButton(groupObj);
|
||||
LayoutElement mainBtnLayout = mainButtonObj.AddComponent<LayoutElement>();
|
||||
mainBtnLayout.minHeight = 25;
|
||||
mainBtnLayout.flexibleHeight = 0;
|
||||
@ -224,6 +231,6 @@ namespace UnityExplorer.Inspectors.GameObjects
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ namespace UnityExplorer.Inspectors
|
||||
}
|
||||
}
|
||||
|
||||
public void Inspect(object obj)
|
||||
public void Inspect(object obj, CacheObjectBase parentMember = null)
|
||||
{
|
||||
#if CPP
|
||||
obj = obj.Il2CppCast(ReflectionHelpers.GetActualType(obj));
|
||||
@ -76,6 +76,9 @@ namespace UnityExplorer.Inspectors
|
||||
else
|
||||
inspector = new InstanceInspector(obj);
|
||||
|
||||
if (inspector is ReflectionInspector ri)
|
||||
ri.ParentMember = parentMember;
|
||||
|
||||
m_currentInspectors.Add(inspector);
|
||||
SetInspectorTab(inspector);
|
||||
}
|
||||
|
@ -109,21 +109,12 @@ namespace UnityExplorer.Inspectors
|
||||
internal static void RaycastWorld(Vector2 mousePos)
|
||||
{
|
||||
var ray = UnityHelpers.MainCamera.ScreenPointToRay(mousePos);
|
||||
var casts = Physics.RaycastAll(ray, 1000f);
|
||||
Physics.Raycast(ray, out RaycastHit hit, 1000f);
|
||||
|
||||
if (casts.Length > 0)
|
||||
if (hit.transform)
|
||||
{
|
||||
foreach (var cast in casts)
|
||||
{
|
||||
if (cast.transform)
|
||||
{
|
||||
var obj = cast.transform.gameObject;
|
||||
|
||||
OnHitGameObject(obj);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
var obj = hit.transform.gameObject;
|
||||
OnHitGameObject(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -33,6 +33,9 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
{
|
||||
var fi = MemInfo as FieldInfo;
|
||||
fi.SetValue(fi.IsStatic ? null : DeclaringInstance, IValue.Value);
|
||||
|
||||
if (this.ParentInspector?.ParentMember != null)
|
||||
this.ParentInspector.ParentMember.SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
|
||||
public override Type FallbackType { get; }
|
||||
|
||||
public ReflectionInspector ParentInspector { get; set; }
|
||||
public MemberInfo MemInfo { get; set; }
|
||||
public Type DeclaringType { get; set; }
|
||||
public object DeclaringInstance { get; set; }
|
||||
|
@ -71,6 +71,9 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
while (e.InnerException != null)
|
||||
e = e.InnerException;
|
||||
|
||||
ExplorerCore.LogWarning($"Exception evaluating: {e.GetType()}, {e.Message}");
|
||||
ReflectionException = ReflectionHelpers.ExceptionToString(e);
|
||||
}
|
||||
|
@ -63,6 +63,9 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance;
|
||||
|
||||
pi.SetValue(target, IValue.Value, ParseArguments());
|
||||
|
||||
if (this.ParentInspector?.ParentMember != null)
|
||||
this.ParentInspector.ParentMember.SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ using UnityEngine;
|
||||
using UnityExplorer.Helpers;
|
||||
using UnityExplorer.UI;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Unstrip;
|
||||
using System.IO;
|
||||
|
||||
namespace UnityExplorer.Inspectors.Reflection
|
||||
{
|
||||
@ -70,8 +72,8 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
|
||||
// WIP
|
||||
|
||||
//if (m_targetType == typeof(Texture2D))
|
||||
// ConstructTextureHelper();
|
||||
if (m_targetType == typeof(Texture2D))
|
||||
ConstructTextureHelper();
|
||||
}
|
||||
|
||||
internal void ConstructCompHelper(GameObject rowObj)
|
||||
@ -136,94 +138,176 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
//btn.onClick.AddListener(() => { InspectorManager.Instance.Inspect(comp.gameObject); });
|
||||
}
|
||||
|
||||
//internal bool showingTextureHelper;
|
||||
//internal bool constructedTextureViewer;
|
||||
internal bool showingTextureHelper;
|
||||
internal bool constructedTextureViewer;
|
||||
|
||||
//internal void ConstructTextureHelper()
|
||||
//{
|
||||
// var rowObj = UIFactory.CreateHorizontalGroup(Content, new Color(0.1f, 0.1f, 0.1f));
|
||||
// var rowLayout = rowObj.AddComponent<LayoutElement>();
|
||||
// rowLayout.minHeight = 25;
|
||||
// rowLayout.flexibleHeight = 0;
|
||||
// var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
|
||||
// rowGroup.childForceExpandHeight = true;
|
||||
// rowGroup.childForceExpandWidth = false;
|
||||
// rowGroup.padding.top = 3;
|
||||
// rowGroup.padding.left = 3;
|
||||
// rowGroup.padding.bottom = 3;
|
||||
// rowGroup.padding.right = 3;
|
||||
// rowGroup.spacing = 5;
|
||||
internal GameObject m_textureViewerObj;
|
||||
|
||||
// var showBtnObj = UIFactory.CreateButton(rowObj, new Color(0.2f, 0.2f, 0.2f));
|
||||
// var showBtnLayout = showBtnObj.AddComponent<LayoutElement>();
|
||||
// showBtnLayout.minWidth = 50;
|
||||
// showBtnLayout.flexibleWidth = 0;
|
||||
// var showText = showBtnObj.GetComponentInChildren<Text>();
|
||||
// showText.text = "Show";
|
||||
// var showBtn = showBtnObj.GetComponent<Button>();
|
||||
internal void ConstructTextureHelper()
|
||||
{
|
||||
var rowObj = UIFactory.CreateHorizontalGroup(Content, new Color(0.1f, 0.1f, 0.1f));
|
||||
var rowLayout = rowObj.AddComponent<LayoutElement>();
|
||||
rowLayout.minHeight = 25;
|
||||
rowLayout.flexibleHeight = 0;
|
||||
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
|
||||
rowGroup.childForceExpandHeight = true;
|
||||
rowGroup.childForceExpandWidth = false;
|
||||
rowGroup.padding.top = 3;
|
||||
rowGroup.padding.left = 3;
|
||||
rowGroup.padding.bottom = 3;
|
||||
rowGroup.padding.right = 3;
|
||||
rowGroup.spacing = 5;
|
||||
|
||||
// var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
|
||||
// var labelText = labelObj.GetComponent<Text>();
|
||||
// labelText.text = "Texture Viewer";
|
||||
var showBtnObj = UIFactory.CreateButton(rowObj, new Color(0.2f, 0.6f, 0.2f));
|
||||
var showBtnLayout = showBtnObj.AddComponent<LayoutElement>();
|
||||
showBtnLayout.minWidth = 50;
|
||||
showBtnLayout.flexibleWidth = 0;
|
||||
var showText = showBtnObj.GetComponentInChildren<Text>();
|
||||
showText.text = "Show";
|
||||
var showBtn = showBtnObj.GetComponent<Button>();
|
||||
|
||||
// var textureViewerObj = UIFactory.CreateScrollView(Content, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f));
|
||||
// var viewerGroup = scrollContent.GetComponent<VerticalLayoutGroup>();
|
||||
// viewerGroup.childForceExpandHeight = false;
|
||||
// viewerGroup.childForceExpandWidth = false;
|
||||
// viewerGroup.childControlHeight = true;
|
||||
// viewerGroup.childControlWidth = true;
|
||||
// var mainLayout = textureViewerObj.GetComponent<LayoutElement>();
|
||||
// mainLayout.flexibleHeight = -1;
|
||||
// mainLayout.flexibleWidth = 2000;
|
||||
// mainLayout.minHeight = 25;
|
||||
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
|
||||
var labelText = labelObj.GetComponent<Text>();
|
||||
labelText.text = "Texture Viewer";
|
||||
|
||||
// textureViewerObj.SetActive(false);
|
||||
var textureViewerObj = UIFactory.CreateScrollView(Content, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f));
|
||||
var viewerGroup = scrollContent.GetComponent<VerticalLayoutGroup>();
|
||||
viewerGroup.childForceExpandHeight = false;
|
||||
viewerGroup.childForceExpandWidth = false;
|
||||
viewerGroup.childControlHeight = true;
|
||||
viewerGroup.childControlWidth = true;
|
||||
var mainLayout = textureViewerObj.GetComponent<LayoutElement>();
|
||||
mainLayout.flexibleHeight = 9999;
|
||||
mainLayout.flexibleWidth = 9999;
|
||||
mainLayout.minHeight = 100;
|
||||
|
||||
// showBtn.onClick.AddListener(() =>
|
||||
// {
|
||||
// showingTextureHelper = !showingTextureHelper;
|
||||
textureViewerObj.SetActive(false);
|
||||
|
||||
// if (showingTextureHelper)
|
||||
// {
|
||||
// if (!constructedTextureViewer)
|
||||
// ConstructTextureViewerArea(scrollContent);
|
||||
m_textureViewerObj = textureViewerObj;
|
||||
|
||||
// showText.text = "Hide";
|
||||
// textureViewerObj.SetActive(true);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// showText.text = "Show";
|
||||
// textureViewerObj.SetActive(false);
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
showBtn.onClick.AddListener(() =>
|
||||
{
|
||||
showingTextureHelper = !showingTextureHelper;
|
||||
|
||||
//internal void ConstructTextureViewerArea(GameObject parent)
|
||||
//{
|
||||
// constructedTextureViewer = true;
|
||||
if (showingTextureHelper)
|
||||
{
|
||||
if (!constructedTextureViewer)
|
||||
ConstructTextureViewerArea(scrollContent);
|
||||
|
||||
// var tex = Target as Texture2D;
|
||||
showText.text = "Hide";
|
||||
ToggleTextureViewer(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
showText.text = "Show";
|
||||
ToggleTextureViewer(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// if (!tex)
|
||||
// {
|
||||
// ExplorerCore.LogWarning("Could not cast the target instance to Texture2D!");
|
||||
// return;
|
||||
// }
|
||||
internal void ConstructTextureViewerArea(GameObject parent)
|
||||
{
|
||||
constructedTextureViewer = true;
|
||||
|
||||
// var imageObj = UIFactory.CreateUIObject("TextureViewerImage", parent, new Vector2(1, 1));
|
||||
// var image = imageObj.AddComponent<Image>();
|
||||
// var sprite = UIManager.CreateSprite(tex);
|
||||
// image.sprite = sprite;
|
||||
var tex = Target as Texture2D;
|
||||
#if CPP
|
||||
if (!tex)
|
||||
tex = (Target as Il2CppSystem.Object).TryCast<Texture2D>();
|
||||
#endif
|
||||
|
||||
// var fitter = imageObj.AddComponent<ContentSizeFitter>();
|
||||
// fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
// //fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
if (!tex)
|
||||
{
|
||||
ExplorerCore.LogWarning("Could not cast the target instance to Texture2D! Maybe its null or destroyed?");
|
||||
return;
|
||||
}
|
||||
|
||||
// var imageLayout = imageObj.AddComponent<LayoutElement>();
|
||||
// imageLayout.preferredHeight = sprite.rect.height;
|
||||
// imageLayout.preferredWidth = sprite.rect.width;
|
||||
//}
|
||||
// Save helper
|
||||
|
||||
var saveRowObj = UIFactory.CreateHorizontalGroup(parent, new Color(0.1f, 0.1f, 0.1f));
|
||||
var saveRow = saveRowObj.GetComponent<HorizontalLayoutGroup>();
|
||||
saveRow.childForceExpandHeight = true;
|
||||
saveRow.childForceExpandWidth = true;
|
||||
saveRow.padding = new RectOffset() { left = 2, bottom = 2, right = 2, top = 2 };
|
||||
saveRow.spacing = 2;
|
||||
|
||||
var btnObj = UIFactory.CreateButton(saveRowObj, new Color(0.2f, 0.2f, 0.2f));
|
||||
var btnLayout = btnObj.AddComponent<LayoutElement>();
|
||||
btnLayout.minHeight = 25;
|
||||
btnLayout.minWidth = 100;
|
||||
btnLayout.flexibleWidth = 0;
|
||||
var saveBtn = btnObj.GetComponent<Button>();
|
||||
|
||||
var saveBtnText = btnObj.GetComponentInChildren<Text>();
|
||||
saveBtnText.text = "Save .PNG";
|
||||
|
||||
var inputObj = UIFactory.CreateInputField(saveRowObj);
|
||||
var inputLayout = inputObj.AddComponent<LayoutElement>();
|
||||
inputLayout.minHeight = 25;
|
||||
inputLayout.minWidth = 100;
|
||||
inputLayout.flexibleWidth = 9999;
|
||||
var inputField = inputObj.GetComponent<InputField>();
|
||||
|
||||
var name = tex.name;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
name = "untitled";
|
||||
|
||||
var savePath = $@"{Config.ModConfig.Instance.Default_Output_Path}\{name}.png";
|
||||
inputField.text = savePath;
|
||||
|
||||
saveBtn.onClick.AddListener(() =>
|
||||
{
|
||||
if (tex && !string.IsNullOrEmpty(inputField.text))
|
||||
{
|
||||
var path = inputField.text;
|
||||
if (!path.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
ExplorerCore.LogWarning("Desired save path must end with '.png'!");
|
||||
return;
|
||||
}
|
||||
|
||||
var dir = Path.GetDirectoryName(path);
|
||||
if (!Directory.Exists(dir))
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
if (File.Exists(path))
|
||||
File.Delete(path);
|
||||
|
||||
if (!tex.IsReadable())
|
||||
tex = Texture2DHelpers.ForceReadTexture(tex);
|
||||
#if CPP
|
||||
byte[] data = tex.EncodeToPNG();
|
||||
#else
|
||||
byte[] data = tex.EncodeToPNGSafe();
|
||||
#endif
|
||||
|
||||
File.WriteAllBytes(path, data);
|
||||
}
|
||||
});
|
||||
|
||||
// Actual texture viewer
|
||||
|
||||
var imageObj = UIFactory.CreateUIObject("TextureViewerImage", parent);
|
||||
var image = imageObj.AddComponent<Image>();
|
||||
var sprite = ImageConversionUnstrip.CreateSprite(tex);
|
||||
image.sprite = sprite;
|
||||
|
||||
var fitter = imageObj.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
//fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
var imageLayout = imageObj.AddComponent<LayoutElement>();
|
||||
imageLayout.preferredHeight = sprite.rect.height;
|
||||
imageLayout.preferredWidth = sprite.rect.width;
|
||||
}
|
||||
|
||||
internal void ToggleTextureViewer(bool enabled)
|
||||
{
|
||||
m_textureViewerObj.SetActive(enabled);
|
||||
|
||||
m_filterAreaObj.SetActive(!enabled);
|
||||
m_memberListObj.SetActive(!enabled);
|
||||
m_updateRowObj.SetActive(!enabled);
|
||||
}
|
||||
|
||||
public void ConstructInstanceFilters(GameObject parent)
|
||||
{
|
||||
|
@ -10,6 +10,9 @@ using UnityExplorer.Helpers;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Shared;
|
||||
using System.Reflection;
|
||||
#if CPP
|
||||
using CppDictionary = Il2CppSystem.Collections.IDictionary;
|
||||
#endif
|
||||
|
||||
namespace UnityExplorer.Inspectors.Reflection
|
||||
{
|
||||
@ -44,7 +47,11 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
}
|
||||
|
||||
internal IDictionary RefIDictionary;
|
||||
|
||||
#if CPP
|
||||
internal CppDictionary RefCppDictionary;
|
||||
#else
|
||||
internal IDictionary RefCppDictionary = null;
|
||||
#endif
|
||||
internal Type m_typeOfKeys;
|
||||
internal Type m_typeofValues;
|
||||
|
||||
@ -65,6 +72,11 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
{
|
||||
RefIDictionary = Value as IDictionary;
|
||||
|
||||
#if CPP
|
||||
try { RefCppDictionary = (Value as Il2CppSystem.Object).TryCast<CppDictionary>(); }
|
||||
catch { }
|
||||
#endif
|
||||
|
||||
if (m_subContentParent.activeSelf)
|
||||
{
|
||||
GetCacheEntries();
|
||||
@ -129,13 +141,6 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
{
|
||||
var value = RefIDictionary[key];
|
||||
|
||||
//if (index >= m_rowHolders.Count)
|
||||
//{
|
||||
// AddRowHolder();
|
||||
//}
|
||||
|
||||
//var holder = m_rowHolders[index];
|
||||
|
||||
var cacheKey = new CachePaired(index, this, this.RefIDictionary, PairTypes.Key, m_listContent);
|
||||
cacheKey.CreateIValue(key, this.m_typeOfKeys);
|
||||
cacheKey.Disable();
|
||||
@ -206,9 +211,10 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
RefreshDisplay();
|
||||
}
|
||||
|
||||
#region CPP fixes
|
||||
#region CPP fixes
|
||||
#if CPP
|
||||
// temp fix for Il2Cpp IDictionary until interfaces are fixed
|
||||
|
||||
private IDictionary EnumerateWithReflection()
|
||||
{
|
||||
var valueType = Value?.GetType() ?? FallbackType;
|
||||
@ -222,8 +228,8 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
var valueList = new List<object>();
|
||||
|
||||
// store entries with reflection
|
||||
EnumerateWithReflection(keys, keyList);
|
||||
EnumerateWithReflection(values, valueList);
|
||||
EnumerateCollection(keys, keyList);
|
||||
EnumerateCollection(values, valueList);
|
||||
|
||||
// make actual mono dictionary
|
||||
var dict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>)
|
||||
@ -236,7 +242,7 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
return dict;
|
||||
}
|
||||
|
||||
private void EnumerateWithReflection(object collection, List<object> list)
|
||||
private void EnumerateCollection(object collection, List<object> list)
|
||||
{
|
||||
// invoke GetEnumerator
|
||||
var enumerator = collection.GetType().GetMethod("GetEnumerator").Invoke(collection, null);
|
||||
@ -253,9 +259,9 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region UI CONSTRUCTION
|
||||
#region UI CONSTRUCTION
|
||||
|
||||
internal GameObject m_listContent;
|
||||
internal LayoutElement m_listLayout;
|
||||
@ -309,6 +315,6 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
// m_rowHolders.Add(obj);
|
||||
//}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,11 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
|
||||
internal IEnumerable RefIEnumerable;
|
||||
internal IList RefIList;
|
||||
#if CPP
|
||||
internal Il2CppSystem.Collections.ICollection CppICollection;
|
||||
#else
|
||||
internal ICollection CppICollection = null;
|
||||
#endif
|
||||
|
||||
internal readonly Type m_baseEntryType;
|
||||
|
||||
@ -49,6 +54,14 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
RefIEnumerable = Value as IEnumerable;
|
||||
RefIList = Value as IList;
|
||||
|
||||
#if CPP
|
||||
if (Value != null && RefIList == null)
|
||||
{
|
||||
try { CppICollection = (Value as Il2CppSystem.Object).TryCast<Il2CppSystem.Collections.ICollection>(); }
|
||||
catch { }
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_subContentParent.activeSelf)
|
||||
{
|
||||
GetCacheEntries();
|
||||
@ -77,8 +90,8 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
if (Value != null)
|
||||
{
|
||||
string count = "?";
|
||||
if (m_recacheWanted && RefIList != null)
|
||||
count = RefIList.Count.ToString();
|
||||
if (m_recacheWanted && (RefIList != null || CppICollection != null))
|
||||
count = RefIList?.Count.ToString() ?? CppICollection.Count.ToString();
|
||||
else if (!m_recacheWanted)
|
||||
count = m_entries.Count.ToString();
|
||||
|
||||
@ -169,89 +182,62 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
RefreshDisplay();
|
||||
}
|
||||
|
||||
#region CPP Helpers
|
||||
#region CPP Helpers
|
||||
|
||||
#if CPP
|
||||
// some temp fixes for Il2Cpp IEnumerables until interfaces are fixed
|
||||
|
||||
internal static readonly Dictionary<Type, MethodInfo> s_getEnumeratorMethods = new Dictionary<Type, MethodInfo>();
|
||||
|
||||
internal static readonly Dictionary<Type, EnumeratorInfo> s_enumeratorInfos = new Dictionary<Type, EnumeratorInfo>();
|
||||
|
||||
internal class EnumeratorInfo
|
||||
{
|
||||
internal MethodInfo moveNext;
|
||||
internal PropertyInfo current;
|
||||
}
|
||||
|
||||
private IEnumerable EnumerateWithReflection()
|
||||
{
|
||||
if (Value.IsNullOrDestroyed())
|
||||
if (Value == null)
|
||||
return null;
|
||||
|
||||
var genericDef = Value.GetType().GetGenericTypeDefinition();
|
||||
|
||||
if (genericDef == typeof(Il2CppSystem.Collections.Generic.List<>))
|
||||
return CppListToMono(genericDef);
|
||||
else if (genericDef == typeof(Il2CppSystem.Collections.Generic.HashSet<>))
|
||||
return CppHashSetToMono();
|
||||
else
|
||||
return CppIListToMono();
|
||||
}
|
||||
|
||||
// List<T>.ToArray()
|
||||
private IEnumerable CppListToMono(Type genericTypeDef)
|
||||
{
|
||||
if (genericTypeDef == null) return null;
|
||||
|
||||
return genericTypeDef
|
||||
.MakeGenericType(new Type[] { this.m_baseEntryType })
|
||||
.GetMethod("ToArray")
|
||||
.Invoke(Value, new object[0]) as IEnumerable;
|
||||
}
|
||||
|
||||
// HashSet.GetEnumerator
|
||||
private IEnumerable CppHashSetToMono()
|
||||
{
|
||||
var set = new HashSet<object>();
|
||||
|
||||
// invoke GetEnumerator
|
||||
var enumerator = Value.GetType().GetMethod("GetEnumerator").Invoke(Value, null);
|
||||
// get the type of it
|
||||
var enumeratorType = enumerator.GetType();
|
||||
// reflect MoveNext and Current
|
||||
var moveNext = enumeratorType.GetMethod("MoveNext");
|
||||
var current = enumeratorType.GetProperty("Current");
|
||||
// iterate
|
||||
while ((bool)moveNext.Invoke(enumerator, null))
|
||||
set.Add(current.GetValue(enumerator));
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
// IList.Item
|
||||
private IList CppIListToMono()
|
||||
{
|
||||
try
|
||||
// new test
|
||||
var CppEnumerable = (Value as Il2CppSystem.Object)?.TryCast<Il2CppSystem.Collections.IEnumerable>();
|
||||
if (CppEnumerable != null)
|
||||
{
|
||||
var genericType = typeof(List<>).MakeGenericType(new Type[] { this.m_baseEntryType });
|
||||
var list = (IList)Activator.CreateInstance(genericType);
|
||||
var type = Value.GetType();
|
||||
if (!s_getEnumeratorMethods.ContainsKey(type))
|
||||
s_getEnumeratorMethods.Add(type, type.GetMethod("GetEnumerator"));
|
||||
|
||||
var enumerator = s_getEnumeratorMethods[type].Invoke(Value, null);
|
||||
var enumeratorType = enumerator.GetType();
|
||||
|
||||
for (int i = 0; ; i++)
|
||||
if (!s_enumeratorInfos.ContainsKey(enumeratorType))
|
||||
{
|
||||
try
|
||||
s_enumeratorInfos.Add(enumeratorType, new EnumeratorInfo
|
||||
{
|
||||
var itm = Value?.GetType()
|
||||
.GetProperty("Item")
|
||||
.GetValue(Value, new object[] { i });
|
||||
list.Add(itm);
|
||||
}
|
||||
catch { break; }
|
||||
current = enumeratorType.GetProperty("Current"),
|
||||
moveNext = enumeratorType.GetMethod("MoveNext"),
|
||||
});
|
||||
}
|
||||
var info = s_enumeratorInfos[enumeratorType];
|
||||
|
||||
// iterate
|
||||
var list = new List<object>();
|
||||
while ((bool)info.moveNext.Invoke(enumerator, null))
|
||||
list.Add(info.current.GetValue(enumerator));
|
||||
|
||||
return list;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log("Exception converting Il2Cpp IList to Mono IList: " + e.GetType() + ", " + e.Message);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region UI CONSTRUCTION
|
||||
#region UI CONSTRUCTION
|
||||
|
||||
internal GameObject m_listContent;
|
||||
internal LayoutElement m_listLayout;
|
||||
@ -296,6 +282,6 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -176,6 +176,10 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
ConstructSubcontent();
|
||||
}
|
||||
|
||||
internal MethodInfo m_toStringMethod;
|
||||
internal MethodInfo m_toStringFormatMethod;
|
||||
internal bool m_gotToStringMethods;
|
||||
|
||||
public string GetDefaultLabel(bool updateType = true)
|
||||
{
|
||||
var valueType = Value?.GetType() ?? this.FallbackType;
|
||||
@ -205,8 +209,29 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
}
|
||||
else
|
||||
{
|
||||
var toString = (string)valueType.GetMethod("ToString", new Type[0])?.Invoke(Value, null)
|
||||
?? Value.ToString();
|
||||
if (!m_gotToStringMethods)
|
||||
{
|
||||
m_gotToStringMethods = true;
|
||||
|
||||
m_toStringMethod = valueType.GetMethod("ToString", new Type[0]);
|
||||
m_toStringFormatMethod = valueType.GetMethod("ToString", new Type[] { typeof(string) });
|
||||
|
||||
// test format method actually works
|
||||
try
|
||||
{
|
||||
m_toStringFormatMethod.Invoke(Value, new object[] { "F3" });
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_toStringFormatMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
string toString;
|
||||
if (m_toStringFormatMethod != null)
|
||||
toString = (string)m_toStringFormatMethod.Invoke(Value, new object[] { "F3" });
|
||||
else
|
||||
toString = (string)m_toStringMethod.Invoke(Value, new object[0]);
|
||||
|
||||
var fullnametemp = valueType.ToString();
|
||||
if (fullnametemp.StartsWith("Il2CppSystem"))
|
||||
@ -303,7 +328,7 @@ namespace UnityExplorer.Inspectors.Reflection
|
||||
void OnInspectClicked()
|
||||
{
|
||||
if (!Value.IsNullOrDestroyed(false))
|
||||
InspectorManager.Instance.Inspect(this.Value);
|
||||
InspectorManager.Instance.Inspect(this.Value, this.Owner);
|
||||
}
|
||||
|
||||
m_inspectButton.SetActive(false);
|
||||
|
@ -58,6 +58,8 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
public override string TabLabel => m_targetTypeShortName;
|
||||
|
||||
internal CacheObjectBase ParentMember { get; set; }
|
||||
|
||||
internal readonly Type m_targetType;
|
||||
internal readonly string m_targetTypeShortName;
|
||||
|
||||
@ -202,6 +204,8 @@ namespace UnityExplorer.Inspectors
|
||||
list.Add(new CacheProperty(pi, target, m_scrollContent));
|
||||
else
|
||||
list.Add(new CacheField(fi, target, m_scrollContent));
|
||||
|
||||
list.Last().ParentInspector = this;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -363,6 +367,10 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
#region UI CONSTRUCTION
|
||||
|
||||
internal GameObject m_filterAreaObj;
|
||||
internal GameObject m_updateRowObj;
|
||||
internal GameObject m_memberListObj;
|
||||
|
||||
internal void ConstructUI()
|
||||
{
|
||||
var parent = InspectorManager.Instance.m_inspectorContent;
|
||||
@ -423,7 +431,7 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
ConstructFilterArea();
|
||||
|
||||
ConstructOptionsArea();
|
||||
ConstructUpdateRow();
|
||||
}
|
||||
|
||||
internal void ConstructFilterArea()
|
||||
@ -444,6 +452,8 @@ namespace UnityExplorer.Inspectors
|
||||
filterGroup.padding.top = 4;
|
||||
filterGroup.padding.bottom = 4;
|
||||
|
||||
m_filterAreaObj = filterAreaObj;
|
||||
|
||||
// name filter
|
||||
|
||||
var nameFilterRowObj = UIFactory.CreateHorizontalGroup(filterAreaObj, new Color(1, 1, 1, 0));
|
||||
@ -540,7 +550,7 @@ namespace UnityExplorer.Inspectors
|
||||
btn.colors = colors;
|
||||
}
|
||||
|
||||
internal void ConstructOptionsArea()
|
||||
internal void ConstructUpdateRow()
|
||||
{
|
||||
var optionsRowObj = UIFactory.CreateHorizontalGroup(Content, new Color(1, 1, 1, 0));
|
||||
var optionsLayout = optionsRowObj.AddComponent<LayoutElement>();
|
||||
@ -551,6 +561,8 @@ namespace UnityExplorer.Inspectors
|
||||
optionsGroup.childAlignment = TextAnchor.MiddleLeft;
|
||||
optionsGroup.spacing = 10;
|
||||
|
||||
m_updateRowObj = optionsRowObj;
|
||||
|
||||
// update button
|
||||
|
||||
var updateButtonObj = UIFactory.CreateButton(optionsRowObj, new Color(0.2f, 0.2f, 0.2f));
|
||||
@ -578,11 +590,12 @@ namespace UnityExplorer.Inspectors
|
||||
autoUpdateToggle.isOn = false;
|
||||
autoUpdateToggle.onValueChanged.AddListener((bool val) => { m_autoUpdate = val; });
|
||||
}
|
||||
|
||||
|
||||
internal void ConstructMemberList()
|
||||
{
|
||||
var scrollobj = UIFactory.CreateScrollView(Content, out m_scrollContent, out m_sliderScroller, new Color(0.05f, 0.05f, 0.05f));
|
||||
|
||||
m_memberListObj = scrollobj;
|
||||
m_scrollContentRect = m_scrollContent.GetComponent<RectTransform>();
|
||||
|
||||
var scrollGroup = m_scrollContent.GetComponent<VerticalLayoutGroup>();
|
||||
|
BIN
src/Resources/explorerui.modern.bundle
Normal file
BIN
src/Resources/explorerui.modern.bundle
Normal file
Binary file not shown.
@ -3,7 +3,12 @@ using System.Collections.Generic;
|
||||
using UnityExplorer.UI;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using UnityExplorer.Unstrip;
|
||||
#if CPP
|
||||
using UnhollowerBaseLib;
|
||||
using UnityExplorer.Helpers;
|
||||
#endif
|
||||
|
||||
namespace UnityExplorer.Tests
|
||||
@ -19,7 +24,6 @@ namespace UnityExplorer.Tests
|
||||
"three",
|
||||
};
|
||||
public static void StaticMethod() { }
|
||||
|
||||
}
|
||||
|
||||
public class TestClass
|
||||
@ -118,13 +122,15 @@ namespace UnityExplorer.Tests
|
||||
private static bool m_setOnlyProperty;
|
||||
public static bool ReadSetOnlyProperty => m_setOnlyProperty;
|
||||
|
||||
public Texture TestTexture;
|
||||
public Texture2D TestTexture;
|
||||
public static Sprite TestSprite;
|
||||
|
||||
#if CPP
|
||||
public static Il2CppSystem.Collections.Generic.HashSet<string> CppHashSetTest;
|
||||
public static Il2CppSystem.Collections.Generic.List<string> CppStringTest;
|
||||
public static Il2CppSystem.Collections.IList CppIList;
|
||||
//public static Il2CppSystem.Collections.Generic.Dictionary<string, string> CppDictTest;
|
||||
//public static Il2CppSystem.Collections.Generic.Dictionary<int, float> CppDictTest2;
|
||||
#endif
|
||||
|
||||
public TestClass()
|
||||
@ -140,20 +146,7 @@ namespace UnityExplorer.Tests
|
||||
}
|
||||
|
||||
#if CPP
|
||||
TestTexture = UIManager.MakeSolidTexture(Color.white, 1000, 600);
|
||||
TestTexture.name = "TestTexture";
|
||||
|
||||
var r = new Rect(0, 0, TestTexture.width, TestTexture.height);
|
||||
var v2 = Vector2.zero;
|
||||
var v4 = Vector4.zero;
|
||||
TestSprite = Sprite.CreateSprite_Injected((Texture2D)TestTexture, ref r, ref v2, 100f, 0u, SpriteMeshType.Tight, ref v4, false);
|
||||
|
||||
GameObject.DontDestroyOnLoad(TestTexture);
|
||||
GameObject.DontDestroyOnLoad(TestSprite);
|
||||
|
||||
//// test loading a tex from file
|
||||
//var dataToLoad = System.IO.File.ReadAllBytes(@"Mods\UnityExplorer\Tex_Nemundis_Nebula.png");
|
||||
//ExplorerCore.Log($"Tex load success: {TestTexture.LoadImage(dataToLoad, false)}");
|
||||
TextureSpriteTest();
|
||||
|
||||
CppHashSetTest = new Il2CppSystem.Collections.Generic.HashSet<string>();
|
||||
CppHashSetTest.Add("1");
|
||||
@ -163,9 +156,38 @@ namespace UnityExplorer.Tests
|
||||
CppStringTest = new Il2CppSystem.Collections.Generic.List<string>();
|
||||
CppStringTest.Add("1");
|
||||
CppStringTest.Add("2");
|
||||
|
||||
//CppDictTest = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
|
||||
//CppDictTest.Add("key1", "value1");
|
||||
//CppDictTest.Add("key2", "value2");
|
||||
//CppDictTest.Add("key3", "value3");
|
||||
|
||||
//CppDictTest2 = new Il2CppSystem.Collections.Generic.Dictionary<int, float>();
|
||||
//CppDictTest2.Add(0, 0.5f);
|
||||
//CppDictTest2.Add(1, 0.5f);
|
||||
//CppDictTest2.Add(2, 0.5f);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void TextureSpriteTest()
|
||||
{
|
||||
TestTexture = new Texture2D(32, 32, TextureFormat.ARGB32, false)
|
||||
{
|
||||
name = "TestTexture"
|
||||
};
|
||||
TestSprite = ImageConversionUnstrip.CreateSprite(TestTexture);
|
||||
|
||||
GameObject.DontDestroyOnLoad(TestTexture);
|
||||
GameObject.DontDestroyOnLoad(TestSprite);
|
||||
|
||||
// test loading a tex from file
|
||||
if (System.IO.File.Exists(@"D:\Downloads\test.png"))
|
||||
{
|
||||
var dataToLoad = System.IO.File.ReadAllBytes(@"D:\Downloads\test.png");
|
||||
ExplorerCore.Log($"Tex load success: {TestTexture.LoadImage(dataToLoad, false)}");
|
||||
}
|
||||
}
|
||||
|
||||
public static string TestRefInOutGeneric<T>(ref string arg0, in int arg1, out string arg2) where T : Component
|
||||
{
|
||||
arg2 = "this is arg2";
|
||||
|
@ -87,12 +87,6 @@ namespace UnityExplorer.UI
|
||||
new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_visible))),
|
||||
true);
|
||||
|
||||
#if BIE
|
||||
#if CPP
|
||||
// temporarily disabling this patch in BepInEx il2cpp as it's causing a crash in some games.
|
||||
return;
|
||||
#endif
|
||||
#endif
|
||||
TryPatch(typeof(EventSystem),
|
||||
"current",
|
||||
new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_EventSystem_set_current))),
|
||||
@ -111,8 +105,10 @@ namespace UnityExplorer.UI
|
||||
var harmony =
|
||||
#if ML
|
||||
ExplorerMelonMod.Instance.harmonyInstance;
|
||||
#else
|
||||
#elif BIE
|
||||
ExplorerBepInPlugin.HarmonyInstance;
|
||||
#elif STANDALONE
|
||||
ExplorerStandalone.HarmonyInstance;
|
||||
#endif
|
||||
|
||||
System.Reflection.PropertyInfo prop = type.GetProperty(property);
|
||||
@ -164,11 +160,25 @@ namespace UnityExplorer.UI
|
||||
|
||||
public static void SetEventSystem()
|
||||
{
|
||||
// temp disabled for new InputSystem
|
||||
if (InputManager.CurrentType == InputType.InputSystem)
|
||||
return;
|
||||
|
||||
// Disable current event system object
|
||||
if (m_lastEventSystem || EventSystem.current)
|
||||
{
|
||||
if (!m_lastEventSystem)
|
||||
m_lastEventSystem = EventSystem.current;
|
||||
|
||||
//ExplorerCore.Log("Disabling current event system...");
|
||||
m_lastEventSystem.enabled = false;
|
||||
//m_lastEventSystem.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Set to our current system
|
||||
m_settingEventSystem = true;
|
||||
EventSystem.current = UIManager.EventSys;
|
||||
UIManager.EventSys.enabled = true;
|
||||
InputManager.ActivateUIModule();
|
||||
m_settingEventSystem = false;
|
||||
}
|
||||
@ -180,6 +190,9 @@ namespace UnityExplorer.UI
|
||||
|
||||
if (m_lastEventSystem)
|
||||
{
|
||||
m_lastEventSystem.enabled = true;
|
||||
//m_lastEventSystem.gameObject.SetActive(true);
|
||||
|
||||
m_settingEventSystem = true;
|
||||
EventSystem.current = m_lastEventSystem;
|
||||
m_lastInputModule?.ActivateModule();
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
//using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
@ -9,6 +8,7 @@ using UnityExplorer.Helpers;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI.Shared;
|
||||
using UnityExplorer.Unstrip;
|
||||
using System.Reflection;
|
||||
#if CPP
|
||||
using UnhollowerRuntimeLib;
|
||||
#endif
|
||||
@ -21,7 +21,7 @@ namespace UnityExplorer.UI.Modules
|
||||
GameObject,
|
||||
Component,
|
||||
Custom,
|
||||
Instance,
|
||||
Singleton,
|
||||
StaticClass
|
||||
}
|
||||
|
||||
@ -46,11 +46,14 @@ namespace UnityExplorer.UI.Modules
|
||||
|
||||
public static SearchPage Instance;
|
||||
|
||||
internal SearchContext m_context;
|
||||
private SceneFilter m_sceneFilter;
|
||||
private ChildFilter m_childFilter;
|
||||
|
||||
// ui elements
|
||||
|
||||
private Text m_resultCountText;
|
||||
|
||||
internal SearchContext m_context;
|
||||
private InputField m_customTypeInput;
|
||||
|
||||
private InputField m_nameInput;
|
||||
@ -60,9 +63,6 @@ namespace UnityExplorer.UI.Modules
|
||||
|
||||
private Dropdown m_sceneDropdown;
|
||||
private int m_lastSceneCount = -1;
|
||||
private SceneFilter m_sceneFilter;
|
||||
|
||||
private ChildFilter m_childFilter;
|
||||
|
||||
private GameObject m_extraFilterRow;
|
||||
|
||||
@ -132,10 +132,9 @@ namespace UnityExplorer.UI.Modules
|
||||
else
|
||||
{
|
||||
var obj = m_results[itemIndex];
|
||||
var unityObj = obj as UnityEngine.Object;
|
||||
|
||||
var uObj = obj as UnityEngine.Object;
|
||||
|
||||
if (obj == null || (uObj != null && !uObj))
|
||||
if (obj == null || (unityObj != null && !unityObj))
|
||||
continue;
|
||||
|
||||
if (i >= m_resultShortList.Count)
|
||||
@ -150,17 +149,25 @@ namespace UnityExplorer.UI.Modules
|
||||
|
||||
var text = m_resultListTexts[i];
|
||||
|
||||
var name = $"<color={UISyntaxHighlight.Class_Instance}>{ReflectionHelpers.GetActualType(obj).Name}</color>";
|
||||
|
||||
if (m_context != SearchContext.Instance && m_context != SearchContext.StaticClass)
|
||||
if (m_context != SearchContext.StaticClass)
|
||||
{
|
||||
if (uObj && !string.IsNullOrEmpty(uObj.name))
|
||||
name += $": {uObj.name}";
|
||||
else
|
||||
name += ": <i><color=grey>untitled</color></i>";
|
||||
}
|
||||
var name = UISyntaxHighlight.ParseFullSyntax(obj.GetActualType(), true);
|
||||
|
||||
text.text = name;
|
||||
if (unityObj && m_context != SearchContext.Singleton)
|
||||
{
|
||||
if (unityObj && !string.IsNullOrEmpty(unityObj.name))
|
||||
name += $": {unityObj.name}";
|
||||
else
|
||||
name += ": <i><color=grey>untitled</color></i>";
|
||||
}
|
||||
|
||||
text.text = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = obj as Type;
|
||||
text.text = UISyntaxHighlight.ParseFullSyntax(type, true);
|
||||
}
|
||||
|
||||
var label = text.transform.parent.parent.gameObject;
|
||||
if (!label.activeSelf)
|
||||
@ -222,14 +229,127 @@ namespace UnityExplorer.UI.Modules
|
||||
}
|
||||
|
||||
m_sceneDropdown.transform.Find("Label").GetComponent<Text>().text = "Any";
|
||||
m_sceneFilter = SceneFilter.Any;
|
||||
}
|
||||
|
||||
// ~~~~~ UI Callbacks ~~~~~
|
||||
|
||||
internal void OnUnitySearchClicked()
|
||||
internal void OnSearchClicked()
|
||||
{
|
||||
m_resultListPageHandler.CurrentPage = 0;
|
||||
|
||||
if (m_context == SearchContext.StaticClass)
|
||||
StaticClassSearch();
|
||||
else if (m_context == SearchContext.Singleton)
|
||||
SingletonSearch();
|
||||
else
|
||||
UnityObjectSearch();
|
||||
|
||||
RefreshResultList();
|
||||
|
||||
if (m_results.Length > 0)
|
||||
m_resultCountText.text = $"{m_results.Length} Results";
|
||||
else
|
||||
m_resultCountText.text = "No results...";
|
||||
}
|
||||
|
||||
internal void StaticClassSearch()
|
||||
{
|
||||
var list = new List<Type>();
|
||||
|
||||
var nameFilter = "";
|
||||
if (!string.IsNullOrEmpty(m_nameInput.text))
|
||||
nameFilter = m_nameInput.text.ToLower();
|
||||
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
foreach (var type in asm.TryGetTypes().Where(it => it.IsSealed && it.IsAbstract))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ToLower().Contains(nameFilter))
|
||||
continue;
|
||||
|
||||
list.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
m_results = list.ToArray();
|
||||
}
|
||||
|
||||
internal string[] s_instanceNames = new string[]
|
||||
{
|
||||
"m_instance",
|
||||
"m_Instance",
|
||||
"s_instance",
|
||||
"s_Instance",
|
||||
"_instance",
|
||||
"_Instance",
|
||||
"instance",
|
||||
"Instance",
|
||||
"<Instance>k__BackingField",
|
||||
"<instance>k__BackingField",
|
||||
};
|
||||
|
||||
private void SingletonSearch()
|
||||
{
|
||||
var instances = new List<object>();
|
||||
|
||||
var nameFilter = "";
|
||||
if (!string.IsNullOrEmpty(m_nameInput.text))
|
||||
nameFilter = m_nameInput.text.ToLower();
|
||||
|
||||
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
|
||||
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
// Search all non-static, non-enum classes.
|
||||
foreach (var type in asm.TryGetTypes().Where(it => !(it.IsSealed && it.IsAbstract) && !it.IsEnum))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ToLower().Contains(nameFilter))
|
||||
continue;
|
||||
#if CPP
|
||||
// Only look for Properties in IL2CPP, not for Mono.
|
||||
PropertyInfo pi;
|
||||
foreach (var name in s_instanceNames)
|
||||
{
|
||||
pi = type.GetProperty(name, flags);
|
||||
if (pi != null)
|
||||
{
|
||||
var instance = pi.GetValue(null, null);
|
||||
if (instance != null)
|
||||
{
|
||||
instances.Add(instance);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Look for a typical Instance backing field.
|
||||
FieldInfo fi;
|
||||
foreach (var name in s_instanceNames)
|
||||
{
|
||||
fi = type.GetField(name, flags);
|
||||
if (fi != null)
|
||||
{
|
||||
var instance = fi.GetValue(null);
|
||||
if (instance != null)
|
||||
{
|
||||
instances.Add(instance);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
m_results = instances.ToArray();
|
||||
}
|
||||
|
||||
internal void UnityObjectSearch()
|
||||
{
|
||||
Type searchType = null;
|
||||
switch (m_context)
|
||||
{
|
||||
@ -305,12 +425,12 @@ namespace UnityExplorer.UI.Modules
|
||||
: obj.TryCast<Component>().gameObject;
|
||||
#endif
|
||||
|
||||
if (!go)
|
||||
continue;
|
||||
|
||||
// scene check
|
||||
if (m_sceneFilter != SceneFilter.Any)
|
||||
{
|
||||
if (!go)
|
||||
continue;
|
||||
|
||||
switch (m_context)
|
||||
{
|
||||
case SearchContext.GameObject:
|
||||
@ -325,24 +445,23 @@ namespace UnityExplorer.UI.Modules
|
||||
}
|
||||
}
|
||||
|
||||
// root object check (no parent)
|
||||
if (m_childFilter == ChildFilter.HasParent && !go.transform.parent)
|
||||
continue;
|
||||
else if (m_childFilter == ChildFilter.RootObject && go.transform.parent)
|
||||
continue;
|
||||
if (m_childFilter != ChildFilter.Any)
|
||||
{
|
||||
if (!go)
|
||||
continue;
|
||||
|
||||
// root object check (no parent)
|
||||
if (m_childFilter == ChildFilter.HasParent && !go.transform.parent)
|
||||
continue;
|
||||
else if (m_childFilter == ChildFilter.RootObject && go.transform.parent)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
results.Add(obj);
|
||||
}
|
||||
|
||||
m_results = results.ToArray();
|
||||
|
||||
if (m_results.Length > 0)
|
||||
m_resultCountText.text = $"{m_results.Length} Results";
|
||||
else
|
||||
m_resultCountText.text = "No results...";
|
||||
|
||||
RefreshResultList();
|
||||
}
|
||||
|
||||
private void OnResultPageTurn()
|
||||
@ -490,6 +609,23 @@ namespace UnityExplorer.UI.Modules
|
||||
m_customTypeInput = customTypeObj.GetComponent<InputField>();
|
||||
m_customTypeInput.placeholder.gameObject.GetComponent<Text>().text = "eg. UnityEngine.Texture2D, etc...";
|
||||
|
||||
// static class and singleton buttons
|
||||
|
||||
var secondRow = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0));
|
||||
var secondGroup = secondRow.GetComponent<HorizontalLayoutGroup>();
|
||||
secondGroup.childForceExpandWidth = false;
|
||||
secondGroup.childForceExpandHeight = false;
|
||||
secondGroup.spacing = 3;
|
||||
var secondLayout = secondRow.AddComponent<LayoutElement>();
|
||||
secondLayout.minHeight = 25;
|
||||
var spacer = UIFactory.CreateUIObject("spacer", secondRow);
|
||||
var spaceLayout = spacer.AddComponent<LayoutElement>();
|
||||
spaceLayout.minWidth = 125;
|
||||
spaceLayout.minHeight = 25;
|
||||
|
||||
AddContextButton(secondRow, "Static Class", SearchContext.StaticClass);
|
||||
AddContextButton(secondRow, "Singleton", SearchContext.Singleton);
|
||||
|
||||
// search input
|
||||
|
||||
var nameRowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0));
|
||||
@ -601,7 +737,7 @@ namespace UnityExplorer.UI.Modules
|
||||
searchBtnLayout.flexibleHeight = 0;
|
||||
var searchBtn = searchBtnObj.GetComponent<Button>();
|
||||
|
||||
searchBtn.onClick.AddListener(OnUnitySearchClicked);
|
||||
searchBtn.onClick.AddListener(OnSearchClicked);
|
||||
}
|
||||
|
||||
internal void AddContextButton(GameObject parent, string label, SearchContext context, float width = 110)
|
||||
|
@ -33,6 +33,8 @@ namespace UnityExplorer.UI.Shared
|
||||
this.sliderScroller = sliderScroller;
|
||||
this.inputField = inputField;
|
||||
|
||||
sliderScroller.m_parentInputScroller = this;
|
||||
|
||||
inputField.onValueChanged.AddListener(OnTextChanged);
|
||||
|
||||
inputRect = inputField.GetComponent<RectTransform>();
|
||||
@ -68,6 +70,17 @@ namespace UnityExplorer.UI.Shared
|
||||
}
|
||||
}
|
||||
|
||||
internal bool CheckDestroyed()
|
||||
{
|
||||
if (sliderScroller == null || sliderScroller.CheckDestroyed())
|
||||
{
|
||||
Instances.Remove(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void OnTextChanged(string text)
|
||||
{
|
||||
m_lastText = text;
|
||||
|
@ -8,150 +8,154 @@ using UnityExplorer;
|
||||
using UnityExplorer.Helpers;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
// Basically just to fix an issue with Scrollbars, instead we use a Slider as the scrollbar.
|
||||
public class SliderScrollbar
|
||||
namespace UnityExplorer.UI.Shared
|
||||
{
|
||||
internal static readonly List<SliderScrollbar> Instances = new List<SliderScrollbar>();
|
||||
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
internal readonly Scrollbar m_scrollbar;
|
||||
internal readonly Slider m_slider;
|
||||
internal readonly RectTransform m_scrollRect;
|
||||
|
||||
public SliderScrollbar(Scrollbar scrollbar, Slider slider)
|
||||
// Basically just to fix an issue with Scrollbars, instead we use a Slider as the scrollbar.
|
||||
public class SliderScrollbar
|
||||
{
|
||||
Instances.Add(this);
|
||||
internal static readonly List<SliderScrollbar> Instances = new List<SliderScrollbar>();
|
||||
|
||||
this.m_scrollbar = scrollbar;
|
||||
this.m_slider = slider;
|
||||
this.m_scrollRect = scrollbar.transform.parent.GetComponent<RectTransform>();
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
this.m_scrollbar.onValueChanged.AddListener(this.OnScrollbarValueChanged);
|
||||
this.m_slider.onValueChanged.AddListener(this.OnSliderValueChanged);
|
||||
internal readonly Scrollbar m_scrollbar;
|
||||
internal readonly Slider m_slider;
|
||||
internal readonly RectTransform m_scrollRect;
|
||||
|
||||
this.RefreshVisibility();
|
||||
this.m_slider.Set(1f, false);
|
||||
}
|
||||
internal InputFieldScroller m_parentInputScroller;
|
||||
|
||||
internal bool CheckDestroyed()
|
||||
{
|
||||
if (!m_slider || !m_scrollbar)
|
||||
public SliderScrollbar(Scrollbar scrollbar, Slider slider)
|
||||
{
|
||||
Instances.Remove(this);
|
||||
return true;
|
||||
Instances.Add(this);
|
||||
|
||||
this.m_scrollbar = scrollbar;
|
||||
this.m_slider = slider;
|
||||
this.m_scrollRect = scrollbar.transform.parent.GetComponent<RectTransform>();
|
||||
|
||||
this.m_scrollbar.onValueChanged.AddListener(this.OnScrollbarValueChanged);
|
||||
this.m_slider.onValueChanged.AddListener(this.OnSliderValueChanged);
|
||||
|
||||
this.RefreshVisibility();
|
||||
this.m_slider.Set(1f, false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
this.RefreshVisibility();
|
||||
}
|
||||
|
||||
internal void RefreshVisibility()
|
||||
{
|
||||
if (!m_slider.gameObject.activeInHierarchy)
|
||||
internal bool CheckDestroyed()
|
||||
{
|
||||
IsActive = false;
|
||||
return;
|
||||
if (!m_slider || !m_scrollbar)
|
||||
{
|
||||
Instances.Remove(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool shouldShow = !Mathf.Approximately(this.m_scrollbar.size, 1);
|
||||
var obj = this.m_slider.handleRect.gameObject;
|
||||
|
||||
if (IsActive != shouldShow)
|
||||
internal void Update()
|
||||
{
|
||||
IsActive = shouldShow;
|
||||
obj.SetActive(IsActive);
|
||||
|
||||
if (IsActive)
|
||||
this.m_slider.Set(this.m_scrollbar.value, false);
|
||||
else
|
||||
m_slider.Set(1f, false);
|
||||
this.RefreshVisibility();
|
||||
}
|
||||
|
||||
internal void RefreshVisibility()
|
||||
{
|
||||
if (!m_slider.gameObject.activeInHierarchy)
|
||||
{
|
||||
IsActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool shouldShow = !Mathf.Approximately(this.m_scrollbar.size, 1);
|
||||
var obj = this.m_slider.handleRect.gameObject;
|
||||
|
||||
if (IsActive != shouldShow)
|
||||
{
|
||||
IsActive = shouldShow;
|
||||
obj.SetActive(IsActive);
|
||||
|
||||
if (IsActive)
|
||||
this.m_slider.Set(this.m_scrollbar.value, false);
|
||||
else
|
||||
m_slider.Set(1f, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnScrollbarValueChanged(float _value)
|
||||
{
|
||||
if (this.m_slider.value != _value)
|
||||
this.m_slider.Set(_value, false);
|
||||
}
|
||||
|
||||
public void OnSliderValueChanged(float _value)
|
||||
{
|
||||
this.m_scrollbar.value = _value;
|
||||
}
|
||||
|
||||
#region UI CONSTRUCTION
|
||||
|
||||
public static GameObject CreateSliderScrollbar(GameObject parent, out Slider slider)
|
||||
{
|
||||
GameObject sliderObj = UIFactory.CreateUIObject("Slider", parent, UIFactory.thinSize);
|
||||
|
||||
GameObject bgObj = UIFactory.CreateUIObject("Background", sliderObj);
|
||||
GameObject fillAreaObj = UIFactory.CreateUIObject("Fill Area", sliderObj);
|
||||
GameObject fillObj = UIFactory.CreateUIObject("Fill", fillAreaObj);
|
||||
GameObject handleSlideAreaObj = UIFactory.CreateUIObject("Handle Slide Area", sliderObj);
|
||||
GameObject handleObj = UIFactory.CreateUIObject("Handle", handleSlideAreaObj);
|
||||
|
||||
Image bgImage = bgObj.AddComponent<Image>();
|
||||
bgImage.type = Image.Type.Sliced;
|
||||
bgImage.color = new Color(0.05f, 0.05f, 0.05f, 1.0f);
|
||||
|
||||
RectTransform bgRect = bgObj.GetComponent<RectTransform>();
|
||||
bgRect.anchorMin = Vector2.zero;
|
||||
bgRect.anchorMax = Vector2.one;
|
||||
bgRect.sizeDelta = Vector2.zero;
|
||||
bgRect.offsetMax = new Vector2(-10f, 0f);
|
||||
|
||||
RectTransform fillAreaRect = fillAreaObj.GetComponent<RectTransform>();
|
||||
fillAreaRect.anchorMin = new Vector2(0f, 0.25f);
|
||||
fillAreaRect.anchorMax = new Vector2(1f, 0.75f);
|
||||
fillAreaRect.anchoredPosition = new Vector2(-5f, 0f);
|
||||
fillAreaRect.sizeDelta = new Vector2(-20f, 0f);
|
||||
|
||||
Image fillImage = fillObj.AddComponent<Image>();
|
||||
fillImage.type = Image.Type.Sliced;
|
||||
fillImage.color = Color.clear;
|
||||
|
||||
fillObj.GetComponent<RectTransform>().sizeDelta = new Vector2(10f, 0f);
|
||||
|
||||
RectTransform handleSlideRect = handleSlideAreaObj.GetComponent<RectTransform>();
|
||||
handleSlideRect.anchorMin = new Vector2(0f, 0f);
|
||||
handleSlideRect.anchorMax = new Vector2(1f, 1f);
|
||||
handleSlideRect.offsetMin = new Vector2(15f, 30f);
|
||||
handleSlideRect.offsetMax = new Vector2(-15f, 0f);
|
||||
handleSlideRect.sizeDelta = new Vector2(-30f, -30f);
|
||||
|
||||
Image handleImage = handleObj.AddComponent<Image>();
|
||||
handleImage.color = new Color(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
|
||||
var handleRect = handleObj.GetComponent<RectTransform>();
|
||||
handleRect.sizeDelta = new Vector2(15f, 30f);
|
||||
handleRect.offsetMin = new Vector2(-13f, -28f);
|
||||
handleRect.offsetMax = new Vector2(3f, -2f);
|
||||
|
||||
var sliderBarLayout = sliderObj.AddComponent<LayoutElement>();
|
||||
sliderBarLayout.minWidth = 25;
|
||||
sliderBarLayout.flexibleWidth = 0;
|
||||
sliderBarLayout.minHeight = 30;
|
||||
sliderBarLayout.flexibleHeight = 5000;
|
||||
|
||||
slider = sliderObj.AddComponent<Slider>();
|
||||
slider.fillRect = fillObj.GetComponent<RectTransform>();
|
||||
slider.handleRect = handleObj.GetComponent<RectTransform>();
|
||||
slider.targetGraphic = handleImage;
|
||||
slider.direction = Slider.Direction.BottomToTop;
|
||||
UIFactory.SetDefaultColorTransitionValues(slider);
|
||||
|
||||
return sliderObj;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public void OnScrollbarValueChanged(float _value)
|
||||
{
|
||||
if (this.m_slider.value != _value)
|
||||
this.m_slider.Set(_value, false);
|
||||
}
|
||||
|
||||
public void OnSliderValueChanged(float _value)
|
||||
{
|
||||
this.m_scrollbar.value = _value;
|
||||
}
|
||||
|
||||
#region UI CONSTRUCTION
|
||||
|
||||
public static GameObject CreateSliderScrollbar(GameObject parent, out Slider slider)
|
||||
{
|
||||
GameObject sliderObj = UIFactory.CreateUIObject("Slider", parent, UIFactory.thinSize);
|
||||
|
||||
GameObject bgObj = UIFactory.CreateUIObject("Background", sliderObj);
|
||||
GameObject fillAreaObj = UIFactory.CreateUIObject("Fill Area", sliderObj);
|
||||
GameObject fillObj = UIFactory.CreateUIObject("Fill", fillAreaObj);
|
||||
GameObject handleSlideAreaObj = UIFactory.CreateUIObject("Handle Slide Area", sliderObj);
|
||||
GameObject handleObj = UIFactory.CreateUIObject("Handle", handleSlideAreaObj);
|
||||
|
||||
Image bgImage = bgObj.AddComponent<Image>();
|
||||
bgImage.type = Image.Type.Sliced;
|
||||
bgImage.color = new Color(0.05f, 0.05f, 0.05f, 1.0f);
|
||||
|
||||
RectTransform bgRect = bgObj.GetComponent<RectTransform>();
|
||||
bgRect.anchorMin = Vector2.zero;
|
||||
bgRect.anchorMax = Vector2.one;
|
||||
bgRect.sizeDelta = Vector2.zero;
|
||||
bgRect.offsetMax = new Vector2(-10f, 0f);
|
||||
|
||||
RectTransform fillAreaRect = fillAreaObj.GetComponent<RectTransform>();
|
||||
fillAreaRect.anchorMin = new Vector2(0f, 0.25f);
|
||||
fillAreaRect.anchorMax = new Vector2(1f, 0.75f);
|
||||
fillAreaRect.anchoredPosition = new Vector2(-5f, 0f);
|
||||
fillAreaRect.sizeDelta = new Vector2(-20f, 0f);
|
||||
|
||||
Image fillImage = fillObj.AddComponent<Image>();
|
||||
fillImage.type = Image.Type.Sliced;
|
||||
fillImage.color = Color.clear;
|
||||
|
||||
fillObj.GetComponent<RectTransform>().sizeDelta = new Vector2(10f, 0f);
|
||||
|
||||
RectTransform handleSlideRect = handleSlideAreaObj.GetComponent<RectTransform>();
|
||||
handleSlideRect.anchorMin = new Vector2(0f, 0f);
|
||||
handleSlideRect.anchorMax = new Vector2(1f, 1f);
|
||||
handleSlideRect.offsetMin = new Vector2(15f, 30f);
|
||||
handleSlideRect.offsetMax = new Vector2(-15f, 0f);
|
||||
handleSlideRect.sizeDelta = new Vector2(-30f, -30f);
|
||||
|
||||
Image handleImage = handleObj.AddComponent<Image>();
|
||||
handleImage.color = new Color(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
|
||||
var handleRect = handleObj.GetComponent<RectTransform>();
|
||||
handleRect.sizeDelta = new Vector2(15f, 30f);
|
||||
handleRect.offsetMin = new Vector2(-13f, -28f);
|
||||
handleRect.offsetMax = new Vector2(3f, -2f);
|
||||
|
||||
var sliderBarLayout = sliderObj.AddComponent<LayoutElement>();
|
||||
sliderBarLayout.minWidth = 25;
|
||||
sliderBarLayout.flexibleWidth = 0;
|
||||
sliderBarLayout.minHeight = 30;
|
||||
sliderBarLayout.flexibleHeight = 5000;
|
||||
|
||||
slider = sliderObj.AddComponent<Slider>();
|
||||
slider.fillRect = fillObj.GetComponent<RectTransform>();
|
||||
slider.handleRect = handleObj.GetComponent<RectTransform>();
|
||||
slider.targetGraphic = handleImage;
|
||||
slider.direction = Slider.Direction.BottomToTop;
|
||||
UIFactory.SetDefaultColorTransitionValues(slider);
|
||||
|
||||
return sliderObj;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
#if MONO
|
||||
public static class SliderExtensions
|
||||
{
|
||||
@ -175,4 +179,5 @@ public static class SliderExtensions
|
||||
SetMethod.Invoke(slider, new object[] { value, invokeCallback });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
@ -45,7 +45,6 @@ namespace UnityExplorer.UI
|
||||
SceneExplorer.Instance?.OnSceneChange();
|
||||
SearchPage.Instance?.OnSceneChange();
|
||||
}
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
MainMenu.Instance?.Update();
|
||||
@ -53,12 +52,9 @@ namespace UnityExplorer.UI
|
||||
if (EventSys)
|
||||
{
|
||||
if (EventSystem.current != EventSys)
|
||||
{
|
||||
ForceUnlockCursor.SetEventSystem();
|
||||
}
|
||||
|
||||
#if CPP
|
||||
// Fix for games which override the InputModule pointer events (eg, VRChat)
|
||||
// Some IL2CPP games behave weird with multiple UI Input Systems, some fixes for them.
|
||||
var evt = InputManager.InputPointerEvent;
|
||||
if (evt != null)
|
||||
{
|
||||
@ -69,9 +65,7 @@ namespace UnityExplorer.UI
|
||||
}
|
||||
|
||||
if (PanelDragger.Instance != null)
|
||||
{
|
||||
PanelDragger.Instance.Update();
|
||||
}
|
||||
|
||||
for (int i = 0; i < SliderScrollbar.Instances.Count; i++)
|
||||
{
|
||||
@ -87,40 +81,73 @@ namespace UnityExplorer.UI
|
||||
{
|
||||
var input = InputFieldScroller.Instances[i];
|
||||
|
||||
if (input.sliderScroller.CheckDestroyed())
|
||||
if (input.CheckDestroyed())
|
||||
i--;
|
||||
else
|
||||
input.Update();
|
||||
}
|
||||
}
|
||||
|
||||
private static AssetBundle LoadExplorerUi(string id)
|
||||
{
|
||||
return AssetBundle.LoadFromMemory(ReadFully(typeof(ExplorerCore).Assembly.GetManifestResourceStream($"UnityExplorer.Resources.explorerui.{id}.bundle")));
|
||||
}
|
||||
|
||||
private static byte[] ReadFully(this Stream input)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
byte[] buffer = new byte[81920];
|
||||
int read;
|
||||
while ((read = input.Read(buffer, 0, buffer.Length)) != 0)
|
||||
ms.Write(buffer, 0, read);
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadBundle()
|
||||
{
|
||||
var bundlePath = ExplorerCore.EXPLORER_FOLDER + @"\explorerui.bundle";
|
||||
if (File.Exists(bundlePath))
|
||||
AssetBundle bundle = null;
|
||||
|
||||
try
|
||||
{
|
||||
var bundle = AssetBundle.LoadFromFile(bundlePath);
|
||||
|
||||
BackupShader = bundle.LoadAsset<Shader>("DefaultUI");
|
||||
|
||||
// Fix for games which don't ship with 'UI/Default' shader.
|
||||
if (Graphic.defaultGraphicMaterial.shader?.name != "UI/Default")
|
||||
{
|
||||
ExplorerCore.Log("This game does not ship with the 'UI/Default' shader, using manual Default Shader...");
|
||||
Graphic.defaultGraphicMaterial.shader = BackupShader;
|
||||
}
|
||||
|
||||
ResizeCursor = bundle.LoadAsset<Sprite>("cursor");
|
||||
|
||||
ConsoleFont = bundle.LoadAsset<Font>("CONSOLA");
|
||||
|
||||
ExplorerCore.Log("Loaded UI bundle");
|
||||
bundle = LoadExplorerUi("modern");
|
||||
}
|
||||
else
|
||||
catch
|
||||
{
|
||||
ExplorerCore.LogWarning("Could not find the ExplorerUI Bundle! It should exist at '" + bundlePath + "'");
|
||||
ExplorerCore.Log("Failed to load modern ExplorerUI Bundle, falling back to legacy");
|
||||
|
||||
try
|
||||
{
|
||||
bundle = LoadExplorerUi("legacy");
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
if (bundle == null)
|
||||
{
|
||||
ExplorerCore.LogWarning("Could not load the ExplorerUI Bundle!");
|
||||
return;
|
||||
}
|
||||
|
||||
BackupShader = bundle.LoadAsset<Shader>("DefaultUI");
|
||||
|
||||
// Fix for games which don't ship with 'UI/Default' shader.
|
||||
if (Graphic.defaultGraphicMaterial.shader?.name != "UI/Default")
|
||||
{
|
||||
ExplorerCore.Log("This game does not ship with the 'UI/Default' shader, using manual Default Shader...");
|
||||
Graphic.defaultGraphicMaterial.shader = BackupShader;
|
||||
}
|
||||
|
||||
ResizeCursor = bundle.LoadAsset<Sprite>("cursor");
|
||||
|
||||
ConsoleFont = bundle.LoadAsset<Font>("CONSOLA");
|
||||
|
||||
ExplorerCore.Log("Loaded UI bundle");
|
||||
}
|
||||
|
||||
private static GameObject CreateRootCanvas()
|
||||
@ -139,7 +166,7 @@ namespace UnityExplorer.UI
|
||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
||||
canvas.referencePixelsPerUnit = 100;
|
||||
canvas.sortingOrder = 999;
|
||||
canvas.pixelPerfect = false;
|
||||
//canvas.pixelPerfect = false;
|
||||
|
||||
CanvasScaler scaler = rootObj.AddComponent<CanvasScaler>();
|
||||
scaler.referenceResolution = new Vector2(1920, 1080);
|
||||
@ -149,37 +176,5 @@ namespace UnityExplorer.UI
|
||||
|
||||
return rootObj;
|
||||
}
|
||||
|
||||
public static Sprite CreateSprite(Texture2D tex, Rect size = default)
|
||||
{
|
||||
#if CPP
|
||||
Vector2 pivot = Vector2.zero;
|
||||
Vector4 border = Vector4.zero;
|
||||
|
||||
if (size == default)
|
||||
{
|
||||
size = new Rect(0, 0, tex.width, tex.height);
|
||||
}
|
||||
|
||||
return Sprite.CreateSprite_Injected(tex, ref size, ref pivot, 100f, 0u, SpriteMeshType.Tight, ref border, false);
|
||||
#else
|
||||
return Sprite.Create(tex, size, Vector2.zero);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Texture2D MakeSolidTexture(Color color, int width, int height)
|
||||
{
|
||||
Color[] pixels = new Color[width * height];
|
||||
for (int i = 0; i < pixels.Length; i++)
|
||||
{
|
||||
pixels[i] = color;
|
||||
}
|
||||
|
||||
Texture2D tex = new Texture2D(width, height);
|
||||
tex.SetPixels(pixels);
|
||||
tex.Apply();
|
||||
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,9 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<RootNamespace>UnityExplorer</RootNamespace>
|
||||
<!-- Set this to the BepInEx Il2Cpp Game folder, without the ending '\' character. -->
|
||||
<BIECppGameFolder>D:\source\Unity Projects\Test\_BUILD</BIECppGameFolder>
|
||||
<BIECppGameFolder>E:\source\Unity Projects\Test\_BUILD</BIECppGameFolder>
|
||||
<!-- Set this to the MelonLoader Il2Cpp Game folder, without the ending '\' character. -->
|
||||
<MLCppGameFolder>D:\source\Unity Projects\Test\_BUILD</MLCppGameFolder>
|
||||
<MLCppGameFolder>E:\source\Unity Projects\Test\_BUILD</MLCppGameFolder>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
@ -68,6 +68,24 @@
|
||||
<IsMelonLoader>false</IsMelonLoader>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_STANDALONE_Mono|AnyCPU'">
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<OutputPath>..\Release\UnityExplorer.Standalone.Mono\</OutputPath>
|
||||
<DefineConstants>MONO,STANDALONE</DefineConstants>
|
||||
<AssemblyName>UnityExplorer.STANDALONE.Mono</AssemblyName>
|
||||
<IsCpp>false</IsCpp>
|
||||
<IsMelonLoader>false</IsMelonLoader>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_STANDALONE_Cpp|AnyCPU'">
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<OutputPath>..\Release\UnityExplorer.Standalone.Il2Cpp\</OutputPath>
|
||||
<DefineConstants>CPP,STANDALONE</DefineConstants>
|
||||
<AssemblyName>UnityExplorer.STANDALONE.IL2CPP</AssemblyName>
|
||||
<IsCpp>true</IsCpp>
|
||||
<IsMelonLoader>false</IsMelonLoader>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="INIFileParser, Version=2.5.2.0, Culture=neutral, PublicKeyToken=79af7b307b65cf3c, processorArchitecture=MSIL">
|
||||
<HintPath>packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll</HintPath>
|
||||
@ -217,6 +235,7 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ExplorerStandalone.cs" />
|
||||
<Compile Include="Helpers\EventHelper.cs" />
|
||||
<Compile Include="Inspectors\MouseInspector.cs" />
|
||||
<Compile Include="Inspectors\Reflection\CacheObject\CacheEnumerated.cs" />
|
||||
@ -293,6 +312,7 @@
|
||||
<Compile Include="Unstrip\SceneUnstrip.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UI\UIFactory.cs" />
|
||||
<EmbeddedResource Include="Resources\*" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ILRepack.targets" />
|
||||
|
@ -11,6 +11,8 @@ Global
|
||||
Release_BIE_Mono|Any CPU = Release_BIE_Mono|Any CPU
|
||||
Release_ML_Cpp|Any CPU = Release_ML_Cpp|Any CPU
|
||||
Release_ML_Mono|Any CPU = Release_ML_Mono|Any CPU
|
||||
Release_STANDALONE_Cpp|Any CPU = Release_STANDALONE_Cpp|Any CPU
|
||||
Release_STANDALONE_Mono|Any CPU = Release_STANDALONE_Mono|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_BIE_Cpp|Any CPU.ActiveCfg = Release_BIE_Cpp|Any CPU
|
||||
@ -21,6 +23,10 @@ Global
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Cpp|Any CPU.Build.0 = Release_ML_Cpp|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Mono|Any CPU.ActiveCfg = Release_ML_Mono|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Mono|Any CPU.Build.0 = Release_ML_Mono|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release_STANDALONE_Cpp|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release_STANDALONE_Cpp|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release_STANDALONE_Mono|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Mono|Any CPU.Build.0 = Release_STANDALONE_Mono|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -24,6 +24,17 @@ namespace UnityExplorer.Unstrip
|
||||
|
||||
return new AssetBundle(ptr);
|
||||
}
|
||||
|
||||
private delegate IntPtr d_LoadFromMemory(IntPtr binary, uint crc);
|
||||
|
||||
public static AssetBundle LoadFromMemory(byte[] binary, uint crc = 0)
|
||||
{
|
||||
var iCall = ICallHelper.GetICall<d_LoadFromMemory>("UnityEngine.AssetBundle::LoadFromMemory_Internal");
|
||||
|
||||
var ptr = iCall(((Il2CppStructArray<byte>) binary).Pointer, crc);
|
||||
|
||||
return new AssetBundle(ptr);
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~ Instance ~~~~~~~~~~~~
|
||||
|
||||
|
@ -10,6 +10,16 @@ namespace UnityExplorer.Unstrip
|
||||
{
|
||||
public static class ImageConversionUnstrip
|
||||
{
|
||||
// LoadImage helper from a filepath
|
||||
|
||||
public static bool LoadImage(Texture2D tex, string filePath, bool markNonReadable)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
return tex.LoadImage(File.ReadAllBytes(filePath), markNonReadable);
|
||||
}
|
||||
|
||||
#if CPP
|
||||
// byte[] ImageConversion.EncodeToPNG(this Texture2D image);
|
||||
|
||||
@ -17,8 +27,12 @@ namespace UnityExplorer.Unstrip
|
||||
|
||||
public static byte[] EncodeToPNG(this Texture2D tex)
|
||||
{
|
||||
IntPtr ptr = ICallHelper.GetICall<d_EncodeToPNG>("UnityEngine.ImageConversion::EncodeToPNG")
|
||||
.Invoke(tex.Pointer);
|
||||
var iCall = ICallHelper.GetICall<d_EncodeToPNG>("UnityEngine.ImageConversion::EncodeToPNG");
|
||||
|
||||
IntPtr ptr = iCall.Invoke(tex.Pointer);
|
||||
|
||||
if (ptr == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
return new Il2CppStructArray<byte>(ptr);
|
||||
}
|
||||
@ -29,28 +43,40 @@ namespace UnityExplorer.Unstrip
|
||||
|
||||
public static bool LoadImage(this Texture2D tex, byte[] data, bool markNonReadable)
|
||||
{
|
||||
Il2CppStructArray<byte> il2cppArray = new Il2CppStructArray<byte>(data.Length);
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
il2cppArray[i] = data[i];
|
||||
var il2cppArray = (Il2CppStructArray<byte>)data;
|
||||
|
||||
bool ret = ICallHelper.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage")
|
||||
.Invoke(tex.Pointer, il2cppArray.Pointer, markNonReadable);
|
||||
var iCall = ICallHelper.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage");
|
||||
|
||||
return iCall.Invoke(tex.Pointer, il2cppArray.Pointer, markNonReadable);
|
||||
}
|
||||
|
||||
return ret;
|
||||
// Sprite Sprite.Create
|
||||
|
||||
internal delegate IntPtr d_CreateSprite(IntPtr texture, ref Rect rect, ref Vector2 pivot, float pixelsPerUnit,
|
||||
uint extrude, int meshType, ref Vector4 border, bool generateFallbackPhysicsShape);
|
||||
|
||||
public static Sprite CreateSprite(Texture texture, Rect rect, Vector2 pivot, float pixelsPerUnit, uint extrude, Vector4 border)
|
||||
{
|
||||
var iCall = ICallHelper.GetICall<d_CreateSprite>("UnityEngine.Sprite::CreateSprite_Injected");
|
||||
|
||||
var ptr = iCall.Invoke(texture.Pointer, ref rect, ref pivot, pixelsPerUnit, extrude, 1, ref border, false);
|
||||
|
||||
if (ptr == IntPtr.Zero)
|
||||
return null;
|
||||
else
|
||||
return new Sprite(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Helper for LoadImage from filepath
|
||||
// Simpler CreateSprite helper
|
||||
|
||||
public static bool LoadImage(Texture2D tex, string filePath, bool markNonReadable)
|
||||
public static Sprite CreateSprite(Texture2D texture)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] data = File.ReadAllBytes(filePath);
|
||||
return tex.LoadImage(data, markNonReadable);
|
||||
#if CPP
|
||||
return CreateSprite(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero, 100f, 0u, Vector4.zero);
|
||||
#else
|
||||
return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user