Compare commits

...

45 Commits

Author SHA1 Message Date
995e2a3e93 3.1.11: fix potential crash on scene reload 2021-03-03 22:09:14 +11:00
2c95fec646 3.1.10: Add "Hide on startup" config option 2021-02-27 17:04:47 +11:00
69912d7ea4 Prevent GC Mark Overflow on C# Console copy+paste 2021-02-26 17:54:00 +11:00
9c5596ace4 Update lib versions 2021-02-26 17:52:21 +11:00
d4dac58fc8 Fix for deobfuscated unhollowed types not being properly resolved 2021-02-20 19:39:19 +11:00
77b97cbe17 Update README.md 2021-02-03 18:31:29 +11:00
c6f0f34ac0 Update README.md 2021-01-28 02:09:40 +11:00
d1f4f74d32 some ui cleanups (minor) 2021-01-22 21:56:00 +11:00
f13068bf01 Update README.md 2021-01-20 23:05:04 +11:00
dfc288a101 Update README.md 2021-01-20 19:10:13 +11:00
544009dc21 3.1.7
* Added standalone release build (thanks @Alloc86)
* Improved formatting for ToString methods which accept an IFormatProvider
* When editing a struct, the reference to the parent member will now be updated if you modify the struct values.
2021-01-20 17:22:36 +11:00
fdfaaadd89 3.1.6 - don't bother setting pixelPerfect on canvas 2021-01-14 17:46:32 +11:00
58d60a10d4 Update ForceUnlockCursor.cs 2021-01-04 01:23:20 +11:00
0432c6d56c 3.1.5
* Integrate PR from js6pak
2021-01-03 19:27:02 +11:00
8c34aa2be5 Merge pull request #29 from js6pak/embedded-assetbundle
Load assetbundle from EmbeddedResource
2021-01-03 19:13:15 +11:00
4a1c54fac1 Load assetbundle from EmbeddedResource 2021-01-02 19:38:01 +01:00
190467fa5c Update README.md 2020-12-31 18:34:26 +11:00
44f54d9190 3.1.4 2020-12-31 18:32:52 +11:00
3b4ea31b50 Fix Texture2D saver in Mono and for non-readable textures 2020-12-24 18:10:17 +11:00
ad7b05f721 Just disable EventSystem component and not the entire gameobject 2020-12-21 16:33:34 +11:00
852ca8e9eb New attempt at fixing conflicting EventSystem problems in IL2CPP 2020-12-16 14:28:54 +11:00
7386eca0c2 Update UIManager.cs 2020-12-15 19:33:04 +11:00
97325a5f3a Fix an issue causing duplicated clicks in some IL2CPP games, fix setting Component.enabled in IL2CPP 2020-12-15 19:32:50 +11:00
82e52de557 Cleanup and fix Singleton search slightly 2020-12-14 19:26:59 +11:00
28181e2266 Restoring Texture viewer/saver, and Static/Singleton class searching 2020-12-14 18:35:43 +11:00
6dfa4806ce 3.0.8
Reverting to the previous World-Raycast method as it gave more accurate/expected results
2020-12-12 23:24:44 +11:00
27f6a6ca52 Update README.md 2020-12-10 03:21:22 +11:00
cd7b260ea7 Fix in issue where the Behaviour Enabled toggle doesn't work in IL2CPP 2020-12-08 19:42:44 +11:00
ba986274be Bump version 2020-12-07 22:22:25 +11:00
d181c0bee9 Improved Enumerable and Dictionary enumeration in IL2CPP 2020-12-07 22:22:03 +11:00
a9faec8cf9 Some cleanups 2020-12-03 22:12:30 +11:00
a6bf91b7af accidentally replaced the original asset bundle 2020-11-25 16:47:13 +11:00
e7c5170232 3.0.5 2020-11-25 16:41:42 +11:00
be635e46a0 Swapping to INI instead of XML config, including an AssetBundle for old (5.6.1) Unity versions. 2020-11-25 16:40:36 +11:00
687f56eac9 Update README.md 2020-11-23 21:16:29 +11:00
1dfcdb2dca Update build instructions, remove unnecessary references from CS project file 2020-11-23 20:28:22 +11:00
0025c83930 Fix a preprocessor directive 2020-11-23 20:17:54 +11:00
cfa4b12039 3.0.4
see release notes
2020-11-23 18:23:25 +11:00
c7ccdf387c update version 2020-11-22 18:23:07 +11:00
bb46d77a02 3.0.3
* Fixed not being able to set values on Enums
* [MONO] Fixed an issue where GameObjects in no scene (a Resource/Asset) would display nothing for their scene name, instead of "None (Resource/Asset)".
* Some UI layout cleanups and fixes, the Child/Component lists on the GameObject inspector should now expand to fill available height.
2020-11-22 18:22:57 +11:00
c38155ab04 Fix for InputSystem in 3.0.0 (temp fix for il2cpp) 2020-11-20 17:12:40 +11:00
97dbecaa2a Made instance inspector helper (owner gameobject/name), force loading unhollowed Assembly-CSharp on game start 2020-11-19 16:47:18 +11:00
e77e4cce07 fix release links 2020-11-19 01:41:11 +11:00
dcf0bdce48 disabling EventSystem.current patch for bepinex il2cpp as its causing a crash in some games 2020-11-19 00:55:17 +11:00
2a3df5de9d cleanup CacheMembers a bit 2020-11-17 23:26:22 +11:00
54 changed files with 1931 additions and 1074 deletions

View File

