Compare commits

...

17 Commits
3.0.7 ... 3.1.7

Author SHA1 Message Date
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
25 changed files with 623 additions and 215 deletions

View File

@ -28,9 +28,6 @@
| [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) | | [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) |
<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
<p align="center"> <p align="center">
@ -52,15 +49,14 @@
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\unhollowed\base\` 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`
## Mod Config ## Mod Config

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()
{ {
@ -22,7 +22,7 @@ namespace UnityExplorer.Config
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 Save_Logs_To_Disk = true;

View File

@ -1,5 +1,6 @@
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;
@ -16,10 +17,31 @@ namespace UnityExplorer
public class ExplorerCore public class ExplorerCore
{ {
public const string NAME = "UnityExplorer"; public const string NAME = "UnityExplorer";
public const string VERSION = "3.0.6"; public const string VERSION = "3.1.7";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer"; public const string GUID = "com.sinai.unityexplorer";
#if ML
public const string EXPLORER_FOLDER = @"Mods\UnityExplorer"; public const string EXPLORER_FOLDER = @"Mods\UnityExplorer";
#elif BIE
public static string EXPLORER_FOLDER = Path.Combine(BepInEx.Paths.ConfigPath, "UnityExplorer");
#elif STANDALONE
public static string EXPLORER_FOLDER
{
get
{
if (s_explorerFolder == null)
{
s_explorerFolder = (new Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath;
s_explorerFolder = Uri.UnescapeDataString(s_explorerFolder);
s_explorerFolder = Path.GetDirectoryName(s_explorerFolder);
}
return s_explorerFolder;
}
}
private static string s_explorerFolder;
#endif
public static ExplorerCore Instance { get; private set; } public static ExplorerCore Instance { get; private set; }
@ -161,6 +183,12 @@ namespace UnityExplorer
} }
} }
#if STANDALONE
public static Action<string> OnLogMessage;
public static Action<string> OnLogWarning;
public static Action<string> OnLogError;
#endif
public static void Log(object message, bool unity = false) public static void Log(object message, bool unity = false)
{ {
DebugConsole.Log(message?.ToString()); DebugConsole.Log(message?.ToString());
@ -170,8 +198,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 +214,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 +230,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

@ -15,6 +15,16 @@ namespace UnityExplorer.Helpers
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)
@ -60,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

@ -111,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)

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

@ -109,21 +109,12 @@ namespace UnityExplorer.Inspectors
internal static void RaycastWorld(Vector2 mousePos) internal static void RaycastWorld(Vector2 mousePos)
{ {
var ray = UnityHelpers.MainCamera.ScreenPointToRay(mousePos); var ray = UnityHelpers.MainCamera.ScreenPointToRay(mousePos);
var casts = Physics.RaycastAll(ray, 1000f); Physics.Raycast(ray, out RaycastHit hit, 1000f);
if (casts.Length > 0) if (hit.transform)
{ {
foreach (var cast in casts) var obj = hit.transform.gameObject;
{ OnHitGameObject(obj);
if (cast.transform)
{
var obj = cast.transform.gameObject;
OnHitGameObject(obj);
break;
}
}
} }
else else
{ {

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

@ -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
{ {
@ -70,8 +72,8 @@ namespace UnityExplorer.Inspectors.Reflection
// WIP // WIP
//if (m_targetType == typeof(Texture2D)) if (m_targetType == typeof(Texture2D))
// ConstructTextureHelper(); ConstructTextureHelper();
} }
internal void ConstructCompHelper(GameObject rowObj) internal void ConstructCompHelper(GameObject rowObj)
@ -136,94 +138,176 @@ namespace UnityExplorer.Inspectors.Reflection
//btn.onClick.AddListener(() => { InspectorManager.Instance.Inspect(comp.gameObject); }); //btn.onClick.AddListener(() => { InspectorManager.Instance.Inspect(comp.gameObject); });
} }
//internal bool showingTextureHelper; internal bool showingTextureHelper;
//internal bool constructedTextureViewer; internal bool constructedTextureViewer;
//internal void ConstructTextureHelper() internal GameObject m_textureViewerObj;
//{
// 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 showBtnObj = UIFactory.CreateButton(rowObj, new Color(0.2f, 0.2f, 0.2f)); internal void ConstructTextureHelper()
// var showBtnLayout = showBtnObj.AddComponent<LayoutElement>(); {
// showBtnLayout.minWidth = 50; var rowObj = UIFactory.CreateHorizontalGroup(Content, new Color(0.1f, 0.1f, 0.1f));
// showBtnLayout.flexibleWidth = 0; var rowLayout = rowObj.AddComponent<LayoutElement>();
// var showText = showBtnObj.GetComponentInChildren<Text>(); rowLayout.minHeight = 25;
// showText.text = "Show"; rowLayout.flexibleHeight = 0;
// var showBtn = showBtnObj.GetComponent<Button>(); var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.childForceExpandHeight = true;
rowGroup.childForceExpandWidth = false;
rowGroup.padding.top = 3;
rowGroup.padding.left = 3;
rowGroup.padding.bottom = 3;
rowGroup.padding.right = 3;
rowGroup.spacing = 5;
// var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft); var showBtnObj = UIFactory.CreateButton(rowObj, new Color(0.2f, 0.6f, 0.2f));
// var labelText = labelObj.GetComponent<Text>(); var showBtnLayout = showBtnObj.AddComponent<LayoutElement>();
// labelText.text = "Texture Viewer"; showBtnLayout.minWidth = 50;
showBtnLayout.flexibleWidth = 0;
var showText = showBtnObj.GetComponentInChildren<Text>();
showText.text = "Show";
var showBtn = showBtnObj.GetComponent<Button>();
// var textureViewerObj = UIFactory.CreateScrollView(Content, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f)); var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
// var viewerGroup = scrollContent.GetComponent<VerticalLayoutGroup>(); var labelText = labelObj.GetComponent<Text>();
// viewerGroup.childForceExpandHeight = false; labelText.text = "Texture Viewer";
// viewerGroup.childForceExpandWidth = false;
// viewerGroup.childControlHeight = true;
// viewerGroup.childControlWidth = true;
// var mainLayout = textureViewerObj.GetComponent<LayoutElement>();
// mainLayout.flexibleHeight = -1;
// mainLayout.flexibleWidth = 2000;
// mainLayout.minHeight = 25;
// textureViewerObj.SetActive(false); var textureViewerObj = UIFactory.CreateScrollView(Content, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f));
var viewerGroup = scrollContent.GetComponent<VerticalLayoutGroup>();
viewerGroup.childForceExpandHeight = false;
viewerGroup.childForceExpandWidth = false;
viewerGroup.childControlHeight = true;
viewerGroup.childControlWidth = true;
var mainLayout = textureViewerObj.GetComponent<LayoutElement>();
mainLayout.flexibleHeight = 9999;
mainLayout.flexibleWidth = 9999;
mainLayout.minHeight = 100;
// showBtn.onClick.AddListener(() => textureViewerObj.SetActive(false);
// {
// showingTextureHelper = !showingTextureHelper;
// if (showingTextureHelper) m_textureViewerObj = textureViewerObj;
// {
// if (!constructedTextureViewer)
// ConstructTextureViewerArea(scrollContent);
// showText.text = "Hide"; showBtn.onClick.AddListener(() =>
// textureViewerObj.SetActive(true); {
// } showingTextureHelper = !showingTextureHelper;
// else
// {
// showText.text = "Show";
// textureViewerObj.SetActive(false);
// }
// });
//}
//internal void ConstructTextureViewerArea(GameObject parent) if (showingTextureHelper)
//{ {
// constructedTextureViewer = true; if (!constructedTextureViewer)
ConstructTextureViewerArea(scrollContent);
// var tex = Target as Texture2D; showText.text = "Hide";
ToggleTextureViewer(true);
}
else
{
showText.text = "Show";
ToggleTextureViewer(false);
}
});
}
// if (!tex) internal void ConstructTextureViewerArea(GameObject parent)
// { {
// ExplorerCore.LogWarning("Could not cast the target instance to Texture2D!"); constructedTextureViewer = true;
// return;
// }
// var imageObj = UIFactory.CreateUIObject("TextureViewerImage", parent, new Vector2(1, 1)); var tex = Target as Texture2D;
// var image = imageObj.AddComponent<Image>(); #if CPP
// var sprite = UIManager.CreateSprite(tex); if (!tex)
// image.sprite = sprite; tex = (Target as Il2CppSystem.Object).TryCast<Texture2D>();
#endif
// var fitter = imageObj.AddComponent<ContentSizeFitter>(); if (!tex)
// fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; {
// //fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize; ExplorerCore.LogWarning("Could not cast the target instance to Texture2D! Maybe its null or destroyed?");
return;
}
// var imageLayout = imageObj.AddComponent<LayoutElement>(); // Save helper
// imageLayout.preferredHeight = sprite.rect.height;
// imageLayout.preferredWidth = sprite.rect.width; 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

