Compare commits

...

18 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
31 changed files with 523 additions and 300 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,8 +24,9 @@
| Mod Loader | IL2CPP | Mono | | Mod Loader | IL2CPP | Mono |
| ----------- | ------ | ---- | | ----------- | ------ | ---- |
| [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Mono.zip) |
| [BepInEx](https://github.com/BepInEx/BepInEx) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx.Mono.zip) | | [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) |
| [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Mono.zip) |
| Standalone | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Il2Cpp.zip) | ✔️ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Mono.zip) |
## Features ## Features
@ -49,15 +49,21 @@
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
@ -89,7 +95,7 @@ You can access the settings via the "Options" page of the main menu, or directly
If you'd like to build this yourself, you will need to have installed BepInEx and/or MelonLoader for at least one Unity game. If you want to build all 4 versions, you will need at least one IL2CPP and one Mono game, with BepInEx and MelonLoader installed for both. If you'd like to build this yourself, you will need to have installed BepInEx and/or MelonLoader for at least one Unity game. If you want to build all 4 versions, you will need at least one IL2CPP and one Mono game, with BepInEx and MelonLoader installed for both.
1. Install BepInEx or MelonLoader for your game. 1. Install BepInEx or MelonLoader for your game, or use the standalone build.
2. Open the `src\UnityExplorer.csproj` file in a text editor. 2. Open the `src\UnityExplorer.csproj` file in a text editor.
3. For IL2CPP builds, make sure you set `BIECppGameFolder` (for BepInEx) and/or `MLCppGameFolder` (for MelonLoader) so the project can locate the necessary references. 3. For IL2CPP builds, make sure you set `BIECppGameFolder` (for BepInEx) and/or `MLCppGameFolder` (for MelonLoader) so the project can locate the necessary references.
4. Open the `src\UnityExplorer.sln` project. 4. Open the `src\UnityExplorer.sln` project.

Binary file not shown.

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

@ -11,7 +11,7 @@ namespace UnityExplorer.Config
public static ModConfig Instance; public static ModConfig Instance;
internal static readonly IniDataParser _parser = new IniDataParser(); internal static readonly IniDataParser _parser = new IniDataParser();
internal const string INI_PATH = ExplorerCore.EXPLORER_FOLDER + @"\config.ini"; internal static readonly string INI_PATH = Path.Combine(ExplorerCore.EXPLORER_FOLDER, "config.ini");
static ModConfig() static ModConfig()
{ {
@ -24,7 +24,8 @@ namespace UnityExplorer.Config
public int Default_Page_Limit = 25; public int Default_Page_Limit = 25;
public string Default_Output_Path = ExplorerCore.EXPLORER_FOLDER + @"\Output"; 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;
@ -56,24 +57,27 @@ namespace UnityExplorer.Config
{ {
switch (config.KeyName) switch (config.KeyName)
{ {
case "Main_Menu_Toggle": case nameof(Main_Menu_Toggle):
Instance.Main_Menu_Toggle = (KeyCode)Enum.Parse(typeof(KeyCode), config.Value); Instance.Main_Menu_Toggle = (KeyCode)Enum.Parse(typeof(KeyCode), config.Value);
break; break;
case "Force_Unlock_Mouse": case nameof(Force_Unlock_Mouse):
Instance.Force_Unlock_Mouse = bool.Parse(config.Value); Instance.Force_Unlock_Mouse = bool.Parse(config.Value);
break; break;
case "Default_Page_Limit": case nameof(Default_Page_Limit):
Instance.Default_Page_Limit = int.Parse(config.Value); Instance.Default_Page_Limit = int.Parse(config.Value);
break; break;
case "Log_Unity_Debug": case nameof(Log_Unity_Debug):
Instance.Log_Unity_Debug = bool.Parse(config.Value); Instance.Log_Unity_Debug = bool.Parse(config.Value);
break; break;
case "Save_Logs_To_Disk": case nameof(Default_Output_Path):
Instance.Save_Logs_To_Disk = bool.Parse(config.Value);
break;
case "Default_Output_Path":
Instance.Default_Output_Path = config.Value; Instance.Default_Output_Path = config.Value;
break; 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;
} }
} }
@ -87,12 +91,13 @@ namespace UnityExplorer.Config
data.Sections.AddSection("Config"); data.Sections.AddSection("Config");
var sec = data.Sections["Config"]; var sec = data.Sections["Config"];
sec.AddKey("Main_Menu_Toggle", Instance.Main_Menu_Toggle.ToString()); sec.AddKey(nameof(Main_Menu_Toggle), Instance.Main_Menu_Toggle.ToString());
sec.AddKey("Force_Unlock_Mouse", Instance.Force_Unlock_Mouse.ToString()); sec.AddKey(nameof(Force_Unlock_Mouse), Instance.Force_Unlock_Mouse.ToString());
sec.AddKey("Default_Page_Limit", Instance.Default_Page_Limit.ToString()); sec.AddKey(nameof(Default_Page_Limit), Instance.Default_Page_Limit.ToString());
sec.AddKey("Log_Unity_Debug", Instance.Log_Unity_Debug.ToString()); sec.AddKey(nameof(Log_Unity_Debug), Instance.Log_Unity_Debug.ToString());
sec.AddKey("Save_Logs_To_Disk", Instance.Save_Logs_To_Disk.ToString()); sec.AddKey(nameof(Default_Output_Path), Instance.Default_Output_Path);
sec.AddKey("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()); File.WriteAllText(INI_PATH, data.ToString());
} }

View File

@ -1,25 +1,45 @@
using System; using System;
using System.IO; using System.IO;
using System.Reflection;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityExplorer.Config; using UnityExplorer.Config;
using UnityExplorer.Helpers;
using UnityExplorer.Input; using UnityExplorer.Input;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Modules; using UnityExplorer.UI.Modules;
#if CPP
using UnityExplorer.Helpers;
#endif
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.1.3"; 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; }
@ -90,6 +110,10 @@ 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); // InspectorManager.Instance.Inspect(Tests.TestClass.Instance);
} }
catch (Exception e) catch (Exception e)
@ -161,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());
@ -170,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
} }
@ -184,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
} }
@ -198,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