@ -17,7 +17,6 @@
- [Features](#features) - [Features](#features)
- [How to install](#how-to-install) - [How to install](#how-to-install)
- [Mod Config](#mod-config) - [Mod Config](#mod-config)
- [Mouse Control](#mouse-control)
- [Building](#building) - [Building](#building)
- [Credits](#credits) - [Credits](#credits)
@ -25,11 +24,9 @@
| Mod Loader | IL2CPP | Mono | | Mod Loader | IL2CPP | Mono |
| ----------- | ------ | ---- | | ----------- | ------ | ---- |
| [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) | ✔️ [link](https://github.com/sinai-dev/Explorer/releases/latest/download/Explorer.MelonLoader.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/Explorer/releases/latest/download/Explorer.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) |
| [BepInEx](https://github.com/BepInEx/BepInEx) | ✔️ [link](https://github.com/sinai-dev/Explorer/releases/latest/download/Explorer.BepInEx.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/Explorer/releases/latest/download/Explorer.BepInEx.Mono.zip) | | [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) |
<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).
## Features ## Features
@ -52,19 +49,25 @@
0. Install [BepInEx](https://github.com/BepInEx/BepInEx) for your game. 0. Install [BepInEx](https://github.com/BepInEx/BepInEx) for your game.
1. Download the UnityExplorer release for BepInEx IL2CPP or Mono above. 1. Download the UnityExplorer release for BepInEx IL2CPP or Mono above.
2. Take the `UnityExplorer.dll` file and put it in `[GameFolder]\BepInEx\plugins\` 2. Take the `UnityExplorer.BIE.___.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`. 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.
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.
### MelonLoader ### MelonLoader
0. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) for your game. 0. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) for your game.
1. Download the UnityExplorer release for MelonLoader IL2CPP or Mono above. 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 ## Mod Config
You can access the settings via the "Options" page of the main menu, or directly from the config at `Mods\UnityExplorer\config.xml` (generated after first launch). You can access the settings via the "Options" page of the main menu, or directly from the config at `Mods\UnityExplorer\config.ini` (generated after first launch).
`Main Menu Toggle` (KeyCode) `Main Menu Toggle` (KeyCode)
* Default: `F7` * Default: `F7`
@ -80,7 +83,7 @@ You can access the settings via the "Options" page of the main menu, or directly
* <b>Requires a restart to take effect</b>, apart from Reflection Inspector tabs. * <b>Requires a restart to take effect</b>, apart from Reflection Inspector tabs.
`Default Output Path` (string) `Default Output Path` (string)
* Default: `Mods\Explorer` * Default: `Mods\UnityExplorer`
* Where output is generated to, by default (for Texture PNG saving, etc). * Where output is generated to, by default (for Texture PNG saving, etc).
* Currently this is not actually used for anything, but it will be soon. * Currently this is not actually used for anything, but it will be soon.
@ -92,10 +95,10 @@ 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. 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 MelonLoader or BepInEx for your game. 1. Install BepInEx or MelonLoader for your game, or use the standalone build.
2. Open the `src\Explorer.csproj` file in a text editor. 2. Open the `src\UnityExplorer.csproj` file in a text editor.
3. Set the relevant `GameFolder` values for the versions you want to build, eg. set `MLCppGameFolder` if you want to build for a MelonLoader IL2CPP game. 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\Explorer.sln` project. 4. Open the `src\UnityExplorer.sln` project.
5. Select `Solution 'UnityExplorer' (1 of 1 project)` in the Solution Explorer panel, and set the <b>Active config</b> property to the version you want to build, then build it. 5. Select `Solution 'UnityExplorer' (1 of 1 project)` in the Solution Explorer panel, and set the <b>Active config</b> property to the version you want to build, then build it.
5. The DLLs are built to the `Release\` folder in the root of the repository. 5. The DLLs are built to the `Release\` folder in the root of the repository.
6. If ILRepack fails or is missing, use the NuGet package manager to re-install `ILRepack.Lib.MSBuild.Task`, then re-build. 6. If ILRepack fails or is missing, use the NuGet package manager to re-install `ILRepack.Lib.MSBuild.Task`, then re-build.

Binary file not shown.

Binary file not shown.

BIN
lib/INIFileParser.dll Normal file

Binary file not shown.

Binary file not shown.

View File

@ -32,7 +32,7 @@ namespace UnityExplorer.CSConsole
private Text inputHighlightText; private Text inputHighlightText;
private readonly CSharpLexer highlightLexer; private readonly CSharpLexer highlightLexer;
private readonly StringBuilder sbHighlight; //private readonly StringBuilder sbHighlight;
internal int m_lastCaretPos; internal int m_lastCaretPos;
internal int m_fixCaretPos; internal int m_fixCaretPos;
@ -68,7 +68,6 @@ The following helper methods are available:
public CodeEditor() public CodeEditor()
{ {
sbHighlight = new StringBuilder();
highlightLexer = new CSharpLexer(); highlightLexer = new CSharpLexer();
ConstructUI(); ConstructUI();
@ -76,8 +75,24 @@ The following helper methods are available:
InputField.onValueChanged.AddListener((string s) => { OnInputChanged(s); }); InputField.onValueChanged.AddListener((string s) => { OnInputChanged(s); });
} }
internal static bool IsUserCopyPasting()
{
return (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
&& InputManager.GetKeyDown(KeyCode.V);
}
public void Update() public void Update()
{ {
if (s_copyPasteBuffer != null)
{
if (!IsUserCopyPasting())
{
OnInputChanged(s_copyPasteBuffer);
s_copyPasteBuffer = null;
}
}
if (EnableCtrlRShortcut) if (EnableCtrlRShortcut)
{ {
if ((InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl)) if ((InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
@ -149,11 +164,18 @@ The following helper methods are available:
AutoCompleter.ClearAutocompletes(); AutoCompleter.ClearAutocompletes();
} }
public void OnInputChanged(string newInput, bool forceUpdate = false) internal static string s_copyPasteBuffer;
{
string newText = newInput;
UpdateIndent(newInput); public void OnInputChanged(string newText, bool forceUpdate = false)
{
if (IsUserCopyPasting())
{
//Console.WriteLine("Copy+Paste detected!");
s_copyPasteBuffer = newText;
return;
}
UpdateIndent(newText);
if (!forceUpdate && string.IsNullOrEmpty(newText)) if (!forceUpdate && string.IsNullOrEmpty(newText))
inputHighlightText.text = string.Empty; inputHighlightText.text = string.Empty;
@ -203,35 +225,29 @@ The following helper methods are available:
{ {
int offset = 0; int offset = 0;
sbHighlight.Length = 0; //Console.WriteLine("Highlighting input text:\r\n" + inputText);
string ret = "";
foreach (LexerMatchInfo match in highlightLexer.GetMatches(inputText)) foreach (LexerMatchInfo match in highlightLexer.GetMatches(inputText))
{ {
for (int i = offset; i < match.startIndex; i++) for (int i = offset; i < match.startIndex; i++)
{ ret += inputText[i];
sbHighlight.Append(inputText[i]);
}
sbHighlight.Append($"{match.htmlColor}"); ret += $"{match.htmlColor}";
for (int i = match.startIndex; i < match.endIndex; i++) for (int i = match.startIndex; i < match.endIndex; i++)
{ ret += inputText[i];
sbHighlight.Append(inputText[i]);
}
sbHighlight.Append(CLOSE_COLOR_TAG); ret += CLOSE_COLOR_TAG;
offset = match.endIndex; offset = match.endIndex;
} }
for (int i = offset; i < inputText.Length; i++) for (int i = offset; i < inputText.Length; i++)
{ ret += inputText[i];
sbHighlight.Append(inputText[i]);
}
inputText = sbHighlight.ToString(); return ret;
return inputText;
} }
private void AutoIndentCaret() private void AutoIndentCaret()

View File

@ -1,26 +1,31 @@
using System; using System;
using System.IO; using System.IO;
using System.Xml.Serialization;
using UnityEngine; using UnityEngine;
using IniParser;
using IniParser.Parser;
namespace UnityExplorer.Config namespace UnityExplorer.Config
{ {
public class ModConfig public class ModConfig
{ {
[XmlIgnore] public static readonly XmlSerializer Serializer = new XmlSerializer(typeof(ModConfig)); public static ModConfig Instance;
//[XmlIgnore] private const string EXPLORER_FOLDER = @"Mods\UnityExplorer"; internal static readonly IniDataParser _parser = new IniDataParser();
[XmlIgnore] private const string SETTINGS_PATH = ExplorerCore.EXPLORER_FOLDER + @"\config.xml"; internal static readonly string INI_PATH = Path.Combine(ExplorerCore.EXPLORER_FOLDER, "config.ini");
[XmlIgnore] public static ModConfig Instance; static ModConfig()
{
_parser.Configuration.CommentString = "#";
}
// Actual configs // Actual configs
public KeyCode Main_Menu_Toggle = KeyCode.F7; public KeyCode Main_Menu_Toggle = KeyCode.F7;
public bool Force_Unlock_Mouse = true; public bool Force_Unlock_Mouse = true;
public int Default_Page_Limit = 25; 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 Log_Unity_Debug = false;
public bool Save_Logs_To_Disk = true; public bool Hide_On_Startup = false;
//public bool Save_Logs_To_Disk = true;
public static event Action OnConfigChanged; public static event Action OnConfigChanged;
@ -31,38 +36,70 @@ namespace UnityExplorer.Config
public static void OnLoad() public static void OnLoad()
{ {
Instance = new ModConfig();
if (LoadSettings()) if (LoadSettings())
return; return;
Instance = new ModConfig();
SaveSettings(); SaveSettings();
} }
public static bool LoadSettings() public static bool LoadSettings()
{ {
if (!File.Exists(SETTINGS_PATH)) if (!File.Exists(INI_PATH))
return false; return false;
try string ini = File.ReadAllText(INI_PATH);
var data = _parser.Parse(ini);
foreach (var config in data.Sections["Config"])
{ {
using (var file = File.OpenRead(SETTINGS_PATH)) switch (config.KeyName)
Instance = (ModConfig)Serializer.Deserialize(file); {
} case nameof(Main_Menu_Toggle):
catch Instance.Main_Menu_Toggle = (KeyCode)Enum.Parse(typeof(KeyCode), config.Value);
{ break;
return false; case nameof(Force_Unlock_Mouse):
Instance.Force_Unlock_Mouse = bool.Parse(config.Value);
break;
case nameof(Default_Page_Limit):
Instance.Default_Page_Limit = int.Parse(config.Value);
break;
case nameof(Log_Unity_Debug):
Instance.Log_Unity_Debug = bool.Parse(config.Value);
break;
case nameof(Default_Output_Path):
Instance.Default_Output_Path = config.Value;
break;
case nameof(Hide_On_Startup):
Instance.Hide_On_Startup = bool.Parse(config.Value);
break;
//case nameof(Save_Logs_To_Disk):
// Instance.Save_Logs_To_Disk = bool.Parse(config.Value);
// break;
}
} }
return Instance != null; return true;
} }
public static void SaveSettings() public static void SaveSettings()
{ {
if (File.Exists(SETTINGS_PATH)) var data = new IniParser.Model.IniData();
File.Delete(SETTINGS_PATH);
using (var file = File.Create(SETTINGS_PATH)) data.Sections.AddSection("Config");
Serializer.Serialize(file, Instance);
var sec = data.Sections["Config"];
sec.AddKey(nameof(Main_Menu_Toggle), Instance.Main_Menu_Toggle.ToString());
sec.AddKey(nameof(Force_Unlock_Mouse), Instance.Force_Unlock_Mouse.ToString());
sec.AddKey(nameof(Default_Page_Limit), Instance.Default_Page_Limit.ToString());
sec.AddKey(nameof(Log_Unity_Debug), Instance.Log_Unity_Debug.ToString());
sec.AddKey(nameof(Default_Output_Path), Instance.Default_Output_Path);
sec.AddKey(nameof(Hide_On_Startup), Instance.Hide_On_Startup.ToString());
//sec.AddKey("Save_Logs_To_Disk", Instance.Save_Logs_To_Disk.ToString());
File.WriteAllText(INI_PATH, data.ToString());
} }
} }
} }

View File

@ -1,23 +1,45 @@
using System; using System;
using System.IO;
using System.Reflection;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityExplorer.Config; using UnityExplorer.Config;
using UnityExplorer.Helpers;
using UnityExplorer.Input; using UnityExplorer.Input;
using UnityExplorer.Inspectors;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Modules; using UnityExplorer.UI.Modules;
using UnityEngine;
using UnityExplorer.Inspectors;
using System.IO;
using UnityExplorer.Unstrip;
using UnityEngine.SceneManagement;
namespace UnityExplorer namespace UnityExplorer
{ {
public class ExplorerCore public class ExplorerCore
{ {
public const string NAME = "UnityExplorer"; public const string NAME = "UnityExplorer";
public const string VERSION = "3.0.1"; public const string VERSION = "3.1.11";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer"; public const string GUID = "com.sinai.unityexplorer";
public const string EXPLORER_FOLDER = @"Mods\UnityExplorer";
#if ML
public static string EXPLORER_FOLDER = Path.Combine("Mods", NAME);
#elif BIE
public static string EXPLORER_FOLDER = Path.Combine(BepInEx.Paths.ConfigPath, NAME);
#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; } public static ExplorerCore Instance { get; private set; }
@ -41,6 +63,10 @@ namespace UnityExplorer
Instance = this; Instance = this;
#if CPP
ReflectionHelpers.TryLoadGameModules();
#endif
if (!Directory.Exists(EXPLORER_FOLDER)) if (!Directory.Exists(EXPLORER_FOLDER))
Directory.CreateDirectory(EXPLORER_FOLDER); Directory.CreateDirectory(EXPLORER_FOLDER);
@ -84,6 +110,11 @@ namespace UnityExplorer
{ {
UIManager.Init(); UIManager.Init();
Log("Initialized UnityExplorer UI."); Log("Initialized UnityExplorer UI.");
if (ModConfig.Instance.Hide_On_Startup)
ShowMenu = false;
// InspectorManager.Instance.Inspect(Tests.TestClass.Instance);
} }
catch (Exception e) catch (Exception e)
{ {
@ -154,6 +185,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) public static void Log(object message, bool unity = false)
{ {
DebugConsole.Log(message?.ToString()); DebugConsole.Log(message?.ToString());
@ -163,8 +200,10 @@ namespace UnityExplorer
#if ML #if ML
MelonLoader.MelonLogger.Log(message?.ToString()); MelonLoader.MelonLogger.Log(message?.ToString());
#else #elif BIE
ExplorerBepInPlugin.Logging?.LogMessage(message?.ToString()); ExplorerBepInPlugin.Logging?.LogMessage(message?.ToString());
#elif STANDALONE
OnLogMessage?.Invoke(message?.ToString());
#endif #endif
} }
@ -177,8 +216,10 @@ namespace UnityExplorer
#if ML #if ML
MelonLoader.MelonLogger.LogWarning(message?.ToString()); MelonLoader.MelonLogger.LogWarning(message?.ToString());
#else #elif BIE
ExplorerBepInPlugin.Logging?.LogWarning(message?.ToString()); ExplorerBepInPlugin.Logging?.LogWarning(message?.ToString());
#elif STANDALONE
OnLogWarning?.Invoke(message?.ToString());
#endif #endif
} }
@ -191,8 +232,10 @@ namespace UnityExplorer
#if ML #if ML
MelonLoader.MelonLogger.LogError(message?.ToString()); MelonLoader.MelonLogger.LogError(message?.ToString());
#else #elif BIE
ExplorerBepInPlugin.Logging?.LogError(message?.ToString()); ExplorerBepInPlugin.Logging?.LogError(message?.ToString());
#elif STANDALONE
OnLogError?.Invoke(message?.ToString());
#endif #endif
} }

11
src/ExplorerStandalone.cs Normal file
View File

@ -0,0 +1,11 @@
#if STANDALONE
using HarmonyLib;
namespace UnityExplorer
{
public class ExplorerStandalone
{
public static readonly Harmony HarmonyInstance = new Harmony(ExplorerCore.GUID);
}
}
#endif

View File

@ -52,7 +52,7 @@ namespace UnityExplorer.Helpers
return list.ToArray(); return list.ToArray();
} }
public static Type GetActualType(object obj) public static Type GetActualType(this object obj)
{ {
if (obj == null) if (obj == null)
return null; return null;
@ -101,25 +101,52 @@ namespace UnityExplorer.Helpers
return Il2CppToMonoType[cppType]; return Il2CppToMonoType[cppType];
var getType = Type.GetType(cppType.AssemblyQualifiedName); 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> ClassPointers = new Dictionary<Type, IntPtr>(); 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) public static object Il2CppCast(this object obj, Type castTo)
{ {
if (!(obj is Il2CppSystem.Object ilObj)) if (!(obj is Il2CppSystem.Object ilObj))
{
return obj; return obj;
}
if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr)) if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr))
return obj; return obj;
IntPtr classPtr = il2cpp_object_get_class(ilObj.Pointer); IntPtr castFromPtr = il2cpp_object_get_class(ilObj.Pointer);
if (!il2cpp_class_is_assignable_from(castToPtr, classPtr)) if (!il2cpp_class_is_assignable_from(castToPtr, castFromPtr))
return obj; return obj;
if (RuntimeSpecificsStore.IsInjected(castToPtr)) if (RuntimeSpecificsStore.IsInjected(castToPtr))
@ -128,24 +155,54 @@ namespace UnityExplorer.Helpers
return Activator.CreateInstance(castTo, ilObj.Pointer); return Activator.CreateInstance(castTo, ilObj.Pointer);
} }
public static bool Il2CppTypeNotNull(Type type) 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)
{ {
return Il2CppTypeNotNull(type, out _); 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) public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
{ {
if (!ClassPointers.ContainsKey(type)) if (!CppClassPointers.ContainsKey(type))
{ {
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>) il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
.MakeGenericType(new Type[] { type }) .MakeGenericType(new Type[] { type })
.GetField("NativeClassPtr", BF.Public | BF.Static) .GetField("NativeClassPtr", BF.Public | BF.Static)
.GetValue(null); .GetValue(null);
ClassPointers.Add(type, il2cppPtr); CppClassPointers.Add(type, il2cppPtr);
} }
else else
il2cppPtr = ClassPointers[type]; il2cppPtr = CppClassPointers[type];
return il2cppPtr != IntPtr.Zero; return il2cppPtr != IntPtr.Zero;
} }
@ -181,76 +238,95 @@ namespace UnityExplorer.Helpers
} }
} }
#if CPP
internal static void TryLoadGameModules()
{
LoadModule("Assembly-CSharp");
LoadModule("Assembly-CSharp-firstpass");
}
public static bool LoadModule(string module) public static bool LoadModule(string module)
{ {
#if CPP
#if ML #if ML
string path = $@"MelonLoader\Managed\{module}.dll"; var path = $@"MelonLoader\Managed\{module}.dll";
#else #else
var path = $@"BepInEx\unhollowed\{module}.dll"; var path = $@"BepInEx\unhollowed\{module}.dll";
#endif #endif
if (!File.Exists(path))
{ return LoadModuleInternal(path);
}
internal static bool LoadModuleInternal(string fullPath)
{
if (!File.Exists(fullPath))
return false; return false;
}
try try
{ {
Assembly.Load(File.ReadAllBytes(path)); Assembly.Load(File.ReadAllBytes(fullPath));
return true; return true;
} }
catch (Exception e) catch (Exception e)
{ {
ExplorerCore.Log(e.GetType() + ", " + e.Message); Console.WriteLine(e.GetType() + ", " + e.Message);
} }
#endif
return false; return false;
} }
#else
public static bool LoadModule(string module) => true;
#endif
#if CPP
internal static IntPtr s_cppEnumerableClassPtr;
#endif
public static bool IsEnumerable(Type t) public static bool IsEnumerable(Type t)
{ {
if (typeof(IEnumerable).IsAssignableFrom(t)) if (typeof(IEnumerable).IsAssignableFrom(t))
{
return true; 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 CPP
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g) internal static IntPtr s_cppDictionaryClassPtr;
{
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;
#endif #endif
}
public static bool IsDictionary(Type t) public static bool IsDictionary(Type t)
{ {
if (typeof(IDictionary).IsAssignableFrom(t)) if (typeof(IDictionary).IsAssignableFrom(t))
{
return true; return true;
}
#if CPP #if CPP
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g) try
{ {
return typeof(Il2CppSystem.Collections.Generic.Dictionary<,>).IsAssignableFrom(g) if (s_cppDictionaryClassPtr == IntPtr.Zero)
|| typeof(Il2CppSystem.Collections.Generic.IDictionary<,>).IsAssignableFrom(g); 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 catch { }
{
return typeof(Il2CppSystem.Collections.IDictionary).IsAssignableFrom(t)
|| typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(t);
}
#else
return false;
#endif #endif
return false;
} }
public static string ExceptionToString(Exception e, bool innerMost = false) public static string ExceptionToString(Exception e, bool innerMost = false)

View File

@ -10,12 +10,21 @@ namespace UnityExplorer.Helpers
{ {
public static class Texture2DHelpers public static class Texture2DHelpers
{ {
#if CPP // If Mono #if MONO
#else
private static bool isNewEncodeMethod = false; private static bool isNewEncodeMethod = false;
private static MethodInfo EncodeToPNGMethod => m_encodeToPNGMethod ?? GetEncodeToPNGMethod(); private static MethodInfo EncodeToPNGMethod => m_encodeToPNGMethod ?? GetEncodeToPNGMethod();
private static MethodInfo m_encodeToPNGMethod; 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() private static MethodInfo GetEncodeToPNGMethod()
{ {
if (ReflectionHelpers.GetTypeByName("UnityEngine.ImageConversion") is Type imageConversion) if (ReflectionHelpers.GetTypeByName("UnityEngine.ImageConversion") is Type imageConversion)
@ -35,7 +44,6 @@ namespace UnityExplorer.Helpers
} }
#endif #endif
public static bool IsReadable(this Texture2D tex) public static bool IsReadable(this Texture2D tex)
{ {
try try
@ -53,7 +61,7 @@ namespace UnityExplorer.Helpers
} }
} }
public static Texture2D Copy(Texture2D orig, Rect rect) //, bool isDTXnmNormal = false) public static Texture2D Copy(Texture2D orig, Rect rect)
{ {
Color[] pixels; Color[] pixels;
@ -62,12 +70,21 @@ namespace UnityExplorer.Helpers
pixels = orig.GetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height); 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); var _newTex = new Texture2D((int)rect.width, (int)rect.height);
#endif
_newTex.SetPixels(pixels); _newTex.SetPixels(pixels);
return _newTex; return _newTex;
} }
#if CPP
internal delegate void d_Blit2(IntPtr source, IntPtr dest);
#endif
public static Texture2D ForceReadTexture(Texture2D tex) public static Texture2D ForceReadTexture(Texture2D tex)
{ {
try try
@ -78,7 +95,13 @@ namespace UnityExplorer.Helpers
var rt = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32); var rt = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
rt.filterMode = FilterMode.Point; rt.filterMode = FilterMode.Point;
RenderTexture.active = rt; RenderTexture.active = rt;
#if MONO
Graphics.Blit(tex, rt); Graphics.Blit(tex, rt);
#else
var iCall = ICallHelper.GetICall<d_Blit2>("UnityEngine.Graphics::Blit2");
iCall.Invoke(tex.Pointer, rt.Pointer);
#endif
var _newTex = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false); var _newTex = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);

View File

@ -5,6 +5,7 @@
<ItemGroup> <ItemGroup>
<InputAssemblies Include="$(OutputPath)$(AssemblyName).dll" /> <InputAssemblies Include="$(OutputPath)$(AssemblyName).dll" />
<InputAssemblies Include="..\lib\mcs.dll" /> <InputAssemblies Include="..\lib\mcs.dll" />
<InputAssemblies Include="..\lib\INIFileParser.dll" />
</ItemGroup> </ItemGroup>
<ILRepack <ILRepack

View File

@ -1,4 +1,5 @@
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
namespace UnityExplorer.Input namespace UnityExplorer.Input
{ {
@ -11,5 +12,12 @@ namespace UnityExplorer.Input
bool GetMouseButtonDown(int btn); bool GetMouseButtonDown(int btn);
bool GetMouseButton(int btn); bool GetMouseButton(int btn);
BaseInputModule UIModule { get; }
PointerEventData InputPointerEvent { get; }
void AddUIInputModule();
void ActivateModule();
} }
} }

View File

@ -2,34 +2,26 @@
using UnityEngine; using UnityEngine;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using UnityEngine.EventSystems;
#if CPP #if CPP
using UnhollowerBaseLib; using UnhollowerBaseLib;
#endif #endif
namespace UnityExplorer.Input namespace UnityExplorer.Input
{ {
public enum InputType
{
InputSystem,
Legacy,
None
}
public static class InputManager public static class InputManager
{ {
public static InputType CurrentType { get; private set; }
private static IHandleInput m_inputModule; private static IHandleInput m_inputModule;
public static void Init()
{
if (InputSystem.TKeyboard != null || (ReflectionHelpers.LoadModule("Unity.InputSystem") && InputSystem.TKeyboard != null))
{
m_inputModule = new InputSystem();
}
else if (LegacyInput.TInput != null || (ReflectionHelpers.LoadModule("UnityEngine.InputLegacyModule") && LegacyInput.TInput != null))
{
m_inputModule = new LegacyInput();
}
if (m_inputModule == null)
{
ExplorerCore.LogWarning("Could not find any Input module!");
m_inputModule = new NoInput();
}
}
public static Vector3 MousePosition => m_inputModule.MousePosition; public static Vector3 MousePosition => m_inputModule.MousePosition;
public static bool GetKeyDown(KeyCode key) => m_inputModule.GetKeyDown(key); public static bool GetKeyDown(KeyCode key) => m_inputModule.GetKeyDown(key);
@ -37,5 +29,37 @@ namespace UnityExplorer.Input
public static bool GetMouseButtonDown(int btn) => m_inputModule.GetMouseButtonDown(btn); public static bool GetMouseButtonDown(int btn) => m_inputModule.GetMouseButtonDown(btn);
public static bool GetMouseButton(int btn) => m_inputModule.GetMouseButton(btn); public static bool GetMouseButton(int btn) => m_inputModule.GetMouseButton(btn);
public static BaseInputModule UIInput => m_inputModule.UIModule;
public static PointerEventData InputPointerEvent => m_inputModule.InputPointerEvent;
public static void ActivateUIModule() => m_inputModule.ActivateModule();
public static void AddUIModule()
{
m_inputModule.AddUIInputModule();
ActivateUIModule();
}
public static void Init()
{
if (InputSystem.TKeyboard != null || (ReflectionHelpers.LoadModule("Unity.InputSystem") && InputSystem.TKeyboard != null))
{
m_inputModule = new InputSystem();
CurrentType = InputType.InputSystem;
}
else if (LegacyInput.TInput != null || (ReflectionHelpers.LoadModule("UnityEngine.InputLegacyModule") && LegacyInput.TInput != null))
{
m_inputModule = new LegacyInput();
CurrentType = InputType.Legacy;
}
if (m_inputModule == null)
{
ExplorerCore.LogWarning("Could not find any Input module!");
m_inputModule = new NoInput();
CurrentType = InputType.None;
}
}
} }
} }

View File

@ -2,6 +2,9 @@
using System.Reflection; using System.Reflection;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
using UnityExplorer.UI;
using System.Collections.Generic;
namespace UnityExplorer.Input namespace UnityExplorer.Input
{ {
@ -64,24 +67,46 @@ namespace UnityExplorer.Input
private static PropertyInfo m_positionProp; private static PropertyInfo m_positionProp;
private static MethodInfo m_readVector2InputMethod; private static MethodInfo m_readVector2InputMethod;
public Vector2 MousePosition => (Vector2)m_readVector2InputMethod.Invoke(MousePositionInfo, new object[0]); public Vector2 MousePosition
public bool GetKeyDown(KeyCode key)
{ {
var parsedKey = Enum.Parse(TKey, key.ToString()); get
var actualKey = m_kbIndexer.GetValue(CurrentKeyboard, new object[] { parsedKey }); {
try
return (bool)m_btnWasPressedProp.GetValue(actualKey, null); {
return (Vector2)m_readVector2InputMethod.Invoke(MousePositionInfo, new object[0]);
}
catch
{
return Vector2.zero;
}
}
} }
public bool GetKey(KeyCode key) internal static Dictionary<KeyCode, object> ActualKeyDict = new Dictionary<KeyCode, object>();
{
var parsed = Enum.Parse(TKey, key.ToString());
var actualKey = m_kbIndexer.GetValue(CurrentKeyboard, new object[] { parsed });
return (bool)m_btnIsPressedProp.GetValue(actualKey, null); internal object GetActualKey(KeyCode key)
{
if (!ActualKeyDict.ContainsKey(key))
{
var s = key.ToString();
if (s.Contains("Control"))
s = s.Replace("Control", "Ctrl");
else if (s.Contains("Return"))
s = "Enter";
var parsed = Enum.Parse(TKey, s);
var actualKey = m_kbIndexer.GetValue(CurrentKeyboard, new object[] { parsed });
ActualKeyDict.Add(key, actualKey);
}
return ActualKeyDict[key];
} }
public bool GetKeyDown(KeyCode key) => (bool)m_btnWasPressedProp.GetValue(GetActualKey(key), null);
public bool GetKey(KeyCode key) => (bool)m_btnIsPressedProp.GetValue(GetActualKey(key), null);
public bool GetMouseButtonDown(int btn) public bool GetMouseButtonDown(int btn)
{ {
switch (btn) switch (btn)
@ -103,5 +128,44 @@ namespace UnityExplorer.Input
default: throw new NotImplementedException(); default: throw new NotImplementedException();
} }
} }
// UI Input
//public Type TInputSystemUIInputModule
// => m_tUIInputModule
// ?? (m_tUIInputModule = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.UI.InputSystemUIInputModule"));
//internal Type m_tUIInputModule;
public BaseInputModule UIModule => null; // m_newInputModule;
//internal BaseInputModule m_newInputModule;
public PointerEventData InputPointerEvent => null;
public void AddUIInputModule()
{
// if (TInputSystemUIInputModule != null)
// {
//#if CPP
// // m_newInputModule = UIManager.CanvasRoot.AddComponent(Il2CppType.From(TInputSystemUIInputModule)).TryCast<BaseInputModule>();
//#else
// m_newInputModule = (BaseInputModule)UIManager.CanvasRoot.AddComponent(TInputSystemUIInputModule);
//#endif
// }
// else
// {
// ExplorerCore.LogWarning("New input system: Could not find type by name 'UnityEngine.InputSystem.UI.InputSystemUIInputModule'");
// }
}
public void ActivateModule()
{
//#if CPP
// // m_newInputModule.ActivateModule();
//#else
// m_newInputModule.ActivateModule();
//#endif
}
} }
} }

View File

@ -2,6 +2,8 @@
using System.Reflection; using System.Reflection;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
using UnityExplorer.UI;
namespace UnityExplorer.Input namespace UnityExplorer.Input
{ {
@ -36,5 +38,27 @@ namespace UnityExplorer.Input
public bool GetMouseButton(int btn) => (bool)m_getMouseButtonMethod.Invoke(null, new object[] { btn }); public bool GetMouseButton(int btn) => (bool)m_getMouseButtonMethod.Invoke(null, new object[] { btn });
public bool GetMouseButtonDown(int btn) => (bool)m_getMouseButtonDownMethod.Invoke(null, new object[] { btn }); public bool GetMouseButtonDown(int btn) => (bool)m_getMouseButtonDownMethod.Invoke(null, new object[] { btn });
// UI Input module
public BaseInputModule UIModule => m_inputModule;
internal StandaloneInputModule m_inputModule;
public PointerEventData InputPointerEvent =>
#if CPP
m_inputModule.m_InputPointerEvent;
#else
null;
#endif
public void AddUIInputModule()
{
m_inputModule = UIManager.CanvasRoot.gameObject.AddComponent<StandaloneInputModule>();
}
public void ActivateModule()
{
m_inputModule.ActivateModule();
}
} }
} }

View File

@ -1,4 +1,5 @@
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
namespace UnityExplorer.Input namespace UnityExplorer.Input
{ {
@ -13,5 +14,10 @@ namespace UnityExplorer.Input
public bool GetMouseButton(int btn) => false; public bool GetMouseButton(int btn) => false;
public bool GetMouseButtonDown(int btn) => false; public bool GetMouseButtonDown(int btn) => false;
public BaseInputModule UIModule => null;
public PointerEventData InputPointerEvent => null;
public void ActivateModule() { }
public void AddUIInputModule() { }
} }
} }

View File

@ -140,7 +140,7 @@ namespace UnityExplorer.Inspectors.GameObjects
{ {
var vertGroupObj = UIFactory.CreateVerticalGroup(parent, new Color(1, 1, 1, 0)); var vertGroupObj = UIFactory.CreateVerticalGroup(parent, new Color(1, 1, 1, 0));
var vertGroup = vertGroupObj.GetComponent<VerticalLayoutGroup>(); var vertGroup = vertGroupObj.GetComponent<VerticalLayoutGroup>();
vertGroup.childForceExpandHeight = false; vertGroup.childForceExpandHeight = true;
vertGroup.childForceExpandWidth = false; vertGroup.childForceExpandWidth = false;
vertGroup.childControlWidth = true; vertGroup.childControlWidth = true;
vertGroup.spacing = 5; vertGroup.spacing = 5;

View File

@ -80,7 +80,11 @@ namespace UnityExplorer.Inspectors.GameObjects
text.text = UISyntaxHighlight.ParseFullSyntax(ReflectionHelpers.GetActualType(comp), true); text.text = UISyntaxHighlight.ParseFullSyntax(ReflectionHelpers.GetActualType(comp), true);
var toggle = s_compToggles[i]; var toggle = s_compToggles[i];
#if CPP
if (comp.TryCast<Behaviour>() is Behaviour behaviour)
#else
if (comp is Behaviour behaviour) if (comp is Behaviour behaviour)
#endif
{ {
if (!toggle.gameObject.activeSelf) if (!toggle.gameObject.activeSelf)
toggle.gameObject.SetActive(true); toggle.gameObject.SetActive(true);
@ -107,8 +111,11 @@ namespace UnityExplorer.Inspectors.GameObjects
internal static void OnCompToggleClicked(int index, bool value) internal static void OnCompToggleClicked(int index, bool value)
{ {
var comp = s_compShortlist[index]; var comp = s_compShortlist[index];
#if CPP
comp.TryCast<Behaviour>().enabled = value;
#else
(comp as Behaviour).enabled = value; (comp as Behaviour).enabled = value;
#endif
} }
internal static void OnCompListObjectClicked(int index) internal static void OnCompListObjectClicked(int index)
@ -130,13 +137,13 @@ namespace UnityExplorer.Inspectors.GameObjects
} }
#region UI CONSTRUCTION #region UI CONSTRUCTION
internal void ConstructCompList(GameObject parent) internal void ConstructCompList(GameObject parent)
{ {
var vertGroupObj = UIFactory.CreateVerticalGroup(parent, new Color(1, 1, 1, 0)); var vertGroupObj = UIFactory.CreateVerticalGroup(parent, new Color(1, 1, 1, 0));
var vertGroup = vertGroupObj.GetComponent<VerticalLayoutGroup>(); var vertGroup = vertGroupObj.GetComponent<VerticalLayoutGroup>();
vertGroup.childForceExpandHeight = false; vertGroup.childForceExpandHeight = true;
vertGroup.childForceExpandWidth = false; vertGroup.childForceExpandWidth = false;
vertGroup.childControlWidth = true; vertGroup.childControlWidth = true;
vertGroup.spacing = 5; vertGroup.spacing = 5;
@ -157,6 +164,7 @@ namespace UnityExplorer.Inspectors.GameObjects
var compScrollObj = UIFactory.CreateScrollView(vertGroupObj, out s_compListContent, out SliderScrollbar scroller, new Color(0.07f, 0.07f, 0.07f)); var compScrollObj = UIFactory.CreateScrollView(vertGroupObj, out s_compListContent, out SliderScrollbar scroller, new Color(0.07f, 0.07f, 0.07f));
var contentLayout = compScrollObj.AddComponent<LayoutElement>(); var contentLayout = compScrollObj.AddComponent<LayoutElement>();
contentLayout.minHeight = 50; contentLayout.minHeight = 50;
contentLayout.flexibleHeight = 5000;
s_compListPageHandler = new PageHandler(scroller); s_compListPageHandler = new PageHandler(scroller);
s_compListPageHandler.ConstructUI(vertGroupObj); s_compListPageHandler.ConstructUI(vertGroupObj);
@ -167,34 +175,34 @@ namespace UnityExplorer.Inspectors.GameObjects
{ {
int thisIndex = s_compListTexts.Count; int thisIndex = s_compListTexts.Count;
GameObject btnGroupObj = UIFactory.CreateHorizontalGroup(s_compListContent, new Color(0.07f, 0.07f, 0.07f)); GameObject groupObj = UIFactory.CreateHorizontalGroup(s_compListContent, new Color(0.07f, 0.07f, 0.07f));
HorizontalLayoutGroup btnGroup = btnGroupObj.GetComponent<HorizontalLayoutGroup>(); HorizontalLayoutGroup group = groupObj.GetComponent<HorizontalLayoutGroup>();
btnGroup.childForceExpandWidth = true; group.childForceExpandWidth = true;
btnGroup.childControlWidth = true; group.childControlWidth = true;
btnGroup.childForceExpandHeight = false; group.childForceExpandHeight = false;
btnGroup.childControlHeight = true; group.childControlHeight = true;
btnGroup.childAlignment = TextAnchor.MiddleLeft; group.childAlignment = TextAnchor.MiddleLeft;
LayoutElement btnLayout = btnGroupObj.AddComponent<LayoutElement>(); LayoutElement groupLayout = groupObj.AddComponent<LayoutElement>();
btnLayout.minWidth = 25; groupLayout.minWidth = 25;
btnLayout.flexibleWidth = 999; groupLayout.flexibleWidth = 999;
btnLayout.minHeight = 25; groupLayout.minHeight = 25;
btnLayout.flexibleHeight = 0; groupLayout.flexibleHeight = 0;
btnGroupObj.AddComponent<Mask>(); groupObj.AddComponent<Mask>();
// Behaviour enabled toggle // 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>(); var toggleLayout = toggleObj.AddComponent<LayoutElement>();
toggleLayout.minHeight = 25; toggleLayout.minHeight = 25;
toggleLayout.minWidth = 25; toggleLayout.minWidth = 25;
toggleText.text = ""; toggleText.text = "";
toggle.isOn = false; toggle.isOn = true;
s_compToggles.Add(toggle); s_compToggles.Add(toggle);
toggle.onValueChanged.AddListener((bool val) => { OnCompToggleClicked(thisIndex, val); }); toggle.onValueChanged.AddListener((bool val) => { OnCompToggleClicked(thisIndex, val); });
// Main component button // Main component button
GameObject mainButtonObj = UIFactory.CreateButton(btnGroupObj); GameObject mainButtonObj = UIFactory.CreateButton(groupObj);
LayoutElement mainBtnLayout = mainButtonObj.AddComponent<LayoutElement>(); LayoutElement mainBtnLayout = mainButtonObj.AddComponent<LayoutElement>();
mainBtnLayout.minHeight = 25; mainBtnLayout.minHeight = 25;
mainBtnLayout.flexibleHeight = 0; mainBtnLayout.flexibleHeight = 0;
@ -223,6 +231,6 @@ namespace UnityExplorer.Inspectors.GameObjects
} }
#endregion #endregion
} }
} }

View File

@ -164,7 +164,7 @@ namespace UnityExplorer.Inspectors
m_layerDropdown.value = TargetGO.layer; m_layerDropdown.value = TargetGO.layer;
} }
if (m_lastScene != TargetGO.scene.name) if (string.IsNullOrEmpty(m_lastScene) || m_lastScene != TargetGO.scene.name)
{ {
m_lastScene = TargetGO.scene.name; m_lastScene = TargetGO.scene.name;
@ -217,10 +217,20 @@ namespace UnityExplorer.Inspectors
s_content = UIFactory.CreateScrollView(parent, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f)); s_content = UIFactory.CreateScrollView(parent, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f));
var parentLayout = scrollContent.transform.parent.gameObject.AddComponent<VerticalLayoutGroup>();
parentLayout.childForceExpandWidth = true;
parentLayout.childControlWidth = true;
parentLayout.childForceExpandHeight = true;
parentLayout.childControlHeight = true;
var scrollGroup = scrollContent.GetComponent<VerticalLayoutGroup>(); var scrollGroup = scrollContent.GetComponent<VerticalLayoutGroup>();
scrollGroup.childForceExpandHeight = true; scrollGroup.childForceExpandHeight = true;
scrollGroup.childControlHeight = true; scrollGroup.childControlHeight = true;
scrollGroup.childForceExpandWidth = true;
scrollGroup.childControlWidth = true;
scrollGroup.spacing = 5; scrollGroup.spacing = 5;
var contentFitter = scrollContent.GetComponent<ContentSizeFitter>();
contentFitter.verticalFit = ContentSizeFitter.FitMode.Unconstrained;
ConstructTopArea(scrollContent); ConstructTopArea(scrollContent);
@ -230,6 +240,9 @@ namespace UnityExplorer.Inspectors
s_childList.ConstructChildList(midGroupObj); s_childList.ConstructChildList(midGroupObj);
s_compList.ConstructCompList(midGroupObj); s_compList.ConstructCompList(midGroupObj);
LayoutRebuilder.ForceRebuildLayoutImmediate(s_content.GetComponent<RectTransform>());
Canvas.ForceUpdateCanvases();
} }
private void ConstructTopArea(GameObject scrollContent) private void ConstructTopArea(GameObject scrollContent)
@ -431,11 +444,10 @@ namespace UnityExplorer.Inspectors
midGroup.childControlWidth = true; midGroup.childControlWidth = true;
midGroup.childForceExpandHeight = true; midGroup.childForceExpandHeight = true;
midGroup.childControlHeight = true; midGroup.childControlHeight = true;
var midlayout = midGroupObj.AddComponent<LayoutElement>();
midlayout.minHeight = 350; var midLayout = midGroupObj.AddComponent<LayoutElement>();
midlayout.flexibleHeight = 10000; midLayout.minHeight = 300;
midlayout.minWidth = 200; midLayout.flexibleHeight = 5000;
midlayout.flexibleWidth = 25000;
return midGroupObj; return midGroupObj;
} }

View File

@ -38,7 +38,7 @@ namespace UnityExplorer.Inspectors
} }
} }
public void Inspect(object obj) public void Inspect(object obj, CacheObjectBase parentMember = null)
{ {
#if CPP #if CPP
obj = obj.Il2CppCast(ReflectionHelpers.GetActualType(obj)); obj = obj.Il2CppCast(ReflectionHelpers.GetActualType(obj));
@ -76,6 +76,9 @@ namespace UnityExplorer.Inspectors
else else
inspector = new InstanceInspector(obj); inspector = new InstanceInspector(obj);
if (inspector is ReflectionInspector ri)
ri.ParentMember = parentMember;
m_currentInspectors.Add(inspector); m_currentInspectors.Add(inspector);
SetInspectorTab(inspector); SetInspectorTab(inspector);
} }
@ -230,102 +233,35 @@ namespace UnityExplorer.Inspectors
invisGroup.padding.right = 2; invisGroup.padding.right = 2;
invisGroup.spacing = 10; invisGroup.spacing = 10;
// // time scale group
// var timeGroupObj = UIFactory.CreateHorizontalGroup(invisObj, new Color(1, 1, 1, 0));
// var timeGroup = timeGroupObj.GetComponent<HorizontalLayoutGroup>();
// timeGroup.childForceExpandWidth = false;
// timeGroup.childControlWidth = true;
// timeGroup.childForceExpandHeight = false;
// timeGroup.childControlHeight = true;
// timeGroup.padding.top = 2;
// timeGroup.padding.left = 5;
// timeGroup.padding.right = 2;
// timeGroup.padding.bottom = 2;
// timeGroup.spacing = 5;
// timeGroup.childAlignment = TextAnchor.MiddleCenter;
// var timeGroupLayout = timeGroupObj.AddComponent<LayoutElement>();
// timeGroupLayout.minWidth = 100;
// timeGroupLayout.flexibleWidth = 300;
// timeGroupLayout.minHeight = 25;
// timeGroupLayout.flexibleHeight = 0;
// // time scale title
// var timeTitleObj = UIFactory.CreateLabel(timeGroupObj, TextAnchor.MiddleLeft);
// var timeTitle = timeTitleObj.GetComponent<Text>();
// timeTitle.text = "Time Scale:";
// timeTitle.color = new Color(21f / 255f, 192f / 255f, 235f / 255f);
// var titleLayout = timeTitleObj.AddComponent<LayoutElement>();
// titleLayout.minHeight = 25;
// titleLayout.minWidth = 80;
// titleLayout.flexibleHeight = 0;
// timeTitle.horizontalOverflow = HorizontalWrapMode.Overflow;
// // actual active time label
// var timeLabelObj = UIFactory.CreateLabel(timeGroupObj, TextAnchor.MiddleLeft);
// var timeLabelLayout = timeLabelObj.AddComponent<LayoutElement>();
// timeLabelLayout.minWidth = 40;
// timeLabelLayout.minHeight = 25;
// timeLabelLayout.flexibleHeight = 0;
// // todo make static and update
// var s_timeText = timeLabelObj.GetComponent<Text>();
// s_timeText.text = Time.timeScale.ToString("F1");
// // time scale input
// var timeInputObj = UIFactory.CreateInputField(timeGroupObj);
// var timeInput = timeInputObj.GetComponent<InputField>();
// timeInput.characterValidation = InputField.CharacterValidation.Decimal;
// var timeInputLayout = timeInputObj.AddComponent<LayoutElement>();
// timeInputLayout.minWidth = 90;
// timeInputLayout.flexibleWidth = 0;
// timeInputLayout.minHeight = 25;
// timeInputLayout.flexibleHeight = 0;
// // time scale apply button
// var applyBtnObj = UIFactory.CreateButton(timeGroupObj);
// var applyBtn = applyBtnObj.GetComponent<Button>();
// applyBtn.onClick.AddListener(SetTimeScale);
// var applyText = applyBtnObj.GetComponentInChildren<Text>();
// applyText.text = "Apply";
// applyText.fontSize = 14;
// var applyLayout = applyBtnObj.AddComponent<LayoutElement>();
// applyLayout.minWidth = 50;
// applyLayout.minHeight = 25;
// applyLayout.flexibleHeight = 0;
// void SetTimeScale()
// {
// var scale = float.Parse(timeInput.text);
// Time.timeScale = scale;
// s_timeText.text = Time.timeScale.ToString("F1");
// }
// inspect under mouse button // inspect under mouse button
AddMouseInspectButton(topRowObj, MouseInspector.MouseInspectMode.UI);
AddMouseInspectButton(topRowObj, MouseInspector.MouseInspectMode.World);
}
private static void AddMouseInspectButton(GameObject topRowObj, MouseInspector.MouseInspectMode mode)
{
var inspectObj = UIFactory.CreateButton(topRowObj); var inspectObj = UIFactory.CreateButton(topRowObj);
var inspectLayout = inspectObj.AddComponent<LayoutElement>(); var inspectLayout = inspectObj.AddComponent<LayoutElement>();
inspectLayout.minWidth = 120; inspectLayout.minWidth = 120;
inspectLayout.flexibleWidth = 0; inspectLayout.flexibleWidth = 0;
var inspectText = inspectObj.GetComponentInChildren<Text>();
inspectText.text = "Mouse Inspect";
inspectText.fontSize = 13;
if (mode == MouseInspector.MouseInspectMode.UI)
inspectText.text += " (UI)";
var inspectBtn = inspectObj.GetComponent<Button>(); var inspectBtn = inspectObj.GetComponent<Button>();
var inspectColors = inspectBtn.colors; var inspectColors = inspectBtn.colors;
inspectColors.normalColor = new Color(0.2f, 0.2f, 0.2f); inspectColors.normalColor = new Color(0.2f, 0.2f, 0.2f);
inspectBtn.colors = inspectColors; inspectBtn.colors = inspectColors;
var inspectText = inspectObj.GetComponentInChildren<Text>();
inspectText.text = "Mouse Inspect";
inspectText.fontSize = 13;
inspectBtn.onClick.AddListener(OnInspectMouseClicked); inspectBtn.onClick.AddListener(OnInspectMouseClicked);
void OnInspectMouseClicked() void OnInspectMouseClicked()
{ {
MouseInspector.Mode = mode;
MouseInspector.StartInspect(); MouseInspector.StartInspect();
} }
} }

View File

@ -3,18 +3,27 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
using UnityExplorer.Input; using UnityExplorer.Input;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.Unstrip;
namespace UnityExplorer.Inspectors namespace UnityExplorer.Inspectors
{ {
public class MouseInspector public class MouseInspector
{ {
public enum MouseInspectMode
{
World,
UI
}
public static bool Enabled { get; set; } public static bool Enabled { get; set; }
//internal static Text s_objUnderMouseName; public static MouseInspectMode Mode { get; set; }
internal static Text s_objNameLabel; internal static Text s_objNameLabel;
internal static Text s_objPathLabel; internal static Text s_objPathLabel;
internal static Text s_mousePosLabel; internal static Text s_mousePosLabel;
@ -29,6 +38,18 @@ namespace UnityExplorer.Inspectors
Enabled = true; Enabled = true;
MainMenu.Instance.MainPanel.SetActive(false); MainMenu.Instance.MainPanel.SetActive(false);
s_UIContent.SetActive(true); s_UIContent.SetActive(true);
// recache Graphic Raycasters each time we start
var casters = ResourcesUnstrip.FindObjectsOfTypeAll(typeof(GraphicRaycaster));
m_gCasters = new GraphicRaycaster[casters.Length];
for (int i = 0; i < casters.Length; i++)
{
#if CPP
m_gCasters[i] = casters[i].TryCast<GraphicRaycaster>();
#else
m_gCasters[i] = casters[i] as GraphicRaycaster;
#endif
}
} }
public static void StopInspect() public static void StopInspect()
@ -40,50 +61,60 @@ namespace UnityExplorer.Inspectors
ClearHitData(); ClearHitData();
} }
internal static GraphicRaycaster[] m_gCasters;
public static void UpdateInspect() public static void UpdateInspect()
{ {
if (InputManager.GetKeyDown(KeyCode.Escape)) if (InputManager.GetKeyDown(KeyCode.Escape))
{ {
StopInspect(); StopInspect();
return;
} }
var mousePos = InputManager.MousePosition; var mousePos = InputManager.MousePosition;
if (mousePos != s_lastMousePos) if (mousePos != s_lastMousePos)
{ UpdatePosition(mousePos);
s_lastMousePos = mousePos;
var inversePos = UIManager.CanvasRoot.transform.InverseTransformPoint(mousePos);
s_mousePosLabel.text = $"<color=grey>Mouse Position:</color> {((Vector2)InputManager.MousePosition).ToString()}";
float yFix = mousePos.y < 120 ? 80 : -80;
s_UIContent.transform.localPosition = new Vector3(inversePos.x, inversePos.y + yFix, 0);
}
if (!UnityHelpers.MainCamera) if (!UnityHelpers.MainCamera)
return; return;
// actual inspect raycast // actual inspect raycast
var ray = UnityHelpers.MainCamera.ScreenPointToRay(mousePos);
if (Physics.Raycast(ray, out RaycastHit hit, 1000f)) switch (Mode)
{
case MouseInspectMode.UI:
RaycastUI(mousePos); break;
case MouseInspectMode.World:
RaycastWorld(mousePos); break;
}
}
internal static void OnHitGameObject(GameObject obj)
{
if (obj != s_lastHit)
{
s_lastHit = obj;
s_objNameLabel.text = $"<b>Click to Inspect:</b> <color=cyan>{obj.name}</color>";
s_objPathLabel.text = $"Path: {obj.transform.GetTransformPath(true)}";
}
if (InputManager.GetMouseButtonDown(0))
{
StopInspect();
InspectorManager.Instance.Inspect(obj);
}
}
internal static void RaycastWorld(Vector2 mousePos)
{
var ray = UnityHelpers.MainCamera.ScreenPointToRay(mousePos);
Physics.Raycast(ray, out RaycastHit hit, 1000f);
if (hit.transform)
{ {
var obj = hit.transform.gameObject; var obj = hit.transform.gameObject;
OnHitGameObject(obj);
if (obj != s_lastHit)
{
s_lastHit = obj;
s_objNameLabel.text = $"<b>Click to Inspect:</b> <color=cyan>{obj.name}</color>";
s_objPathLabel.text = $"Path: {obj.transform.GetTransformPath(true)}";
}
if (InputManager.GetMouseButtonDown(0))
{
StopInspect();
InspectorManager.Instance.Inspect(obj);
}
} }
else else
{ {
@ -92,6 +123,56 @@ namespace UnityExplorer.Inspectors
} }
} }
internal static void RaycastUI(Vector2 mousePos)
{
var ped = new PointerEventData(null)
{
position = mousePos
};
#if MONO
var list = new List<RaycastResult>();
#else
var list = new Il2CppSystem.Collections.Generic.List<RaycastResult>();
#endif
foreach (var gr in m_gCasters)
{
gr.Raycast(ped, list);
if (list.Count > 0)
{
foreach (var hit in list)
{
if (hit.gameObject)
{
var obj = hit.gameObject;
OnHitGameObject(obj);
break;
}
}
}
else
{
if (s_lastHit)
ClearHitData();
}
}
}
internal static void UpdatePosition(Vector2 mousePos)
{
s_lastMousePos = mousePos;
var inversePos = UIManager.CanvasRoot.transform.InverseTransformPoint(mousePos);
s_mousePosLabel.text = $"<color=grey>Mouse Position:</color> {mousePos.ToString()}";
float yFix = mousePos.y < 120 ? 80 : -80;
s_UIContent.transform.localPosition = new Vector3(inversePos.x, inversePos.y + yFix, 0);
}
internal static void ClearHitData() internal static void ClearHitData()
{ {
s_lastHit = null; s_lastHit = null;
@ -99,7 +180,7 @@ namespace UnityExplorer.Inspectors
s_objPathLabel.text = ""; s_objPathLabel.text = "";
} }
#region UI Construction #region UI Construction
internal static void ConstructUI() internal static void ConstructUI()
{ {
@ -112,7 +193,10 @@ namespace UnityExplorer.Inspectors
baseRect.anchorMin = half; baseRect.anchorMin = half;
baseRect.anchorMax = half; baseRect.anchorMax = half;
baseRect.pivot = half; baseRect.pivot = half;
baseRect.sizeDelta = new Vector2(700, 100); baseRect.sizeDelta = new Vector2(700, 150);
var group = content.GetComponent<VerticalLayoutGroup>();
group.childForceExpandHeight = true;
// Title text // Title text
@ -131,13 +215,16 @@ namespace UnityExplorer.Inspectors
var pathLabelObj = UIFactory.CreateLabel(content, TextAnchor.MiddleLeft); var pathLabelObj = UIFactory.CreateLabel(content, TextAnchor.MiddleLeft);
s_objPathLabel = pathLabelObj.GetComponent<Text>(); s_objPathLabel = pathLabelObj.GetComponent<Text>();
s_objPathLabel.color = Color.grey;
s_objPathLabel.fontStyle = FontStyle.Italic; s_objPathLabel.fontStyle = FontStyle.Italic;
s_objPathLabel.horizontalOverflow = HorizontalWrapMode.Overflow; s_objPathLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
var pathLayout = pathLabelObj.AddComponent<LayoutElement>();
pathLayout.minHeight = 75;
pathLayout.flexibleHeight = 0;
s_UIContent.SetActive(false); s_UIContent.SetActive(false);
} }
#endregion #endregion
} }
} }

View File

@ -5,6 +5,7 @@ using System.Text;
using System.Reflection; using System.Reflection;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
using UnityEngine;
namespace UnityExplorer.Inspectors.Reflection namespace UnityExplorer.Inspectors.Reflection
{ {
@ -14,7 +15,7 @@ namespace UnityExplorer.Inspectors.Reflection
public override Type FallbackType => (MemInfo as FieldInfo).FieldType; public override Type FallbackType => (MemInfo as FieldInfo).FieldType;
public CacheField(FieldInfo fieldInfo, object declaringInstance) : base(fieldInfo, declaringInstance) public CacheField(FieldInfo fieldInfo, object declaringInstance, GameObject parent) : base(fieldInfo, declaringInstance, parent)
{ {
CreateIValue(null, fieldInfo.FieldType); CreateIValue(null, fieldInfo.FieldType);
} }
@ -32,6 +33,9 @@ namespace UnityExplorer.Inspectors.Reflection
{ {
var fi = MemInfo as FieldInfo; var fi = MemInfo as FieldInfo;
fi.SetValue(fi.IsStatic ? null : DeclaringInstance, IValue.Value); fi.SetValue(fi.IsStatic ? null : DeclaringInstance, IValue.Value);
if (this.ParentInspector?.ParentMember != null)
this.ParentInspector.ParentMember.SetValue();
} }
} }
} }

View File

@ -19,6 +19,7 @@ namespace UnityExplorer.Inspectors.Reflection
public override Type FallbackType { get; } public override Type FallbackType { get; }
public ReflectionInspector ParentInspector { get; set; }
public MemberInfo MemInfo { get; set; } public MemberInfo MemInfo { get; set; }
public Type DeclaringType { get; set; } public Type DeclaringType { get; set; }
public object DeclaringInstance { get; set; } public object DeclaringInstance { get; set; }
@ -43,11 +44,12 @@ namespace UnityExplorer.Inspectors.Reflection
public string RichTextName => m_richTextName ?? GetRichTextName(); public string RichTextName => m_richTextName ?? GetRichTextName();
private string m_richTextName; private string m_richTextName;
public CacheMember(MemberInfo memberInfo, object declaringInstance) public CacheMember(MemberInfo memberInfo, object declaringInstance, GameObject parentContent)
{ {
MemInfo = memberInfo; MemInfo = memberInfo;
DeclaringType = memberInfo.DeclaringType; DeclaringType = memberInfo.DeclaringType;
DeclaringInstance = declaringInstance; DeclaringInstance = declaringInstance;
this.m_parentContent = parentContent;
#if CPP #if CPP
if (DeclaringInstance != null) if (DeclaringInstance != null)
DeclaringInstance = DeclaringInstance.Il2CppCast(DeclaringType); DeclaringInstance = DeclaringInstance.Il2CppCast(DeclaringType);

View File

@ -26,7 +26,7 @@ namespace UnityExplorer.Inspectors.Reflection
public string[] m_genericArgInput = new string[0]; public string[] m_genericArgInput = new string[0];
public CacheMethod(MethodInfo methodInfo, object declaringInstance) : base(methodInfo, declaringInstance) public CacheMethod(MethodInfo methodInfo, object declaringInstance, GameObject parent) : base(methodInfo, declaringInstance, parent)
{ {
GenericArgs = methodInfo.GetGenericArguments(); GenericArgs = methodInfo.GetGenericArguments();
@ -71,6 +71,9 @@ namespace UnityExplorer.Inspectors.Reflection
} }
catch (Exception e) catch (Exception e)
{ {
while (e.InnerException != null)
e = e.InnerException;
ExplorerCore.LogWarning($"Exception evaluating: {e.GetType()}, {e.Message}"); ExplorerCore.LogWarning($"Exception evaluating: {e.GetType()}, {e.Message}");
ReflectionException = ReflectionHelpers.ExceptionToString(e); ReflectionException = ReflectionHelpers.ExceptionToString(e);
} }

View File

@ -5,6 +5,7 @@ using System.Text;
using System.Reflection; using System.Reflection;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
using UnityEngine;
namespace UnityExplorer.Inspectors.Reflection namespace UnityExplorer.Inspectors.Reflection
{ {
@ -14,7 +15,7 @@ namespace UnityExplorer.Inspectors.Reflection
public override bool IsStatic => (MemInfo as PropertyInfo).GetAccessors(true)[0].IsStatic; public override bool IsStatic => (MemInfo as PropertyInfo).GetAccessors(true)[0].IsStatic;
public CacheProperty(PropertyInfo propertyInfo, object declaringInstance) : base(propertyInfo, declaringInstance) public CacheProperty(PropertyInfo propertyInfo, object declaringInstance, GameObject parent) : base(propertyInfo, declaringInstance, parent)
{ {
this.m_arguments = propertyInfo.GetIndexParameters(); this.m_arguments = propertyInfo.GetIndexParameters();
this.m_argumentInput = new string[m_arguments.Length]; this.m_argumentInput = new string[m_arguments.Length];
@ -62,6 +63,9 @@ namespace UnityExplorer.Inspectors.Reflection
var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance; var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance;
pi.SetValue(target, IValue.Value, ParseArguments()); pi.SetValue(target, IValue.Value, ParseArguments());
if (this.ParentInspector?.ParentMember != null)
this.ParentInspector.ParentMember.SetValue();
} }
} }
} }

View File

@ -4,6 +4,8 @@ using UnityEngine;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Unstrip;
using System.IO;
namespace UnityExplorer.Inspectors.Reflection namespace UnityExplorer.Inspectors.Reflection
{ {
@ -45,109 +47,267 @@ namespace UnityExplorer.Inspectors.Reflection
public void ConstructInstanceHelpers() public void ConstructInstanceHelpers()
{ {
if (!typeof(Component).IsAssignableFrom(m_targetType) && !typeof(UnityEngine.Object).IsAssignableFrom(m_targetType))
return;
var rowObj = UIFactory.CreateHorizontalGroup(Content, new Color(0.1f, 0.1f, 0.1f));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.childForceExpandWidth = true;
rowGroup.childControlWidth = true;
rowGroup.spacing = 5;
rowGroup.padding.top = 2;
rowGroup.padding.bottom = 2;
rowGroup.padding.right = 2;
rowGroup.padding.left = 2;
var rowLayout = rowObj.AddComponent<LayoutElement>();
rowLayout.minHeight = 25;
rowLayout.flexibleWidth = 5000;
if (typeof(Component).IsAssignableFrom(m_targetType))
{
ConstructCompHelper(rowObj);
}
ConstructUObjHelper(rowObj);
// WIP // WIP
//if (m_targetType == typeof(Texture2D)) if (m_targetType == typeof(Texture2D))
// ConstructTextureHelper(); ConstructTextureHelper();
// todo other helpers
//if (typeof(Component).IsAssignableFrom(m_targetType))
//{
//}
//else if (typeof(UnityEngine.Object).IsAssignableFrom(m_targetType))
//{
//}
} }
//internal bool showingTextureHelper; internal void ConstructCompHelper(GameObject rowObj)
//internal bool constructedTextureViewer; {
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 90;
labelLayout.minHeight = 25;
labelLayout.flexibleWidth = 0;
var labelText = labelObj.GetComponent<Text>();
labelText.text = "GameObject:";
//internal void ConstructTextureHelper() #if MONO
//{ var comp = Target as Component;
// var rowObj = UIFactory.CreateHorizontalGroup(Content, new Color(0.1f, 0.1f, 0.1f)); #else
// var rowLayout = rowObj.AddComponent<LayoutElement>(); var comp = (Target as Il2CppSystem.Object).TryCast<Component>();
// rowLayout.minHeight = 25; #endif
// 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 showBtnObj = UIFactory.CreateButton(rowObj, new Color(0.2f, 0.2f, 0.2f)); var goBtnObj = UIFactory.CreateButton(rowObj, new Color(0.2f, 0.5f, 0.2f));
// var showBtnLayout = showBtnObj.AddComponent<LayoutElement>(); var goBtnLayout = goBtnObj.AddComponent<LayoutElement>();
// showBtnLayout.minWidth = 50; goBtnLayout.minHeight = 25;
// showBtnLayout.flexibleWidth = 0; goBtnLayout.minWidth = 200;
// var showText = showBtnObj.GetComponentInChildren<Text>(); goBtnLayout.flexibleWidth = 0;
// showText.text = "Show"; var text = goBtnObj.GetComponentInChildren<Text>();
// var showBtn = showBtnObj.GetComponent<Button>(); text.text = comp.name;
var btn = goBtnObj.GetComponent<Button>();
btn.onClick.AddListener(() => { InspectorManager.Instance.Inspect(comp.gameObject); });
}
// var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft); internal void ConstructUObjHelper(GameObject rowObj)
// var labelText = labelObj.GetComponent<Text>(); {
// labelText.text = "Texture Viewer"; var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 60;
labelLayout.minHeight = 25;
labelLayout.flexibleWidth = 0;
var labelText = labelObj.GetComponent<Text>();
labelText.text = "Name:";
// var textureViewerObj = UIFactory.CreateScrollView(Content, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f)); #if MONO
// var viewerGroup = scrollContent.GetComponent<VerticalLayoutGroup>(); var uObj = Target as UnityEngine.Object;
// viewerGroup.childForceExpandHeight = false; #else
// viewerGroup.childForceExpandWidth = false; var uObj = (Target as Il2CppSystem.Object).TryCast<UnityEngine.Object>();
// viewerGroup.childControlHeight = true; #endif
// viewerGroup.childControlWidth = true;
// var mainLayout = textureViewerObj.GetComponent<LayoutElement>();
// mainLayout.flexibleHeight = -1;
// mainLayout.flexibleWidth = 2000;
// mainLayout.minHeight = 25;
// textureViewerObj.SetActive(false); var inputObj = UIFactory.CreateInputField(rowObj, 14, 3, 1);
var inputLayout = inputObj.AddComponent<LayoutElement>();
inputLayout.minHeight = 25;
inputLayout.flexibleWidth = 2000;
var inputField = inputObj.GetComponent<InputField>();
inputField.readOnly = true;
inputField.text = uObj.name;
// showBtn.onClick.AddListener(() => //var goBtnObj = UIFactory.CreateButton(rowObj, new Color(0.2f, 0.5f, 0.2f));
// { //var goBtnLayout = goBtnObj.AddComponent<LayoutElement>();
// showingTextureHelper = !showingTextureHelper; //goBtnLayout.minHeight = 25;
//goBtnLayout.minWidth = 200;
//goBtnLayout.flexibleWidth = 0;
//var text = goBtnObj.GetComponentInChildren<Text>();
//text.text = comp.name;
//var btn = goBtnObj.GetComponent<Button>();
//btn.onClick.AddListener(() => { InspectorManager.Instance.Inspect(comp.gameObject); });
}
// if (showingTextureHelper) internal bool showingTextureHelper;
// { internal bool constructedTextureViewer;
// if (!constructedTextureViewer)
// ConstructTextureViewerArea(scrollContent);
// showText.text = "Hide"; internal GameObject m_textureViewerObj;
// textureViewerObj.SetActive(true);
// }
// else
// {
// showText.text = "Show";
// textureViewerObj.SetActive(false);
// }
// });
//}
//internal void ConstructTextureViewerArea(GameObject parent) internal void ConstructTextureHelper()
//{ {
// constructedTextureViewer = true; 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 tex = Target as Texture2D; 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>();
// if (!tex) var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
// { var labelText = labelObj.GetComponent<Text>();
// ExplorerCore.LogWarning("Could not cast the target instance to Texture2D!"); labelText.text = "Texture Viewer";
// return;
// }
// var imageObj = UIFactory.CreateUIObject("TextureViewerImage", parent, new Vector2(1, 1)); var textureViewerObj = UIFactory.CreateScrollView(Content, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f));
// var image = imageObj.AddComponent<Image>(); var viewerGroup = scrollContent.GetComponent<VerticalLayoutGroup>();
// var sprite = UIManager.CreateSprite(tex); viewerGroup.childForceExpandHeight = false;
// image.sprite = sprite; viewerGroup.childForceExpandWidth = false;
viewerGroup.childControlHeight = true;
viewerGroup.childControlWidth = true;
var mainLayout = textureViewerObj.GetComponent<LayoutElement>();
mainLayout.flexibleHeight = 9999;
mainLayout.flexibleWidth = 9999;
mainLayout.minHeight = 100;
// var fitter = imageObj.AddComponent<ContentSizeFitter>(); textureViewerObj.SetActive(false);
// fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// //fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
// var imageLayout = imageObj.AddComponent<LayoutElement>(); m_textureViewerObj = textureViewerObj;
// imageLayout.preferredHeight = sprite.rect.height;
// imageLayout.preferredWidth = sprite.rect.width; showBtn.onClick.AddListener(() =>
//} {
showingTextureHelper = !showingTextureHelper;
if (showingTextureHelper)
{
if (!constructedTextureViewer)
ConstructTextureViewerArea(scrollContent);
showText.text = "Hide";
ToggleTextureViewer(true);
}
else
{
showText.text = "Show";
ToggleTextureViewer(false);
}
});
}
internal void ConstructTextureViewerArea(GameObject parent)
{
constructedTextureViewer = true;
var tex = Target as Texture2D;
#if CPP
if (!tex)
tex = (Target as Il2CppSystem.Object).TryCast<Texture2D>();
#endif
if (!tex)
{
ExplorerCore.LogWarning("Could not cast the target instance to Texture2D! Maybe its null or destroyed?");
return;
}
// 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) public void ConstructInstanceFilters(GameObject parent)
{ {

View File

@ -10,6 +10,9 @@ using UnityExplorer.Helpers;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Shared; using UnityExplorer.UI.Shared;
using System.Reflection; using System.Reflection;
#if CPP
using CppDictionary = Il2CppSystem.Collections.IDictionary;
#endif
namespace UnityExplorer.Inspectors.Reflection namespace UnityExplorer.Inspectors.Reflection
{ {
@ -44,7 +47,11 @@ namespace UnityExplorer.Inspectors.Reflection
} }
internal IDictionary RefIDictionary; internal IDictionary RefIDictionary;
#if CPP
internal CppDictionary RefCppDictionary;
#else
internal IDictionary RefCppDictionary = null;
#endif
internal Type m_typeOfKeys; internal Type m_typeOfKeys;
internal Type m_typeofValues; internal Type m_typeofValues;
@ -65,6 +72,11 @@ namespace UnityExplorer.Inspectors.Reflection
{ {
RefIDictionary = Value as IDictionary; RefIDictionary = Value as IDictionary;
#if CPP
try { RefCppDictionary = (Value as Il2CppSystem.Object).TryCast<CppDictionary>(); }
catch { }
#endif
if (m_subContentParent.activeSelf) if (m_subContentParent.activeSelf)
{ {
GetCacheEntries(); GetCacheEntries();
@ -129,13 +141,6 @@ namespace UnityExplorer.Inspectors.Reflection
{ {
var value = RefIDictionary[key]; 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); var cacheKey = new CachePaired(index, this, this.RefIDictionary, PairTypes.Key, m_listContent);
cacheKey.CreateIValue(key, this.m_typeOfKeys); cacheKey.CreateIValue(key, this.m_typeOfKeys);
cacheKey.Disable(); cacheKey.Disable();
@ -206,9 +211,10 @@ namespace UnityExplorer.Inspectors.Reflection
RefreshDisplay(); RefreshDisplay();
} }
#region CPP fixes #region CPP fixes
#if CPP #if CPP
// temp fix for Il2Cpp IDictionary until interfaces are fixed // temp fix for Il2Cpp IDictionary until interfaces are fixed
private IDictionary EnumerateWithReflection() private IDictionary EnumerateWithReflection()
{ {
var valueType = Value?.GetType() ?? FallbackType; var valueType = Value?.GetType() ?? FallbackType;
@ -222,8 +228,8 @@ namespace UnityExplorer.Inspectors.Reflection
var valueList = new List<object>(); var valueList = new List<object>();
// store entries with reflection // store entries with reflection
EnumerateWithReflection(keys, keyList); EnumerateCollection(keys, keyList);
EnumerateWithReflection(values, valueList); EnumerateCollection(values, valueList);
// make actual mono dictionary // make actual mono dictionary
var dict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>) var dict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>)
@ -236,7 +242,7 @@ namespace UnityExplorer.Inspectors.Reflection
return dict; return dict;
} }
private void EnumerateWithReflection(object collection, List<object> list) private void EnumerateCollection(object collection, List<object> list)
{ {
// invoke GetEnumerator // invoke GetEnumerator
var enumerator = collection.GetType().GetMethod("GetEnumerator").Invoke(collection, null); var enumerator = collection.GetType().GetMethod("GetEnumerator").Invoke(collection, null);
@ -253,9 +259,9 @@ namespace UnityExplorer.Inspectors.Reflection
} }
#endif #endif
#endregion #endregion
#region UI CONSTRUCTION #region UI CONSTRUCTION
internal GameObject m_listContent; internal GameObject m_listContent;
internal LayoutElement m_listLayout; internal LayoutElement m_listLayout;
@ -309,6 +315,6 @@ namespace UnityExplorer.Inspectors.Reflection
// m_rowHolders.Add(obj); // m_rowHolders.Add(obj);
//} //}
#endregion #endregion
} }
} }

View File

@ -37,14 +37,7 @@ namespace UnityExplorer.Inspectors.Reflection
if (m_subContentConstructed) if (m_subContentConstructed)
{ {
// changing types, destroy subcontent DestroySubContent();
for (int i = 0; i < m_subContentParent.transform.childCount; i++)
{
var child = m_subContentParent.transform.GetChild(i);
GameObject.Destroy(child.gameObject);
}
m_subContentConstructed = false;
} }
if (!s_enumNamesCache.ContainsKey(type)) if (!s_enumNamesCache.ContainsKey(type))
@ -96,7 +89,10 @@ namespace UnityExplorer.Inspectors.Reflection
private void SetValueFromDropdown() private void SetValueFromDropdown()
{ {
var type = Value?.GetType() ?? FallbackType; var type = Value?.GetType() ?? FallbackType;
var value = Enum.Parse(type, m_dropdownText.text); var index = m_dropdown.value;
var value = Enum.Parse(type, s_enumNamesCache[type][index].Value);
if (value != null) if (value != null)
{ {
Value = value; Value = value;

View File

@ -37,6 +37,11 @@ namespace UnityExplorer.Inspectors.Reflection
internal IEnumerable RefIEnumerable; internal IEnumerable RefIEnumerable;
internal IList RefIList; internal IList RefIList;
#if CPP
internal Il2CppSystem.Collections.ICollection CppICollection;
#else
internal ICollection CppICollection = null;
#endif
internal readonly Type m_baseEntryType; internal readonly Type m_baseEntryType;
@ -49,6 +54,14 @@ namespace UnityExplorer.Inspectors.Reflection
RefIEnumerable = Value as IEnumerable; RefIEnumerable = Value as IEnumerable;
RefIList = Value as IList; 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) if (m_subContentParent.activeSelf)
{ {
GetCacheEntries(); GetCacheEntries();
@ -77,8 +90,8 @@ namespace UnityExplorer.Inspectors.Reflection
if (Value != null) if (Value != null)
{ {
string count = "?"; string count = "?";
if (m_recacheWanted && RefIList != null) if (m_recacheWanted && (RefIList != null || CppICollection != null))
count = RefIList.Count.ToString(); count = RefIList?.Count.ToString() ?? CppICollection.Count.ToString();
else if (!m_recacheWanted) else if (!m_recacheWanted)
count = m_entries.Count.ToString(); count = m_entries.Count.ToString();
@ -169,89 +182,62 @@ namespace UnityExplorer.Inspectors.Reflection
RefreshDisplay(); RefreshDisplay();
} }
#region CPP Helpers #region CPP Helpers
#if CPP #if CPP
// some temp fixes for Il2Cpp IEnumerables until interfaces are fixed // 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() private IEnumerable EnumerateWithReflection()
{ {
if (Value.IsNullOrDestroyed()) if (Value == null)
return null; return null;
var genericDef = Value.GetType().GetGenericTypeDefinition(); // new test
var CppEnumerable = (Value as Il2CppSystem.Object)?.TryCast<Il2CppSystem.Collections.IEnumerable>();
if (genericDef == typeof(Il2CppSystem.Collections.Generic.List<>)) if (CppEnumerable != null)
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
{ {
var genericType = typeof(List<>).MakeGenericType(new Type[] { this.m_baseEntryType }); var type = Value.GetType();
var list = (IList)Activator.CreateInstance(genericType); 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() current = enumeratorType.GetProperty("Current"),
.GetProperty("Item") moveNext = enumeratorType.GetMethod("MoveNext"),
.GetValue(Value, new object[] { i }); });
list.Add(itm);
}
catch { break; }
} }
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; return list;
} }
catch (Exception e)
{ return null;
ExplorerCore.Log("Exception converting Il2Cpp IList to Mono IList: " + e.GetType() + ", " + e.Message);
return null;
}
} }
#endif #endif
#endregion #endregion
#region UI CONSTRUCTION #region UI CONSTRUCTION
internal GameObject m_listContent; internal GameObject m_listContent;
internal LayoutElement m_listLayout; internal LayoutElement m_listLayout;
@ -296,6 +282,6 @@ namespace UnityExplorer.Inspectors.Reflection
contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
} }
#endregion #endregion
} }
} }

View File

@ -14,8 +14,9 @@ namespace UnityExplorer.Inspectors.Reflection
{ {
public InteractiveString(object value, Type valueType) : base(value, valueType) { } public InteractiveString(object value, Type valueType) : base(value, valueType) { }
public override bool HasSubContent => false; public override bool HasSubContent => true;
public override bool SubContentWanted => false; public override bool SubContentWanted => true;
public override bool WantInspectBtn => false; public override bool WantInspectBtn => false;
public override void OnValueUpdated() public override void OnValueUpdated()
@ -27,10 +28,9 @@ namespace UnityExplorer.Inspectors.Reflection
{ {
base.OnException(member); base.OnException(member);
if (m_hiddenObj.gameObject.activeSelf) if (m_subContentConstructed && m_hiddenObj.gameObject.activeSelf)
m_hiddenObj.gameObject.SetActive(false); m_hiddenObj.gameObject.SetActive(false);
// m_baseLabel.text = DefaultLabel;
m_labelLayout.minWidth = 200; m_labelLayout.minWidth = 200;
m_labelLayout.flexibleWidth = 5000; m_labelLayout.flexibleWidth = 5000;
} }
@ -45,39 +45,62 @@ namespace UnityExplorer.Inspectors.Reflection
return; return;
} }
if (!m_hiddenObj.gameObject.activeSelf)
m_hiddenObj.gameObject.SetActive(true);
m_baseLabel.text = m_richValueType; m_baseLabel.text = m_richValueType;
if (Value != null) if (m_subContentConstructed)
{ {
var toString = Value.ToString(); if (!m_hiddenObj.gameObject.activeSelf)
m_hiddenObj.gameObject.SetActive(true);
}
if (!string.IsNullOrEmpty((string)Value))
{
var toString = (string)Value;
if (toString.Length > 15000) if (toString.Length > 15000)
toString = toString.Substring(0, 15000); toString = toString.Substring(0, 15000);
m_valueInput.text = toString; m_readonlyInput.text = toString;
m_placeholderText.text = toString;
if (m_subContentConstructed)
{
m_valueInput.text = toString;
m_placeholderText.text = toString;
}
} }
else else
{ {
m_valueInput.text = ""; string s = Value == null
m_placeholderText.text = "null"; ? "null"
: "empty";
m_readonlyInput.text = $"<i><color=grey>{s}</color></i>";
if (m_subContentConstructed)
{
m_valueInput.text = "";
m_placeholderText.text = s;
}
} }
m_labelLayout.minWidth = 50; m_labelLayout.minWidth = 50;
m_labelLayout.flexibleWidth = 0; m_labelLayout.flexibleWidth = 0;
} }
internal void OnApplyClicked() internal void OnApplyClicked()
{ {
Value = m_valueInput.text; Value = m_valueInput.text;
Owner.SetValue(); Owner.SetValue();
RefreshUIForValue();
} }
internal InputField m_valueInput; // for the default label
internal LayoutElement m_labelLayout; internal LayoutElement m_labelLayout;
//internal InputField m_readonlyInput;
internal Text m_readonlyInput;
// for input
internal InputField m_valueInput;
internal GameObject m_hiddenObj; internal GameObject m_hiddenObj;
internal Text m_placeholderText; internal Text m_placeholderText;
@ -90,12 +113,38 @@ namespace UnityExplorer.Inspectors.Reflection
m_labelLayout = m_baseLabel.gameObject.GetComponent<LayoutElement>(); m_labelLayout = m_baseLabel.gameObject.GetComponent<LayoutElement>();
m_hiddenObj = UIFactory.CreateLabel(m_valueContent, TextAnchor.MiddleLeft); var readonlyInputObj = UIFactory.CreateLabel(m_valueContent, TextAnchor.MiddleLeft);
m_readonlyInput = readonlyInputObj.GetComponent<Text>();
m_readonlyInput.horizontalOverflow = HorizontalWrapMode.Overflow;
var testFitter = readonlyInputObj.AddComponent<ContentSizeFitter>();
testFitter.verticalFit = ContentSizeFitter.FitMode.MinSize;
var labelLayout = readonlyInputObj.AddComponent<LayoutElement>();
labelLayout.minHeight = 25;
labelLayout.preferredHeight = 25;
labelLayout.flexibleHeight = 0;
}
public override void ConstructSubcontent()
{
base.ConstructSubcontent();
var groupObj = UIFactory.CreateVerticalGroup(m_subContentParent, new Color(1, 1, 1, 0));
var group = groupObj.GetComponent<VerticalLayoutGroup>();
group.spacing = 4;
group.padding.top = 3;
group.padding.left = 3;
group.padding.right = 3;
group.padding.bottom = 3;
m_hiddenObj = UIFactory.CreateLabel(groupObj, TextAnchor.MiddleLeft);
m_hiddenObj.SetActive(false); m_hiddenObj.SetActive(false);
var hiddenText = m_hiddenObj.GetComponent<Text>(); var hiddenText = m_hiddenObj.GetComponent<Text>();
hiddenText.color = Color.clear; hiddenText.color = Color.clear;
hiddenText.fontSize = 14; hiddenText.fontSize = 14;
hiddenText.raycastTarget = false; hiddenText.raycastTarget = false;
hiddenText.supportRichText = false;
var hiddenFitter = m_hiddenObj.AddComponent<ContentSizeFitter>(); var hiddenFitter = m_hiddenObj.AddComponent<ContentSizeFitter>();
hiddenFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; hiddenFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var hiddenLayout = m_hiddenObj.AddComponent<LayoutElement>(); var hiddenLayout = m_hiddenObj.AddComponent<LayoutElement>();
@ -121,19 +170,23 @@ namespace UnityExplorer.Inspectors.Reflection
m_placeholderText = m_valueInput.placeholder.GetComponent<Text>(); m_placeholderText = m_valueInput.placeholder.GetComponent<Text>();
m_valueInput.onValueChanged.AddListener((string val) => m_placeholderText.supportRichText = false;
m_valueInput.textComponent.supportRichText = false;
m_valueInput.onValueChanged.AddListener((string val) =>
{ {
hiddenText.text = val; hiddenText.text = val ?? "";
LayoutRebuilder.ForceRebuildLayoutImmediate(Owner.m_mainRect); LayoutRebuilder.ForceRebuildLayoutImmediate(Owner.m_mainRect);
}); });
if (Owner.CanWrite) if (Owner.CanWrite)
{ {
var applyBtnObj = UIFactory.CreateButton(m_valueContent, new Color(0.2f, 0.2f, 0.2f)); var applyBtnObj = UIFactory.CreateButton(groupObj, new Color(0.2f, 0.2f, 0.2f));
var applyLayout = applyBtnObj.AddComponent<LayoutElement>(); var applyLayout = applyBtnObj.AddComponent<LayoutElement>();
applyLayout.minWidth = 50; applyLayout.minWidth = 50;
applyLayout.minHeight = 25; applyLayout.minHeight = 25;
applyLayout.flexibleWidth = 0; applyLayout.flexibleWidth = 0;
var applyBtn = applyBtnObj.GetComponent<Button>(); var applyBtn = applyBtnObj.GetComponent<Button>();
applyBtn.onClick.AddListener(OnApplyClicked); applyBtn.onClick.AddListener(OnApplyClicked);
@ -144,6 +197,8 @@ namespace UnityExplorer.Inspectors.Reflection
{ {
m_valueInput.readOnly = true; m_valueInput.readOnly = true;
} }
RefreshUIForValue();
} }
} }
} }

View File

@ -226,14 +226,15 @@ namespace UnityExplorer.Inspectors.Reflection
if (StructInfo != null) if (StructInfo != null)
{ {
// changing types, destroy subcontent DestroySubContent();
for (int i = 0; i < m_subContentParent.transform.childCount; i++) //// changing types, destroy subcontent
{ //for (int i = 0; i < m_subContentParent.transform.childCount; i++)
var child = m_subContentParent.transform.GetChild(i); //{
GameObject.Destroy(child.gameObject); // var child = m_subContentParent.transform.GetChild(i);
} // GameObject.Destroy(child.gameObject);
//}
m_UIConstructed = false; //m_UIConstructed = false;
} }
m_lastStructType = type; m_lastStructType = type;

View File

@ -78,7 +78,13 @@ namespace UnityExplorer.Inspectors.Reflection
m_valueContent.SetActive(false); m_valueContent.SetActive(false);
GameObject.Destroy(this.m_valueContent.gameObject); GameObject.Destroy(this.m_valueContent.gameObject);
} }
if (this.m_subContentParent && SubContentWanted)
DestroySubContent();
}
public virtual void DestroySubContent()
{
if (this.m_subContentParent && HasSubContent)
{ {
for (int i = 0; i < this.m_subContentParent.transform.childCount; i++) for (int i = 0; i < this.m_subContentParent.transform.childCount; i++)
{ {
@ -87,6 +93,8 @@ namespace UnityExplorer.Inspectors.Reflection
GameObject.Destroy(child.gameObject); GameObject.Destroy(child.gameObject);
} }
} }
m_subContentConstructed = false;
} }
public virtual void OnValueUpdated() public virtual void OnValueUpdated()
@ -95,18 +103,16 @@ namespace UnityExplorer.Inspectors.Reflection
ConstructUI(m_mainContentParent, m_subContentParent); ConstructUI(m_mainContentParent, m_subContentParent);
if (Owner is CacheMember ownerMember && !string.IsNullOrEmpty(ownerMember.ReflectionException)) if (Owner is CacheMember ownerMember && !string.IsNullOrEmpty(ownerMember.ReflectionException))
{
OnException(ownerMember); OnException(ownerMember);
}
else else
{
RefreshUIForValue(); RefreshUIForValue();
}
} }
public virtual void OnException(CacheMember member) public virtual void OnException(CacheMember member)
{ {
m_baseLabel.text = "<color=red>" + member.ReflectionException + "</color>"; if (m_UIConstructed)
m_baseLabel.text = "<color=red>" + member.ReflectionException + "</color>";
Value = null; Value = null;
} }
@ -170,6 +176,10 @@ namespace UnityExplorer.Inspectors.Reflection
ConstructSubcontent(); ConstructSubcontent();
} }
internal MethodInfo m_toStringMethod;
internal MethodInfo m_toStringFormatMethod;
internal bool m_gotToStringMethods;
public string GetDefaultLabel(bool updateType = true) public string GetDefaultLabel(bool updateType = true)
{ {
var valueType = Value?.GetType() ?? this.FallbackType; var valueType = Value?.GetType() ?? this.FallbackType;
@ -199,8 +209,29 @@ namespace UnityExplorer.Inspectors.Reflection
} }
else else
{ {
var toString = (string)valueType.GetMethod("ToString", new Type[0])?.Invoke(Value, null) if (!m_gotToStringMethods)
?? Value.ToString(); {
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(); var fullnametemp = valueType.ToString();
if (fullnametemp.StartsWith("Il2CppSystem")) if (fullnametemp.StartsWith("Il2CppSystem"))
@ -297,7 +328,7 @@ namespace UnityExplorer.Inspectors.Reflection
void OnInspectClicked() void OnInspectClicked()
{ {
if (!Value.IsNullOrDestroyed(false)) if (!Value.IsNullOrDestroyed(false))
InspectorManager.Instance.Inspect(this.Value); InspectorManager.Instance.Inspect(this.Value, this.Owner);
} }
m_inspectButton.SetActive(false); m_inspectButton.SetActive(false);

View File

@ -34,7 +34,7 @@ namespace UnityExplorer.Inspectors
} }
// Blacklists // Blacklists
private static readonly HashSet<string> s_typeAndMemberBlacklist = new HashSet<string> private static readonly HashSet<string> bl_typeAndMember = new HashSet<string>
{ {
#if CPP #if CPP
// these cause a crash in IL2CPP // these cause a crash in IL2CPP
@ -45,19 +45,21 @@ namespace UnityExplorer.Inspectors
"Texture2D.SetPixelDataImpl", "Texture2D.SetPixelDataImpl",
#endif #endif
}; };
private static readonly HashSet<string> s_methodStartsWithBlacklist = new HashSet<string> private static readonly HashSet<string> bl_memberNameStartsWith = new HashSet<string>
{ {
// these are redundant // these are redundant
"get_", "get_",
"set_", "set_",
}; };
#endregion #endregion
#region INSTANCE #region INSTANCE
public override string TabLabel => m_targetTypeShortName; public override string TabLabel => m_targetTypeShortName;
internal CacheObjectBase ParentMember { get; set; }
internal readonly Type m_targetType; internal readonly Type m_targetType;
internal readonly string m_targetTypeShortName; internal readonly string m_targetTypeShortName;
@ -132,24 +134,101 @@ namespace UnityExplorer.Inspectors
RefreshDisplay(); RefreshDisplay();
} }
private void OnMemberFilterClicked(MemberTypes type, Button button) internal bool IsBlacklisted(string sig) => bl_typeAndMember.Any(it => sig.Contains(it));
internal bool IsBlacklisted(MethodInfo method) => bl_memberNameStartsWith.Any(it => method.Name.StartsWith(it));
internal string GetSig(MemberInfo member) => $"{member.DeclaringType.Name}.{member.Name}";
internal string AppendArgsToSig(ParameterInfo[] args)
{ {
if (m_lastActiveMemButton) string ret = " (";
foreach (var param in args)
ret += $"{param.ParameterType.Name} {param.Name}, ";
ret += ")";
return ret;
}
public void CacheMembers(Type type)
{
var list = new List<CacheMember>();
var cachedSigs = new HashSet<string>();
var types = ReflectionHelpers.GetAllBaseTypes(type);
var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;
if (this is InstanceInspector)
flags |= BindingFlags.Instance;
foreach (var declaringType in types)
{ {
var lastColors = m_lastActiveMemButton.colors; var target = Target;
lastColors.normalColor = new Color(0.2f, 0.2f, 0.2f); #if CPP
m_lastActiveMemButton.colors = lastColors; target = target.Il2CppCast(declaringType);
#endif
IEnumerable<MemberInfo> infos = declaringType.GetMethods(flags);
infos = infos.Concat(declaringType.GetProperties(flags));
infos = infos.Concat(declaringType.GetFields(flags));
foreach (var member in infos)
{
try
{
//ExplorerCore.Log($"Trying to cache member {sig}...");
//ExplorerCore.Log(member.DeclaringType.FullName + "." + member.Name);
var sig = GetSig(member);
var mi = member as MethodInfo;
var pi = member as PropertyInfo;
var fi = member as FieldInfo;
if (IsBlacklisted(sig) || (mi != null && IsBlacklisted(mi)))
continue;
var args = mi?.GetParameters() ?? pi?.GetIndexParameters();
if (args != null)
{
if (!CacheMember.CanProcessArgs(args))
continue;
sig += AppendArgsToSig(args);
}
if (cachedSigs.Contains(sig))
continue;
cachedSigs.Add(sig);
if (mi != null)
list.Add(new CacheMethod(mi, target, m_scrollContent));
else if (pi != null)
list.Add(new CacheProperty(pi, target, m_scrollContent));
else
list.Add(new CacheField(fi, target, m_scrollContent));
list.Last().ParentInspector = this;
}
catch (Exception e)
{
ExplorerCore.LogWarning($"Exception caching member {member.DeclaringType.FullName}.{member.Name}!");
ExplorerCore.Log(e.ToString());
}
}
} }
m_memberFilter = type; var typeList = types.ToList();
m_lastActiveMemButton = button;
var colors = m_lastActiveMemButton.colors; var sorted = new List<CacheMember>();
colors.normalColor = new Color(0.2f, 0.6f, 0.2f); sorted.AddRange(list.Where(it => it is CacheMethod)
m_lastActiveMemButton.colors = colors; .OrderBy(it => typeList.IndexOf(it.DeclaringType))
.ThenBy(it => it.NameForFiltering));
sorted.AddRange(list.Where(it => it is CacheProperty)
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
.ThenBy(it => it.NameForFiltering));
sorted.AddRange(list.Where(it => it is CacheField)
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
.ThenBy(it => it.NameForFiltering));
FilterMembers(null, true); m_allMembers = sorted.ToArray();
m_sliderScroller.m_slider.value = 1f;
} }
public override void Update() public override void Update()
@ -178,6 +257,26 @@ namespace UnityExplorer.Inspectors
} }
} }
private void OnMemberFilterClicked(MemberTypes type, Button button)
{
if (m_lastActiveMemButton)
{
var lastColors = m_lastActiveMemButton.colors;
lastColors.normalColor = new Color(0.2f, 0.2f, 0.2f);
m_lastActiveMemButton.colors = lastColors;
}
m_memberFilter = type;
m_lastActiveMemButton = button;
var colors = m_lastActiveMemButton.colors;
colors.normalColor = new Color(0.2f, 0.6f, 0.2f);
m_lastActiveMemButton.colors = colors;
FilterMembers(null, true);
m_sliderScroller.m_slider.value = 1f;
}
public void FilterMembers(string nameFilter = null, bool force = false) public void FilterMembers(string nameFilter = null, bool force = false)
{ {
int lastCount = m_membersFiltered.Count; int lastCount = m_membersFiltered.Count;
@ -200,7 +299,7 @@ namespace UnityExplorer.Inspectors
} }
// name filter // name filter
if (!string.IsNullOrEmpty(nameFilter) && !mem.NameForFiltering.Contains(nameFilter)) if (!string.IsNullOrEmpty(nameFilter) && !mem.NameForFiltering.Contains(nameFilter))
continue; continue;
m_membersFiltered.Add(mem); m_membersFiltered.Add(mem);
@ -266,139 +365,12 @@ namespace UnityExplorer.Inspectors
} }
} }
public void CacheMembers(Type type)
{
var list = new List<CacheMember>();
var cachedSigs = new HashSet<string>();
var types = ReflectionHelpers.GetAllBaseTypes(type);
foreach (var declaringType in types)
{
MemberInfo[] infos;
try
{
infos = declaringType.GetMembers(ReflectionHelpers.CommonFlags);
}
catch
{
ExplorerCore.Log($"Exception getting members for type: {declaringType.FullName}");
continue;
}
var target = Target;
#if CPP
try
{
target = target.Il2CppCast(declaringType);
}
catch //(Exception e)
{
//ExplorerCore.LogWarning("Excepting casting " + target.GetType().FullName + " to " + declaringType.FullName);
}
#endif
foreach (var member in infos)
{
try
{
// make sure member type is Field, Method or Property (4 / 8 / 16)
int m = (int)member.MemberType;
if (m < 4 || m > 16)
continue;
//ExplorerCore.Log($"Trying to cache member {sig}...");
//ExplorerCore.Log(member.DeclaringType.FullName + "." + member.Name);
var pi = member as PropertyInfo;
var mi = member as MethodInfo;
if (this is StaticInspector)
{
if (member is FieldInfo fi && !fi.IsStatic) continue;
else if (pi != null && !pi.GetAccessors(true)[0].IsStatic) continue;
else if (mi != null && !mi.IsStatic) continue;
}
// check blacklisted members
var sig = $"{member.DeclaringType.Name}.{member.Name}";
if (s_typeAndMemberBlacklist.Any(it => sig.Contains(it)))
continue;
if (s_methodStartsWithBlacklist.Any(it => member.Name.StartsWith(it)))
continue;
if (mi != null)
AppendParams(mi.GetParameters());
else if (pi != null)
AppendParams(pi.GetIndexParameters());
void AppendParams(ParameterInfo[] _args)
{
sig += " (";
foreach (var param in _args)
sig += $"{param.ParameterType.Name} {param.Name}, ";
sig += ")";
}
if (cachedSigs.Contains(sig))
continue;
try
{
CacheMember cached;
if (mi != null && CacheMember.CanProcessArgs(mi.GetParameters()))
cached = new CacheMethod(mi, target);
else if (pi != null && CacheMember.CanProcessArgs(pi.GetIndexParameters()))
cached = new CacheProperty(pi, target);
else if (member is FieldInfo fi)
cached = new CacheField(fi, target);
else
continue;
cached.m_parentContent = m_scrollContent;
if (cached != null)
{
cachedSigs.Add(sig);
list.Add(cached);
}
}
catch (Exception e)
{
ExplorerCore.LogWarning($"Exception caching member {sig}!");
ExplorerCore.Log(e.ToString());
}
}
catch (Exception e)
{
ExplorerCore.LogWarning($"Exception caching member {member.DeclaringType.FullName}.{member.Name}!");
ExplorerCore.Log(e.ToString());
}
}
}
var typeList = types.ToList();
var sorted = new List<CacheMember>();
sorted.AddRange(list.Where(it => it is CacheMethod)
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
.ThenBy(it => it.NameForFiltering));
sorted.AddRange(list.Where(it => it is CacheProperty)
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
.ThenBy(it => it.NameForFiltering));
sorted.AddRange(list.Where(it => it is CacheField)
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
.ThenBy(it => it.NameForFiltering));
m_allMembers = sorted.ToArray();
// ExplorerCore.Log("Cached " + m_allMembers.Length + " members");
}
#region UI CONSTRUCTION #region UI CONSTRUCTION
internal GameObject m_filterAreaObj;
internal GameObject m_updateRowObj;
internal GameObject m_memberListObj;
internal void ConstructUI() internal void ConstructUI()
{ {
var parent = InspectorManager.Instance.m_inspectorContent; var parent = InspectorManager.Instance.m_inspectorContent;
@ -459,7 +431,7 @@ namespace UnityExplorer.Inspectors
ConstructFilterArea(); ConstructFilterArea();
ConstructOptionsArea(); ConstructUpdateRow();
} }
internal void ConstructFilterArea() internal void ConstructFilterArea()
@ -480,6 +452,8 @@ namespace UnityExplorer.Inspectors
filterGroup.padding.top = 4; filterGroup.padding.top = 4;
filterGroup.padding.bottom = 4; filterGroup.padding.bottom = 4;
m_filterAreaObj = filterAreaObj;
// name filter // name filter
var nameFilterRowObj = UIFactory.CreateHorizontalGroup(filterAreaObj, new Color(1, 1, 1, 0)); var nameFilterRowObj = UIFactory.CreateHorizontalGroup(filterAreaObj, new Color(1, 1, 1, 0));
@ -576,9 +550,9 @@ namespace UnityExplorer.Inspectors
btn.colors = colors; btn.colors = colors;
} }
internal void ConstructOptionsArea() internal void ConstructUpdateRow()
{ {
var optionsRowObj = UIFactory.CreateHorizontalGroup(Content, new Color(1,1,1,0)); var optionsRowObj = UIFactory.CreateHorizontalGroup(Content, new Color(1, 1, 1, 0));
var optionsLayout = optionsRowObj.AddComponent<LayoutElement>(); var optionsLayout = optionsRowObj.AddComponent<LayoutElement>();
optionsLayout.minHeight = 25; optionsLayout.minHeight = 25;
var optionsGroup = optionsRowObj.GetComponent<HorizontalLayoutGroup>(); var optionsGroup = optionsRowObj.GetComponent<HorizontalLayoutGroup>();
@ -587,6 +561,8 @@ namespace UnityExplorer.Inspectors
optionsGroup.childAlignment = TextAnchor.MiddleLeft; optionsGroup.childAlignment = TextAnchor.MiddleLeft;
optionsGroup.spacing = 10; optionsGroup.spacing = 10;
m_updateRowObj = optionsRowObj;
// update button // update button
var updateButtonObj = UIFactory.CreateButton(optionsRowObj, new Color(0.2f, 0.2f, 0.2f)); var updateButtonObj = UIFactory.CreateButton(optionsRowObj, new Color(0.2f, 0.2f, 0.2f));
@ -596,7 +572,7 @@ namespace UnityExplorer.Inspectors
var updateText = updateButtonObj.GetComponentInChildren<Text>(); var updateText = updateButtonObj.GetComponentInChildren<Text>();
updateText.text = "Update Values"; updateText.text = "Update Values";
var updateBtn = updateButtonObj.GetComponent<Button>(); var updateBtn = updateButtonObj.GetComponent<Button>();
updateBtn.onClick.AddListener(() => updateBtn.onClick.AddListener(() =>
{ {
bool orig = m_autoUpdate; bool orig = m_autoUpdate;
m_autoUpdate = true; m_autoUpdate = true;
@ -614,11 +590,12 @@ namespace UnityExplorer.Inspectors
autoUpdateToggle.isOn = false; autoUpdateToggle.isOn = false;
autoUpdateToggle.onValueChanged.AddListener((bool val) => { m_autoUpdate = val; }); autoUpdateToggle.onValueChanged.AddListener((bool val) => { m_autoUpdate = val; });
} }
internal void ConstructMemberList() internal void ConstructMemberList()
{ {
var scrollobj = UIFactory.CreateScrollView(Content, out m_scrollContent, out m_sliderScroller, new Color(0.08f, 0.08f, 0.08f)); 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>(); m_scrollContentRect = m_scrollContent.GetComponent<RectTransform>();
var scrollGroup = m_scrollContent.GetComponent<VerticalLayoutGroup>(); var scrollGroup = m_scrollContent.GetComponent<VerticalLayoutGroup>();

View File

@ -55,16 +55,15 @@ namespace UnityExplorer.Inspectors
{ {
get get
{ {
if (!m_dontDestroyObject) if (!s_dontDestroyObject)
{ {
m_dontDestroyObject = new GameObject("DontDestroyMe"); s_dontDestroyObject = new GameObject("DontDestroyMe");
GameObject.DontDestroyOnLoad(m_dontDestroyObject); GameObject.DontDestroyOnLoad(s_dontDestroyObject);
} }
return m_dontDestroyObject; return s_dontDestroyObject;
} }
} }
internal static GameObject s_dontDestroyObject;
internal static GameObject m_dontDestroyObject;
public void Init() public void Init()
{ {
@ -97,22 +96,6 @@ namespace UnityExplorer.Inspectors
} }
} }
//#if CPP
// public int GetSceneHandle(string sceneName)
// {
// if (sceneName == "DontDestroyOnLoad")
// return DontDestroyScene;
// for (int i = 0; i < SceneManager.sceneCount; i++)
// {
// var scene = SceneManager.GetSceneAt(i);
// if (scene.name == sceneName)
// return scene.handle;
// }
// return -1;
// }
//#endif
internal void OnSceneChange() internal void OnSceneChange()
{ {
m_sceneDropdown.OnCancel(null); m_sceneDropdown.OnCancel(null);
@ -121,8 +104,13 @@ namespace UnityExplorer.Inspectors
private void RefreshSceneSelector() private void RefreshSceneSelector()
{ {
var names = new List<string>(); var newNames = new List<string>();
var scenes = new List<Scene>(); var newScenes = new List<Scene>();
if (m_currentScenes == null)
m_currentScenes = new Scene[0];
bool anyChange = SceneManager.sceneCount != m_currentScenes.Length - 1;
for (int i = 0; i < SceneManager.sceneCount; i++) for (int i = 0; i < SceneManager.sceneCount; i++)
{ {
@ -131,33 +119,32 @@ namespace UnityExplorer.Inspectors
if (scene == default) if (scene == default)
continue; continue;
scenes.Add(scene); if (!anyChange && !m_currentScenes.Any(it => it.GetHandle() == scene.GetHandle()))
names.Add(scene.name); anyChange = true;
newScenes.Add(scene);
newNames.Add(scene.name);
} }
names.Add("DontDestroyOnLoad"); newNames.Add("DontDestroyOnLoad");
scenes.Add(DontDestroyScene); newScenes.Add(DontDestroyScene);
m_sceneDropdown.options.Clear(); m_sceneDropdown.options.Clear();
foreach (string scene in names) foreach (string scene in newNames)
{ {
m_sceneDropdown.options.Add(new Dropdown.OptionData { text = scene }); m_sceneDropdown.options.Add(new Dropdown.OptionData { text = scene });
} }
if (!names.Contains(m_sceneDropdownText.text)) if (anyChange)
{ {
m_sceneDropdownText.text = names[0]; m_sceneDropdownText.text = newNames[0];
SetTargetScene(scenes[0]); SetTargetScene(newScenes[0]);
} }
m_currentScenes = scenes.ToArray(); m_currentScenes = newScenes.ToArray();
} }
//#if CPP
// public void SetTargetScene(string name) => SetTargetScene(scene.handle);
//#endif
public void SetTargetScene(Scene scene) public void SetTargetScene(Scene scene)
{ {
if (scene == default) if (scene == default)
@ -167,7 +154,7 @@ namespace UnityExplorer.Inspectors
#if CPP #if CPP
GameObject[] rootObjs = SceneUnstrip.GetRootGameObjects(scene.handle); GameObject[] rootObjs = SceneUnstrip.GetRootGameObjects(scene.handle);
#else #else
GameObject[] rootObjs = SceneUnstrip.GetRootGameObjects(scene); GameObject[] rootObjs = scene.GetRootGameObjects();
#endif #endif
SetSceneObjectList(rootObjs); SetSceneObjectList(rootObjs);

Binary file not shown.

View File

@ -3,7 +3,12 @@ using System.Collections.Generic;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityEngine; using UnityEngine;
using System; using System;
using System.Runtime.InteropServices;
using System.Text;
using UnityExplorer.Unstrip;
#if CPP #if CPP
using UnhollowerBaseLib;
using UnityExplorer.Helpers;
#endif #endif
namespace UnityExplorer.Tests namespace UnityExplorer.Tests
@ -19,11 +24,16 @@ namespace UnityExplorer.Tests
"three", "three",
}; };
public static void StaticMethod() { } public static void StaticMethod() { }
} }
public class TestClass public class TestClass
{ {
public string AAALongString = @"1
2
3
4
5";
public Vector2 AATestVector2 = new Vector2(1, 2); public Vector2 AATestVector2 = new Vector2(1, 2);
public Vector3 AATestVector3 = new Vector3(1, 2, 3); public Vector3 AATestVector3 = new Vector3(1, 2, 3);
public Vector4 AATestVector4 = new Vector4(1, 2, 3, 4); public Vector4 AATestVector4 = new Vector4(1, 2, 3, 4);
@ -112,13 +122,15 @@ namespace UnityExplorer.Tests
private static bool m_setOnlyProperty; private static bool m_setOnlyProperty;
public static bool ReadSetOnlyProperty => m_setOnlyProperty; public static bool ReadSetOnlyProperty => m_setOnlyProperty;
public Texture TestTexture; public Texture2D TestTexture;
public static Sprite TestSprite; public static Sprite TestSprite;
#if CPP #if CPP
public static Il2CppSystem.Collections.Generic.HashSet<string> CppHashSetTest; public static Il2CppSystem.Collections.Generic.HashSet<string> CppHashSetTest;
public static Il2CppSystem.Collections.Generic.List<string> CppStringTest; public static Il2CppSystem.Collections.Generic.List<string> CppStringTest;
public static Il2CppSystem.Collections.IList CppIList; 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 #endif
public TestClass() public TestClass()
@ -134,20 +146,7 @@ namespace UnityExplorer.Tests
} }
#if CPP #if CPP
TestTexture = UIManager.MakeSolidTexture(Color.white, 1000, 600); TextureSpriteTest();
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)}");
CppHashSetTest = new Il2CppSystem.Collections.Generic.HashSet<string>(); CppHashSetTest = new Il2CppSystem.Collections.Generic.HashSet<string>();
CppHashSetTest.Add("1"); CppHashSetTest.Add("1");
@ -157,9 +156,38 @@ namespace UnityExplorer.Tests
CppStringTest = new Il2CppSystem.Collections.Generic.List<string>(); CppStringTest = new Il2CppSystem.Collections.Generic.List<string>();
CppStringTest.Add("1"); CppStringTest.Add("1");
CppStringTest.Add("2"); 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 #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 public static string TestRefInOutGeneric<T>(ref string arg0, in int arg1, out string arg2) where T : Component
{ {
arg2 = "this is arg2"; arg2 = "this is arg2";

View File

@ -77,11 +77,6 @@ namespace UnityExplorer.UI
catch { } catch { }
// Setup Harmony Patches // Setup Harmony Patches
TryPatch(typeof(EventSystem),
"current",
new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_EventSystem_set_current))),
true);
TryPatch(typeof(Cursor), TryPatch(typeof(Cursor),
"lockState", "lockState",
new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_lockState))), new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_lockState))),
@ -91,10 +86,15 @@ namespace UnityExplorer.UI
"visible", "visible",
new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_visible))), new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_visible))),
true); true);
TryPatch(typeof(EventSystem),
"current",
new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_EventSystem_set_current))),
true);
} }
catch (Exception e) catch (Exception e)
{ {
ExplorerCore.Log($"Exception on CursorControl.Init! {e.GetType()}, {e.Message}"); ExplorerCore.Log($"Exception on ForceUnlockCursor.Init! {e.GetType()}, {e.Message}");
} }
} }
@ -105,8 +105,10 @@ namespace UnityExplorer.UI
var harmony = var harmony =
#if ML #if ML
ExplorerMelonMod.Instance.harmonyInstance; ExplorerMelonMod.Instance.harmonyInstance;
#else #elif BIE
ExplorerBepInPlugin.HarmonyInstance; ExplorerBepInPlugin.HarmonyInstance;
#elif STANDALONE
ExplorerStandalone.HarmonyInstance;
#endif #endif
System.Reflection.PropertyInfo prop = type.GetProperty(property); System.Reflection.PropertyInfo prop = type.GetProperty(property);
@ -120,10 +122,10 @@ namespace UnityExplorer.UI
harmony.Patch(prop.GetGetMethod(), postfix: patch); harmony.Patch(prop.GetGetMethod(), postfix: patch);
} }
} }
catch // (Exception e) catch (Exception e)
{ {
//string suf = setter ? "set_" : "get_"; string suf = setter ? "set_" : "get_";
//ExplorerCore.Log($"Unable to patch {type.Name}.{suf}{property}: {e.Message}"); ExplorerCore.Log($"Unable to patch {type.Name}.{suf}{property}: {e.Message}");
} }
} }
@ -158,15 +160,39 @@ namespace UnityExplorer.UI
public static void SetEventSystem() 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; m_settingEventSystem = true;
UIManager.SetEventSystem(); EventSystem.current = UIManager.EventSys;
UIManager.EventSys.enabled = true;
InputManager.ActivateUIModule();
m_settingEventSystem = false; m_settingEventSystem = false;
} }
public static void ReleaseEventSystem() public static void ReleaseEventSystem()
{ {
if (InputManager.CurrentType == InputType.InputSystem)
return;
if (m_lastEventSystem) if (m_lastEventSystem)
{ {
m_lastEventSystem.enabled = true;
//m_lastEventSystem.gameObject.SetActive(true);
m_settingEventSystem = true; m_settingEventSystem = true;
EventSystem.current = m_lastEventSystem; EventSystem.current = m_lastEventSystem;
m_lastInputModule?.ActivateModule(); m_lastInputModule?.ActivateModule();

View File

@ -16,7 +16,7 @@ namespace UnityExplorer.UI.Modules
public static DebugConsole Instance { get; private set; } public static DebugConsole Instance { get; private set; }
public static bool LogUnity { get; set; } = ModConfig.Instance.Log_Unity_Debug; public static bool LogUnity { get; set; } = ModConfig.Instance.Log_Unity_Debug;
public static bool SaveToDisk { get; set; } = ModConfig.Instance.Save_Logs_To_Disk; //public static bool SaveToDisk { get; set; } = ModConfig.Instance.Save_Logs_To_Disk;
internal static StreamWriter s_streamWriter; internal static StreamWriter s_streamWriter;
@ -49,8 +49,8 @@ namespace UnityExplorer.UI.Modules
// set up IO // set up IO
if (!SaveToDisk) //if (!SaveToDisk)
return; // return;
var path = ExplorerCore.EXPLORER_FOLDER + @"\Logs"; var path = ExplorerCore.EXPLORER_FOLDER + @"\Logs";

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
//using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Config; using UnityExplorer.Config;
@ -19,6 +18,7 @@ namespace UnityExplorer.UI.Modules
private Toggle m_unlockMouseToggle; private Toggle m_unlockMouseToggle;
private InputField m_pageLimitInput; private InputField m_pageLimitInput;
private InputField m_defaultOutputInput; private InputField m_defaultOutputInput;
private Toggle m_hideOnStartupToggle;
public override void Init() public override void Init()
{ {
@ -27,26 +27,21 @@ namespace UnityExplorer.UI.Modules
public override void Update() public override void Update()
{ {
// not needed?
} }
internal void OnApply() internal void OnApply()
{ {
if (!string.IsNullOrEmpty(m_keycodeInput.text) && Enum.Parse(typeof(KeyCode), m_keycodeInput.text) is KeyCode keyCode) if (!string.IsNullOrEmpty(m_keycodeInput.text) && Enum.Parse(typeof(KeyCode), m_keycodeInput.text) is KeyCode keyCode)
{
ModConfig.Instance.Main_Menu_Toggle = keyCode; ModConfig.Instance.Main_Menu_Toggle = keyCode;
}
ModConfig.Instance.Force_Unlock_Mouse = m_unlockMouseToggle.isOn; ModConfig.Instance.Force_Unlock_Mouse = m_unlockMouseToggle.isOn;
if (!string.IsNullOrEmpty(m_pageLimitInput.text) && int.TryParse(m_pageLimitInput.text, out int lim)) if (!string.IsNullOrEmpty(m_pageLimitInput.text) && int.TryParse(m_pageLimitInput.text, out int lim))
{
ModConfig.Instance.Default_Page_Limit = lim; ModConfig.Instance.Default_Page_Limit = lim;
}
ModConfig.Instance.Default_Output_Path = m_defaultOutputInput.text; ModConfig.Instance.Default_Output_Path = m_defaultOutputInput.text;
// todo default output path ModConfig.Instance.Hide_On_Startup = m_hideOnStartupToggle.isOn;
ModConfig.SaveSettings(); ModConfig.SaveSettings();
ModConfig.InvokeConfigChanged(); ModConfig.InvokeConfigChanged();
@ -98,6 +93,7 @@ namespace UnityExplorer.UI.Modules
ConstructMouseUnlockOpt(optionsGroupObj); ConstructMouseUnlockOpt(optionsGroupObj);
ConstructPageLimitOpt(optionsGroupObj); ConstructPageLimitOpt(optionsGroupObj);
ConstructOutputPathOpt(optionsGroupObj); ConstructOutputPathOpt(optionsGroupObj);
ConstructHideOnStartupOpt(optionsGroupObj);
var applyBtnObj = UIFactory.CreateButton(Content, new Color(0.2f, 0.2f, 0.2f)); var applyBtnObj = UIFactory.CreateButton(Content, new Color(0.2f, 0.2f, 0.2f));
var applyText = applyBtnObj.GetComponentInChildren<Text>(); var applyText = applyBtnObj.GetComponentInChildren<Text>();
@ -113,10 +109,34 @@ namespace UnityExplorer.UI.Modules
applyBtn.onClick.AddListener(OnApply); applyBtn.onClick.AddListener(OnApply);
} }
private void ConstructHideOnStartupOpt(GameObject optionsGroupObj)
{
var rowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.childControlWidth = true;
rowGroup.childForceExpandWidth = false;
rowGroup.childControlHeight = true;
rowGroup.childForceExpandHeight = true;
var groupLayout = rowObj.AddComponent<LayoutElement>();
groupLayout.minHeight = 25;
groupLayout.flexibleHeight = 0;
groupLayout.minWidth = 200;
groupLayout.flexibleWidth = 1000;
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelText = labelObj.GetComponent<Text>();
labelText.text = "Hide UI on startup:";
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 150;
labelLayout.minHeight = 25;
UIFactory.CreateToggle(rowObj, out m_hideOnStartupToggle, out Text toggleText);
m_hideOnStartupToggle.isOn = ModConfig.Instance.Hide_On_Startup;
toggleText.text = "";
}
internal void ConstructKeycodeOpt(GameObject parent) internal void ConstructKeycodeOpt(GameObject parent)
{ {
//public KeyCode Main_Menu_Toggle = KeyCode.F7;
var rowObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0)); var rowObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>(); var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.childControlWidth = true; rowGroup.childControlWidth = true;
@ -146,8 +166,6 @@ namespace UnityExplorer.UI.Modules
internal void ConstructMouseUnlockOpt(GameObject parent) internal void ConstructMouseUnlockOpt(GameObject parent)
{ {
//public bool Force_Unlock_Mouse = true;
var rowObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0)); var rowObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>(); var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.childControlWidth = true; rowGroup.childControlWidth = true;

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
//using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityEngine.UI; using UnityEngine.UI;
@ -9,6 +8,7 @@ using UnityExplorer.Helpers;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using UnityExplorer.UI.Shared; using UnityExplorer.UI.Shared;
using UnityExplorer.Unstrip; using UnityExplorer.Unstrip;
using System.Reflection;
#if CPP #if CPP
using UnhollowerRuntimeLib; using UnhollowerRuntimeLib;
#endif #endif
@ -21,7 +21,7 @@ namespace UnityExplorer.UI.Modules
GameObject, GameObject,
Component, Component,
Custom, Custom,
Instance, Singleton,
StaticClass StaticClass
} }
@ -46,11 +46,14 @@ namespace UnityExplorer.UI.Modules
public static SearchPage Instance; public static SearchPage Instance;
internal SearchContext m_context;
private SceneFilter m_sceneFilter;
private ChildFilter m_childFilter;
// ui elements // ui elements
private Text m_resultCountText; private Text m_resultCountText;
internal SearchContext m_context;
private InputField m_customTypeInput; private InputField m_customTypeInput;
private InputField m_nameInput; private InputField m_nameInput;
@ -60,9 +63,6 @@ namespace UnityExplorer.UI.Modules
private Dropdown m_sceneDropdown; private Dropdown m_sceneDropdown;
private int m_lastSceneCount = -1; private int m_lastSceneCount = -1;
private SceneFilter m_sceneFilter;
private ChildFilter m_childFilter;
private GameObject m_extraFilterRow; private GameObject m_extraFilterRow;
@ -132,10 +132,9 @@ namespace UnityExplorer.UI.Modules
else else
{ {
var obj = m_results[itemIndex]; var obj = m_results[itemIndex];
var unityObj = obj as UnityEngine.Object;
var uObj = obj as UnityEngine.Object; if (obj == null || (unityObj != null && !unityObj))
if (obj == null || (uObj != null && !uObj))
continue; continue;
if (i >= m_resultShortList.Count) if (i >= m_resultShortList.Count)
@ -150,17 +149,25 @@ namespace UnityExplorer.UI.Modules
var text = m_resultListTexts[i]; var text = m_resultListTexts[i];
var name = $"<color={UISyntaxHighlight.Class_Instance}>{ReflectionHelpers.GetActualType(obj).Name}</color>"; if (m_context != SearchContext.StaticClass)
if (m_context != SearchContext.Instance && m_context != SearchContext.StaticClass)
{ {
if (uObj && !string.IsNullOrEmpty(uObj.name)) var name = UISyntaxHighlight.ParseFullSyntax(obj.GetActualType(), true);
name += $": {uObj.name}";
else
name += ": <i><color=grey>untitled</color></i>";
}
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; var label = text.transform.parent.parent.gameObject;
if (!label.activeSelf) if (!label.activeSelf)
@ -222,14 +229,127 @@ namespace UnityExplorer.UI.Modules
} }
m_sceneDropdown.transform.Find("Label").GetComponent<Text>().text = "Any"; m_sceneDropdown.transform.Find("Label").GetComponent<Text>().text = "Any";
m_sceneFilter = SceneFilter.Any;
} }
// ~~~~~ UI Callbacks ~~~~~ // ~~~~~ UI Callbacks ~~~~~
internal void OnUnitySearchClicked() internal void OnSearchClicked()
{ {
m_resultListPageHandler.CurrentPage = 0; 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; Type searchType = null;
switch (m_context) switch (m_context)
{ {
@ -260,11 +380,8 @@ namespace UnityExplorer.UI.Modules
if (searchType == null) if (searchType == null)
return; return;
#if MONO
var allObjects = ResourcesUnstrip.FindObjectsOfTypeAll(searchType); var allObjects = ResourcesUnstrip.FindObjectsOfTypeAll(searchType);
#else
var allObjects = ResourcesUnstrip.FindObjectsOfTypeAll(Il2CppType.From(searchType));
#endif
var results = new List<object>(); var results = new List<object>();
// perform filter comparers // perform filter comparers
@ -308,12 +425,12 @@ namespace UnityExplorer.UI.Modules
: obj.TryCast<Component>().gameObject; : obj.TryCast<Component>().gameObject;
#endif #endif
if (!go)
continue;
// scene check // scene check
if (m_sceneFilter != SceneFilter.Any) if (m_sceneFilter != SceneFilter.Any)
{ {
if (!go)
continue;
switch (m_context) switch (m_context)
{ {
case SearchContext.GameObject: case SearchContext.GameObject:
@ -328,24 +445,23 @@ namespace UnityExplorer.UI.Modules
} }
} }
// root object check (no parent) if (m_childFilter != ChildFilter.Any)
if (m_childFilter == ChildFilter.HasParent && !go.transform.parent) {
continue; if (!go)
else if (m_childFilter == ChildFilter.RootObject && go.transform.parent) continue;
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); results.Add(obj);
} }
m_results = results.ToArray(); 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() private void OnResultPageTurn()
@ -493,6 +609,23 @@ namespace UnityExplorer.UI.Modules
m_customTypeInput = customTypeObj.GetComponent<InputField>(); m_customTypeInput = customTypeObj.GetComponent<InputField>();
m_customTypeInput.placeholder.gameObject.GetComponent<Text>().text = "eg. UnityEngine.Texture2D, etc..."; 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 // search input
var nameRowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0)); var nameRowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0));
@ -604,7 +737,7 @@ namespace UnityExplorer.UI.Modules
searchBtnLayout.flexibleHeight = 0; searchBtnLayout.flexibleHeight = 0;
var searchBtn = searchBtnObj.GetComponent<Button>(); 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) internal void AddContextButton(GameObject parent, string label, SearchContext context, float width = 110)

View File

@ -33,6 +33,8 @@ namespace UnityExplorer.UI.Shared
this.sliderScroller = sliderScroller; this.sliderScroller = sliderScroller;
this.inputField = inputField; this.inputField = inputField;
sliderScroller.m_parentInputScroller = this;
inputField.onValueChanged.AddListener(OnTextChanged); inputField.onValueChanged.AddListener(OnTextChanged);
inputRect = inputField.GetComponent<RectTransform>(); 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) internal void OnTextChanged(string text)
{ {
m_lastText = text; m_lastText = text;

View File

@ -8,150 +8,154 @@ using UnityExplorer;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
using UnityExplorer.UI; using UnityExplorer.UI;
// Basically just to fix an issue with Scrollbars, instead we use a Slider as the scrollbar. namespace UnityExplorer.UI.Shared
public class SliderScrollbar
{ {
internal static readonly List<SliderScrollbar> Instances = new List<SliderScrollbar>(); // Basically just to fix an issue with Scrollbars, instead we use a Slider as the scrollbar.
public class 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)
{ {
Instances.Add(this); internal static readonly List<SliderScrollbar> Instances = new List<SliderScrollbar>();
this.m_scrollbar = scrollbar; public bool IsActive { get; private set; }
this.m_slider = slider;
this.m_scrollRect = scrollbar.transform.parent.GetComponent<RectTransform>();
this.m_scrollbar.onValueChanged.AddListener(this.OnScrollbarValueChanged); internal readonly Scrollbar m_scrollbar;
this.m_slider.onValueChanged.AddListener(this.OnSliderValueChanged); internal readonly Slider m_slider;
internal readonly RectTransform m_scrollRect;
this.RefreshVisibility(); internal InputFieldScroller m_parentInputScroller;
this.m_slider.Set(1f, false);
}
internal bool CheckDestroyed() public SliderScrollbar(Scrollbar scrollbar, Slider slider)
{
if (!m_slider || !m_scrollbar)
{ {
Instances.Remove(this); Instances.Add(this);
return true;
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 bool CheckDestroyed()
}
internal void Update()
{
this.RefreshVisibility();
}
internal void RefreshVisibility()
{
if (!m_slider.gameObject.activeInHierarchy)
{ {
IsActive = false; if (!m_slider || !m_scrollbar)
return; {
Instances.Remove(this);
return true;
}
return false;
} }
bool shouldShow = !Mathf.Approximately(this.m_scrollbar.size, 1); internal void Update()
var obj = this.m_slider.handleRect.gameObject;
if (IsActive != shouldShow)
{ {
IsActive = shouldShow; this.RefreshVisibility();
obj.SetActive(IsActive);
if (IsActive)
this.m_slider.Set(this.m_scrollbar.value, false);
else
m_slider.Set(1f, false);
} }
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 #if MONO
public static class SliderExtensions public static class SliderExtensions
{ {
@ -175,4 +179,5 @@ public static class SliderExtensions
SetMethod.Invoke(slider, new object[] { value, invokeCallback }); SetMethod.Invoke(slider, new object[] { value, invokeCallback });
} }
} }
#endif #endif
}

View File

@ -178,13 +178,9 @@ namespace UnityExplorer.UI
Image image = groupObj.AddComponent<Image>(); Image image = groupObj.AddComponent<Image>();
if (color != default) if (color != default)
{
image.color = color; image.color = color;
}
else else
{
image.color = new Color(44f / 255f, 44f / 255f, 44f / 255f); image.color = new Color(44f / 255f, 44f / 255f, 44f / 255f);
}
return groupObj; return groupObj;
} }
@ -657,16 +653,16 @@ namespace UnityExplorer.UI
contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var contentLayout = content.AddComponent<VerticalLayoutGroup>(); var contentGroup = content.AddComponent<VerticalLayoutGroup>();
contentLayout.childForceExpandHeight = true; contentGroup.childForceExpandHeight = true;
contentLayout.childControlHeight = true; contentGroup.childControlHeight = true;
contentLayout.childForceExpandWidth = true; contentGroup.childForceExpandWidth = true;
contentLayout.childControlWidth = true; contentGroup.childControlWidth = true;
contentLayout.padding.left = 5; contentGroup.padding.left = 5;
contentLayout.padding.right = 5; contentGroup.padding.right = 5;
contentLayout.padding.top = 5; contentGroup.padding.top = 5;
contentLayout.padding.bottom = 5; contentGroup.padding.bottom = 5;
contentLayout.spacing = 5; contentGroup.spacing = 5;
GameObject scrollBarObj = CreateUIObject("DynamicScrollbar", mainObj); GameObject scrollBarObj = CreateUIObject("DynamicScrollbar", mainObj);

View File

@ -4,10 +4,10 @@ using UnityEngine.UI;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using UnityExplorer.UI.Modules; using UnityExplorer.UI.Modules;
using System.IO; using System.IO;
//using TMPro;
using System.Reflection; using System.Reflection;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
using UnityExplorer.UI.Shared; using UnityExplorer.UI.Shared;
using UnityExplorer.Input;
#if CPP #if CPP
using UnityExplorer.Unstrip; using UnityExplorer.Unstrip;
#endif #endif
@ -18,37 +18,15 @@ namespace UnityExplorer.UI
{ {
public static GameObject CanvasRoot { get; private set; } public static GameObject CanvasRoot { get; private set; }
public static EventSystem EventSys { get; private set; } public static EventSystem EventSys { get; private set; }
public static StandaloneInputModule InputModule { get; private set; }
//internal static Material UIMaterial { get; private set; }
internal static Sprite ResizeCursor { get; private set; }
internal static Font ConsoleFont { get; private set; } internal static Font ConsoleFont { get; private set; }
internal static Sprite ResizeCursor { get; private set; }
internal static Shader BackupShader { get; private set; }
public static void Init() public static void Init()
{ {
var bundlePath = ExplorerCore.EXPLORER_FOLDER + @"\explorerui.bundle"; LoadBundle();
if (File.Exists(bundlePath))
{
var bundle = AssetBundle.LoadFromFile(bundlePath);
// 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 = bundle.LoadAsset<Shader>("DefaultUI");
}
ResizeCursor = bundle.LoadAsset<Sprite>("cursor");
ConsoleFont = bundle.LoadAsset<Font>("CONSOLA");
ExplorerCore.Log("Loaded UI bundle");
}
else
{
ExplorerCore.LogWarning("Could not find the ExplorerUI Bundle! It should exist at '" + bundlePath + "'");
return;
}
// Create core UI Canvas and Event System handler // Create core UI Canvas and Event System handler
CreateRootCanvas(); CreateRootCanvas();
@ -62,47 +40,32 @@ namespace UnityExplorer.UI
Canvas.ForceUpdateCanvases(); Canvas.ForceUpdateCanvases();
} }
public static void SetEventSystem()
{
EventSystem.current = EventSys;
InputModule.ActivateModule();
}
public static void OnSceneChange() public static void OnSceneChange()
{ {
SceneExplorer.Instance?.OnSceneChange(); SceneExplorer.Instance?.OnSceneChange();
SearchPage.Instance?.OnSceneChange(); SearchPage.Instance?.OnSceneChange();
} }
public static void Update() public static void Update()
{ {
MainMenu.Instance?.Update(); MainMenu.Instance?.Update();
if (EventSys && InputModule) if (EventSys)
{ {
if (EventSystem.current != EventSys) if (EventSystem.current != EventSys)
{
ForceUnlockCursor.SetEventSystem(); ForceUnlockCursor.SetEventSystem();
//ForceUnlockCursor.Unlock = true;
}
// Fix for games which override the InputModule pointer events (eg, VRChat)
#if CPP #if CPP
if (InputModule.m_InputPointerEvent != null) // Some IL2CPP games behave weird with multiple UI Input Systems, some fixes for them.
var evt = InputManager.InputPointerEvent;
if (evt != null)
{ {
PointerEventData evt = InputModule.m_InputPointerEvent;
if (!evt.eligibleForClick && evt.selectedObject) if (!evt.eligibleForClick && evt.selectedObject)
{
evt.eligibleForClick = true; evt.eligibleForClick = true;
}
} }
#endif #endif
} }
if (PanelDragger.Instance != null) if (PanelDragger.Instance != null)
{
PanelDragger.Instance.Update(); PanelDragger.Instance.Update();
}
for (int i = 0; i < SliderScrollbar.Instances.Count; i++) for (int i = 0; i < SliderScrollbar.Instances.Count; i++)
{ {
@ -118,13 +81,75 @@ namespace UnityExplorer.UI
{ {
var input = InputFieldScroller.Instances[i]; var input = InputFieldScroller.Instances[i];
if (input.sliderScroller.CheckDestroyed()) if (input.CheckDestroyed())
i--; i--;
else else
input.Update(); 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()
{
AssetBundle bundle = null;
try
{
bundle = LoadExplorerUi("modern");
}
catch
{
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() private static GameObject CreateRootCanvas()
{ {
GameObject rootObj = new GameObject("ExplorerCanvas"); GameObject rootObj = new GameObject("ExplorerCanvas");
@ -135,14 +160,13 @@ namespace UnityExplorer.UI
CanvasRoot.transform.position = new Vector3(0f, 0f, 1f); CanvasRoot.transform.position = new Vector3(0f, 0f, 1f);
EventSys = rootObj.AddComponent<EventSystem>(); EventSys = rootObj.AddComponent<EventSystem>();
InputModule = rootObj.AddComponent<StandaloneInputModule>(); InputManager.AddUIModule();
InputModule.ActivateModule();
Canvas canvas = rootObj.AddComponent<Canvas>(); Canvas canvas = rootObj.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceCamera; canvas.renderMode = RenderMode.ScreenSpaceCamera;
canvas.referencePixelsPerUnit = 100; canvas.referencePixelsPerUnit = 100;
canvas.sortingOrder = 999; canvas.sortingOrder = 999;
canvas.pixelPerfect = false; //canvas.pixelPerfect = false;
CanvasScaler scaler = rootObj.AddComponent<CanvasScaler>(); CanvasScaler scaler = rootObj.AddComponent<CanvasScaler>();
scaler.referenceResolution = new Vector2(1920, 1080); scaler.referenceResolution = new Vector2(1920, 1080);
@ -152,37 +176,5 @@ namespace UnityExplorer.UI
return rootObj; 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;
}
} }
} }

View File

@ -42,10 +42,10 @@ namespace UnityExplorer.UI
public static string ParseFullSyntax(Type type, bool includeNamespace, MemberInfo memberInfo = null) public static string ParseFullSyntax(Type type, bool includeNamespace, MemberInfo memberInfo = null)
{ {
string ret = "";
if (type == null) if (type == null)
return "????????????"; throw new ArgumentNullException("type");
string ret = "";
if (type.IsGenericParameter || (type.HasElementType && type.GetElementType().IsGenericParameter)) if (type.IsGenericParameter || (type.HasElementType && type.GetElementType().IsGenericParameter))
{ {

View File

@ -25,17 +25,9 @@
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
<RootNamespace>UnityExplorer</RootNamespace> <RootNamespace>UnityExplorer</RootNamespace>
<!-- Set this to the BepInEx Il2Cpp Game folder, without the ending '\' character. --> <!-- Set this to the BepInEx Il2Cpp Game folder, without the ending '\' character. -->
<BIECppGameFolder>D:\Steam\steamapps\common\Outward</BIECppGameFolder> <BIECppGameFolder>E:\source\Unity Projects\Test\_BUILD</BIECppGameFolder>
<!-- Set this to the BepInEx Mono Game folder, without the ending '\' character. -->
<BIEMonoGameFolder>D:\source\Unity Projects\Test\_BUILD_MONO</BIEMonoGameFolder>
<!-- Set this to the BepInEx Mono Managed folder, without the ending '\' character. -->
<BIEMonoManagedFolder>D:\source\Unity Projects\Test\_BUILD_MONO\Test_Data\Managed</BIEMonoManagedFolder>
<!-- Set this to the MelonLoader Il2Cpp Game folder, without the ending '\' character. --> <!-- Set this to the MelonLoader Il2Cpp Game folder, without the ending '\' character. -->
<MLCppGameFolder>D:\Steam\steamapps\common\VRChat</MLCppGameFolder> <MLCppGameFolder>E:\source\Unity Projects\Test\_BUILD</MLCppGameFolder>
<!-- Set this to the MelonLoader Mono Game folder, without the ending '\' character. -->
<MLMonoGameFolder>D:\source\Unity Projects\Test\_BUILD_MONO</MLMonoGameFolder>
<!-- Set this to the MelonLoader Mono Managed folder, without the ending '\' character. -->
<MLMonoManagedFolder>D:\source\Unity Projects\Test\_BUILD_MONO\Test_Data\Managed</MLMonoManagedFolder>
<NuGetPackageImportStamp> <NuGetPackageImportStamp>
</NuGetPackageImportStamp> </NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
@ -76,7 +68,29 @@
<IsMelonLoader>false</IsMelonLoader> <IsMelonLoader>false</IsMelonLoader>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </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> <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>
<Private>False</Private>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
@ -103,7 +117,7 @@
<!-- MelonLoader Mono refs --> <!-- MelonLoader Mono refs -->
<ItemGroup Condition="'$(IsMelonLoader)|$(IsCpp)'=='true|false'"> <ItemGroup Condition="'$(IsMelonLoader)|$(IsCpp)'=='true|false'">
<Reference Include="MelonLoader.ModHandler"> <Reference Include="MelonLoader.ModHandler">
<HintPath>$(MLMonoGameFolder)\MelonLoader\MelonLoader.ModHandler.dll</HintPath> <HintPath>..\lib\MelonLoader.ModHandler.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
@ -221,6 +235,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ExplorerStandalone.cs" />
<Compile Include="Helpers\EventHelper.cs" /> <Compile Include="Helpers\EventHelper.cs" />
<Compile Include="Inspectors\MouseInspector.cs" /> <Compile Include="Inspectors\MouseInspector.cs" />
<Compile Include="Inspectors\Reflection\CacheObject\CacheEnumerated.cs" /> <Compile Include="Inspectors\Reflection\CacheObject\CacheEnumerated.cs" />
@ -297,6 +312,7 @@
<Compile Include="Unstrip\SceneUnstrip.cs" /> <Compile Include="Unstrip\SceneUnstrip.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UI\UIFactory.cs" /> <Compile Include="UI\UIFactory.cs" />
<EmbeddedResource Include="Resources\*" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="ILRepack.targets" /> <None Include="ILRepack.targets" />

View File

@ -11,6 +11,8 @@ Global
Release_BIE_Mono|Any CPU = Release_BIE_Mono|Any CPU Release_BIE_Mono|Any CPU = Release_BIE_Mono|Any CPU
Release_ML_Cpp|Any CPU = Release_ML_Cpp|Any CPU Release_ML_Cpp|Any CPU = Release_ML_Cpp|Any CPU
Release_ML_Mono|Any CPU = Release_ML_Mono|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 EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_BIE_Cpp|Any CPU.ActiveCfg = Release_BIE_Cpp|Any CPU {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_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.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_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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -24,6 +24,17 @@ namespace UnityExplorer.Unstrip
return new AssetBundle(ptr); 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 ~~~~~~~~~~~~ // ~~~~~~~~~~~~ Instance ~~~~~~~~~~~~

View File

@ -10,6 +10,16 @@ namespace UnityExplorer.Unstrip
{ {
public static class ImageConversionUnstrip 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 #if CPP
// byte[] ImageConversion.EncodeToPNG(this Texture2D image); // byte[] ImageConversion.EncodeToPNG(this Texture2D image);
@ -17,8 +27,12 @@ namespace UnityExplorer.Unstrip
public static byte[] EncodeToPNG(this Texture2D tex) public static byte[] EncodeToPNG(this Texture2D tex)
{ {
IntPtr ptr = ICallHelper.GetICall<d_EncodeToPNG>("UnityEngine.ImageConversion::EncodeToPNG") var iCall = ICallHelper.GetICall<d_EncodeToPNG>("UnityEngine.ImageConversion::EncodeToPNG");
.Invoke(tex.Pointer);
IntPtr ptr = iCall.Invoke(tex.Pointer);
if (ptr == IntPtr.Zero)
return null;
return new Il2CppStructArray<byte>(ptr); return new Il2CppStructArray<byte>(ptr);
} }
@ -29,28 +43,40 @@ namespace UnityExplorer.Unstrip
public static bool LoadImage(this Texture2D tex, byte[] data, bool markNonReadable) public static bool LoadImage(this Texture2D tex, byte[] data, bool markNonReadable)
{ {
Il2CppStructArray<byte> il2cppArray = new Il2CppStructArray<byte>(data.Length); var il2cppArray = (Il2CppStructArray<byte>)data;
for (int i = 0; i < data.Length; i++)
il2cppArray[i] = data[i];
bool ret = ICallHelper.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage") var iCall = ICallHelper.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage");
.Invoke(tex.Pointer, il2cppArray.Pointer, markNonReadable);
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 #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)) #if CPP
{ return CreateSprite(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero, 100f, 0u, Vector4.zero);
return false; #else
} return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
#endif
byte[] data = File.ReadAllBytes(filePath);
return tex.LoadImage(data, markNonReadable);
} }
} }
} }

View File

@ -3,24 +3,27 @@ using Mono.CSharp;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
#if CPP #if CPP
using UnhollowerBaseLib; using UnhollowerBaseLib;
using UnhollowerRuntimeLib;
#endif #endif
namespace UnityExplorer.Unstrip namespace UnityExplorer.Unstrip
{ {
public class ResourcesUnstrip public class ResourcesUnstrip
{ {
public static UnityEngine.Object[] FindObjectsOfTypeAll(Type type)
{
#if MONO
return UnityEngine.Resources.FindObjectsOfTypeAll(type);
#else
var iCall = ICallHelper.GetICall<d_FindObjectsOfTypeAll>("UnityEngine.Resources::FindObjectsOfTypeAll");
var cppType = Il2CppType.From(type);
return new Il2CppReferenceArray<UnityEngine.Object>(iCall.Invoke(cppType.Pointer));
#endif
}
#if CPP #if CPP
internal delegate IntPtr d_FindObjectsOfTypeAll(IntPtr type); internal delegate IntPtr d_FindObjectsOfTypeAll(IntPtr type);
public static UnityEngine.Object[] FindObjectsOfTypeAll(Il2CppSystem.Type type)
{
var iCall = ICallHelper.GetICall<d_FindObjectsOfTypeAll>("UnityEngine.Resources::FindObjectsOfTypeAll");
return new Il2CppReferenceArray<UnityEngine.Object>(iCall.Invoke(type.Pointer));
}
#else
public static UnityEngine.Object[] FindObjectsOfTypeAll(Type type) => UnityEngine.Resources.FindObjectsOfTypeAll(type);
#endif #endif
} }
} }

View File

@ -3,36 +3,25 @@ using UnityExplorer.Helpers;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using System.Reflection;
namespace UnityExplorer.Unstrip namespace UnityExplorer.Unstrip
{ {
public class SceneUnstrip public static class SceneUnstrip
{ {
#if MONO #if MONO
public static GameObject[] GetRootGameObjects(Scene scene) => scene.GetRootGameObjects(); private static readonly FieldInfo fi_Scene_handle = typeof(Scene).GetField("m_Handle", ReflectionHelpers.CommonFlags);
//public static GameObject[] GetRootGameObjects(int handle)
//{
// Scene scene = default;
// if (handle == SceneExplorer.DontDestroyHandle)
// scene = SceneExplorer.DontDestroyObject.scene;
// else
// {
// for (int i = 0; i < SceneManager.sceneCount; i++)
// {
// var iscene = SceneManager.GetSceneAt(i);
// if (iscene.handle == handle)
// scene = iscene;
// }
// }
// if (scene != default && scene.handle != -1)
// return scene.GetRootGameObjects();
// return new GameObject[0];
//}
#endif #endif
public static int GetHandle(this Scene scene)
{
#if CPP
return scene.handle;
#else
return (int)fi_Scene_handle.GetValue(scene);
#endif
}
#if CPP #if CPP
//Scene.GetRootGameObjects(); //Scene.GetRootGameObjects();
@ -43,13 +32,16 @@ namespace UnityExplorer.Unstrip
public static GameObject[] GetRootGameObjects(int handle) public static GameObject[] GetRootGameObjects(int handle)
{ {
if (handle == -1) if (handle == -1)
{
return new GameObject[0]; return new GameObject[0];
}
Il2CppSystem.Collections.Generic.List<GameObject> list = new Il2CppSystem.Collections.Generic.List<GameObject>(GetRootCount(handle)); int count = GetRootCount(handle);
d_GetRootGameObjects iCall = ICallHelper.GetICall<d_GetRootGameObjects>("UnityEngine.SceneManagement.Scene::GetRootGameObjectsInternal"); if (count < 1)
return new GameObject[0];
var list = new Il2CppSystem.Collections.Generic.List<GameObject>(count);
var iCall = ICallHelper.GetICall<d_GetRootGameObjects>("UnityEngine.SceneManagement.Scene::GetRootGameObjectsInternal");
iCall.Invoke(handle, list.Pointer); iCall.Invoke(handle, list.Pointer);
@ -58,14 +50,14 @@ namespace UnityExplorer.Unstrip
//Scene.rootCount; //Scene.rootCount;
internal delegate int GetRootCountInternal_delegate(int handle); internal delegate int d_GetRootCountInternal(int handle);
public static int GetRootCount(Scene scene) => GetRootCount(scene.handle); public static int GetRootCount(Scene scene) => GetRootCount(scene.handle);
public static int GetRootCount(int handle) public static int GetRootCount(int handle)
{ {
GetRootCountInternal_delegate iCall = ICallHelper.GetICall<GetRootCountInternal_delegate>("UnityEngine.SceneManagement.Scene::GetRootCountInternal"); return ICallHelper.GetICall<d_GetRootCountInternal>("UnityEngine.SceneManagement.Scene::GetRootCountInternal")
return iCall.Invoke(handle); .Invoke(handle);
} }
#endif #endif
} }

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="ILRepack.Lib.MSBuild.Task" version="2.0.18.1" targetFramework="net472" /> <package id="ILRepack.Lib.MSBuild.Task" version="2.0.18.1" targetFramework="net472" />
<package id="ini-parser" version="2.5.2" targetFramework="net35" />
</packages> </packages>