@ -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,33 @@ 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 +332,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)
{ {
@ -363,6 +367,10 @@ namespace UnityExplorer.Inspectors
#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;
@ -423,7 +431,7 @@ namespace UnityExplorer.Inspectors
ConstructFilterArea(); ConstructFilterArea();
ConstructOptionsArea(); ConstructUpdateRow();
} }
internal void ConstructFilterArea() internal void ConstructFilterArea()
@ -444,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));
@ -540,7 +550,7 @@ 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>();
@ -551,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));
@ -578,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.05f, 0.05f, 0.05f)); 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

@ -5,6 +5,7 @@ using UnityEngine;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using UnityExplorer.Unstrip;
#if CPP #if CPP
using UnhollowerBaseLib; using UnhollowerBaseLib;
using UnityExplorer.Helpers; using UnityExplorer.Helpers;
@ -121,15 +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<string, string> CppDictTest;
public static Il2CppSystem.Collections.Generic.Dictionary<int, float> CppDictTest2; //public static Il2CppSystem.Collections.Generic.Dictionary<int, float> CppDictTest2;
#endif #endif
public TestClass() public TestClass()
@ -156,35 +157,35 @@ namespace UnityExplorer.Tests
CppStringTest.Add("1"); CppStringTest.Add("1");
CppStringTest.Add("2"); CppStringTest.Add("2");
CppDictTest = new Il2CppSystem.Collections.Generic.Dictionary<string, string>(); //CppDictTest = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
CppDictTest.Add("key1", "value1"); //CppDictTest.Add("key1", "value1");
CppDictTest.Add("key2", "value2"); //CppDictTest.Add("key2", "value2");
CppDictTest.Add("key3", "value3"); //CppDictTest.Add("key3", "value3");
CppDictTest2 = new Il2CppSystem.Collections.Generic.Dictionary<int, float>(); //CppDictTest2 = new Il2CppSystem.Collections.Generic.Dictionary<int, float>();
CppDictTest2.Add(0, 0.5f); //CppDictTest2.Add(0, 0.5f);
CppDictTest2.Add(1, 0.5f); //CppDictTest2.Add(1, 0.5f);
CppDictTest2.Add(2, 0.5f); //CppDictTest2.Add(2, 0.5f);
#endif #endif
} }
private void TextureSpriteTest() private void TextureSpriteTest()
{ {
//TestTexture = UIManager.MakeSolidTexture(Color.white, 1000, 600); TestTexture = new Texture2D(32, 32, TextureFormat.ARGB32, false)
//TestTexture = new Texture(); {
//TestTexture.name = "TestTexture"; name = "TestTexture"
};
TestSprite = ImageConversionUnstrip.CreateSprite(TestTexture);
//var r = new Rect(0, 0, TestTexture.width, TestTexture.height); GameObject.DontDestroyOnLoad(TestTexture);
//var v2 = Vector2.zero; GameObject.DontDestroyOnLoad(TestSprite);
//var v4 = Vector4.zero;
//TestSprite = Sprite.CreateSprite_Injected((Texture2D)TestTexture, ref r, ref v2, 100f, 0u, SpriteMeshType.Tight, ref v4, false);
//GameObject.DontDestroyOnLoad(TestTexture); // test loading a tex from file
//GameObject.DontDestroyOnLoad(TestSprite); if (System.IO.File.Exists(@"D:\Downloads\test.png"))
{
//// test loading a tex from file var dataToLoad = System.IO.File.ReadAllBytes(@"D:\Downloads\test.png");
//var dataToLoad = System.IO.File.ReadAllBytes(@"Mods\UnityExplorer\Tex_Nemundis_Nebula.png"); ExplorerCore.Log($"Tex load success: {TestTexture.LoadImage(dataToLoad, false)}");
//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

View File

@ -87,12 +87,6 @@ namespace UnityExplorer.UI
new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_visible))), new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_visible))),
true); true);
#if BIE
#if CPP
// temporarily disabling this patch in BepInEx il2cpp as it's causing a crash in some games.
return;
#endif
#endif
TryPatch(typeof(EventSystem), TryPatch(typeof(EventSystem),
"current", "current",
new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_EventSystem_set_current))), new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_EventSystem_set_current))),
@ -111,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);
@ -164,11 +160,25 @@ namespace UnityExplorer.UI
public static void SetEventSystem() public static void SetEventSystem()
{ {
// temp disabled for new InputSystem
if (InputManager.CurrentType == InputType.InputSystem) if (InputManager.CurrentType == InputType.InputSystem)
return; 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;
EventSystem.current = UIManager.EventSys; EventSystem.current = UIManager.EventSys;
UIManager.EventSys.enabled = true;
InputManager.ActivateUIModule(); InputManager.ActivateUIModule();
m_settingEventSystem = false; m_settingEventSystem = false;
} }
@ -180,6 +190,9 @@ namespace UnityExplorer.UI
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