@ -101,8 +101,24 @@ 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> CppClassPointers = new Dictionary<Type, IntPtr>(); private static readonly Dictionary<Type, IntPtr> CppClassPointers = new Dictionary<Type, IntPtr>();

View File

@ -70,7 +70,12 @@ 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;

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);
} }

View File

@ -33,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; }

View File

@ -63,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

@ -176,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;
@ -205,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"))
@ -303,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

@ -58,6 +58,8 @@ namespace UnityExplorer.Inspectors
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;
@ -202,6 +204,8 @@ namespace UnityExplorer.Inspectors
list.Add(new CacheProperty(pi, target, m_scrollContent)); list.Add(new CacheProperty(pi, target, m_scrollContent));
else else
list.Add(new CacheField(fi, target, m_scrollContent)); list.Add(new CacheField(fi, target, m_scrollContent));
list.Last().ParentInspector = this;
} }
catch (Exception e) catch (Exception e)
{ {

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);

View File

@ -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);
@ -176,6 +178,7 @@ namespace UnityExplorer.UI
// Set to our current system // Set to our current system
m_settingEventSystem = true; m_settingEventSystem = true;
EventSystem.current = UIManager.EventSys; EventSystem.current = UIManager.EventSys;
UIManager.EventSys.enabled = true;
InputManager.ActivateUIModule(); InputManager.ActivateUIModule();
m_settingEventSystem = false; m_settingEventSystem = false;
} }

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

@ -153,7 +153,7 @@ namespace UnityExplorer.UI.Modules
{ {
var name = UISyntaxHighlight.ParseFullSyntax(obj.GetActualType(), true); var name = UISyntaxHighlight.ParseFullSyntax(obj.GetActualType(), true);
if (unityObj && m_context != SearchContext.Singleton && m_context != SearchContext.StaticClass) if (unityObj && m_context != SearchContext.Singleton)
{ {
if (unityObj && !string.IsNullOrEmpty(unityObj.name)) if (unityObj && !string.IsNullOrEmpty(unityObj.name))
name += $": {unityObj.name}"; name += $": {unityObj.name}";
@ -229,6 +229,7 @@ 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 ~~~~~
@ -300,8 +301,8 @@ namespace UnityExplorer.UI.Modules
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{ {
// All non-static classes // Search all non-static, non-enum classes.
foreach (var type in asm.TryGetTypes().Where(it => !it.IsSealed && !it.IsAbstract)) foreach (var type in asm.TryGetTypes().Where(it => !(it.IsSealed && it.IsAbstract) && !it.IsEnum))
{ {
try try
{ {
@ -335,7 +336,7 @@ namespace UnityExplorer.UI.Modules
if (instance != null) if (instance != null)
{ {
instances.Add(instance); instances.Add(instance);
continue; break;
} }
} }
} }

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

@ -81,40 +81,73 @@ 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() private static void LoadBundle()
{ {
var bundlePath = ExplorerCore.EXPLORER_FOLDER + @"\explorerui.bundle"; AssetBundle bundle = null;
if (File.Exists(bundlePath))
try
{ {
var bundle = AssetBundle.LoadFromFile(bundlePath); bundle = LoadExplorerUi("modern");
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");
} }
else catch
{ {
ExplorerCore.LogWarning("Could not find the ExplorerUI Bundle! It should exist at '" + bundlePath + "'"); ExplorerCore.Log("Failed to load modern ExplorerUI Bundle, falling back to legacy");
try
{
bundle = LoadExplorerUi("legacy");
}
catch
{
// ignored
}
}
if (bundle == null)
{
ExplorerCore.LogWarning("Could not load the ExplorerUI Bundle!");
return; 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()
@ -133,7 +166,7 @@ namespace UnityExplorer.UI
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);

View File

@ -25,9 +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:\source\Unity Projects\Test\_BUILD</BIECppGameFolder> <BIECppGameFolder>E:\source\Unity Projects\Test\_BUILD</BIECppGameFolder>
<!-- Set this to the MelonLoader Il2Cpp Game folder, without the ending '\' character. --> <!-- Set this to the MelonLoader Il2Cpp Game folder, without the ending '\' character. -->
<MLCppGameFolder>D:\source\Unity Projects\Test\_BUILD</MLCppGameFolder> <MLCppGameFolder>E:\source\Unity Projects\Test\_BUILD</MLCppGameFolder>
<NuGetPackageImportStamp> <NuGetPackageImportStamp>
</NuGetPackageImportStamp> </NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
@ -68,6 +68,24 @@
<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"> <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> <HintPath>packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll</HintPath>
@ -217,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" />
@ -293,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

@ -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
} }