@ -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 && m_context != SearchContext.StaticClass)
{
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())
{
// All non-static classes
foreach (var type in asm.TryGetTypes().Where(it => !it.IsSealed && !it.IsAbstract))
{
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);
continue;
}
}
}
}
catch { }
}
}
m_results = instances.ToArray();
}
internal void UnityObjectSearch()
{
Type searchType = null; Type searchType = null;
switch (m_context) switch (m_context)
{ {
@ -305,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:
@ -325,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()
@ -490,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));
@ -601,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

@ -45,7 +45,6 @@ namespace UnityExplorer.UI
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();
@ -53,12 +52,9 @@ namespace UnityExplorer.UI
if (EventSys) if (EventSys)
{ {
if (EventSystem.current != EventSys) if (EventSystem.current != EventSys)
{
ForceUnlockCursor.SetEventSystem(); ForceUnlockCursor.SetEventSystem();
}
#if CPP #if CPP
// Fix for games which override the InputModule pointer events (eg, VRChat) // Some IL2CPP games behave weird with multiple UI Input Systems, some fixes for them.
var evt = InputManager.InputPointerEvent; var evt = InputManager.InputPointerEvent;
if (evt != null) if (evt != null)
{ {
@ -69,9 +65,7 @@ namespace UnityExplorer.UI
} }
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++)
{ {
@ -94,33 +88,66 @@ namespace UnityExplorer.UI
} }
} }
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()
@ -139,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

@ -43,14 +43,11 @@ 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 // Sprite Sprite.Create
@ -70,5 +67,16 @@ namespace UnityExplorer.Unstrip
return new Sprite(ptr); return new Sprite(ptr);
} }
#endif #endif
// Simpler CreateSprite helper
public static Sprite CreateSprite(Texture2D texture)
{
#if CPP
return CreateSprite(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero, 100f, 0u, Vector4.zero);
#else
return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
#endif
}
} }
} }