mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-23 00:52:31 +08:00
Compare commits
57 Commits
Author | SHA1 | Date | |
---|---|---|---|
fae85c2968 | |||
fc8fa9aa7a | |||
bcf9a801a9 | |||
20298aa47b | |||
e2c1c186c3 | |||
9ce6508828 | |||
506e75c5fe | |||
a2f22051f0 | |||
4e3203a91b | |||
a411ce2dba | |||
48132b3d46 | |||
e49ed3028f | |||
31dd54d25c | |||
3cfdd6fa43 | |||
1fa1283a68 | |||
afa4135b67 | |||
48d1cf574d | |||
df0abbc847 | |||
5c9dcb1d43 | |||
602770d980 | |||
f26371f95f | |||
a673c39f4a | |||
40583cae3d | |||
20018a9ba9 | |||
dabf92a1a5 | |||
b7e275f02c | |||
f393e0d706 | |||
ab8acc9e84 | |||
66c30ee70e | |||
ddd271c00d | |||
30fe9e4dde | |||
fa3a436037 | |||
ca27d2b20f | |||
4315e0c547 | |||
3e19e74329 | |||
5a3ffebadc | |||
6e6b6239d8 | |||
03c8e5a8bd | |||
44f7209843 | |||
734e45cf9f | |||
97838e0b3a | |||
304b47f898 | |||
3d1fcbcd9f | |||
36fc17aa43 | |||
adfa29e63c | |||
3ffdcea73b | |||
dfd55260a8 | |||
29c78dc5a6 | |||
bf59d9d6cd | |||
bb0c59534a | |||
802bb722bc | |||
9ca992b0d7 | |||
5f3b3a6870 | |||
f5bce439cb | |||
e2b2c9038a | |||
fbefccd6b7 | |||
271c91f0d0 |
13
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
13
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -24,10 +24,8 @@ body:
|
||||
- BepInEx IL2CPP
|
||||
- BepInEx 6.X Mono
|
||||
- BepInEx 5.X Mono
|
||||
- MelonLoader 0.4+ IL2CPP
|
||||
- MelonLoader 0.4+ Mono
|
||||
- MelonLoader 0.3 IL2CPP
|
||||
- MelonLoader 0.3 Mono
|
||||
- MelonLoader IL2CPP
|
||||
- MelonLoader Mono
|
||||
- Standalone IL2CPP
|
||||
- Standalone Mono
|
||||
validations:
|
||||
@ -50,12 +48,13 @@ body:
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Log output
|
||||
label: Relevant log output
|
||||
description: |
|
||||
Please copy and paste your mod loader's log output.
|
||||
Please copy and paste any relevant logs and stack traces.
|
||||
* Unity log: `%userprofile%\AppData\LocalLow\{Company}\{Game}\Player.log` or `output_log.txt`
|
||||
* BepInEx: `BepInEx\LogOutput.log`
|
||||
* MelonLoader: `MelonLoader\latest.log`
|
||||
* Standalone: `{DLL_Location}\UnityExplorer\Logs\` (pick the most recent one)
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
required: false
|
13
.github/ISSUE_TEMPLATE/other.yaml
vendored
Normal file
13
.github/ISSUE_TEMPLATE/other.yaml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
name: Other
|
||||
description: Something else?
|
||||
title: "[Other]: "
|
||||
labels: [Other]
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the issue
|
||||
description: |
|
||||
Please describe the issue in as much detail as possible.
|
||||
validations:
|
||||
required: true
|
16
.github/workflows/dotnet.yml
vendored
16
.github/workflows/dotnet.yml
vendored
@ -79,22 +79,6 @@ jobs:
|
||||
name: UnityExplorer.MelonLoader.Mono
|
||||
path: ./Release/UnityExplorer.MelonLoader.Mono/*
|
||||
|
||||
# MelonLoader 0.3.0 Il2Cpp
|
||||
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_MLLegacy_Cpp
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.MelonLoader_Legacy.Il2Cpp
|
||||
path: ./Release/UnityExplorer.MelonLoader_Legacy.Il2Cpp/*
|
||||
|
||||
# MelonLoader 0.3.0 Mono
|
||||
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_MLLegacy_Mono
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.MelonLoader_Legacy.Mono
|
||||
path: ./Release/UnityExplorer.MelonLoader_Legacy.Mono/*
|
||||
|
||||
# Standalone Il2Cpp
|
||||
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_STANDALONE_Cpp
|
||||
|
||||
|
@ -32,8 +32,7 @@
|
||||
|
||||
| Release | IL2CPP | Mono |
|
||||
| ------- | ------ | ---- |
|
||||
| ML 0.4.0 | ✅ [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) |
|
||||
| ML 0.3.0 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Mono.zip) |
|
||||
| ML 0.4+ | ✅ [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) |
|
||||
|
||||
1. Take the `UnityExplorer.ML.[version].dll` file and put it in the `Mods\` folder created by MelonLoader.
|
||||
|
||||
|
Binary file not shown.
Submodule lib/Il2CppAssemblyUnhollower updated: 0911fdaca6...0099c25069
Binary file not shown.
Binary file not shown.
@ -121,16 +121,15 @@ namespace UnityExplorer.CSConsole
|
||||
{
|
||||
while (input.Length - 1 >= matchEndIdx)
|
||||
{
|
||||
matchEndIdx++;
|
||||
if (IsNewLine(input[matchEndIdx]))
|
||||
break;
|
||||
matchEndIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
// check caretIdx to determine inStringOrComment state
|
||||
if (caretIdx >= match.startIndex && (caretIdx <= matchEndIdx || (caretIdx >= input.Length && matchEndIdx >= input.Length - 1)))
|
||||
if (caretIdx >= match.startIndex && (caretIdx <= (matchEndIdx+1) || (caretIdx >= input.Length && matchEndIdx >= input.Length - 1)))
|
||||
caretInStringOrComment = match.isStringOrComment;
|
||||
|
||||
}
|
||||
|
||||
// Append trailing unhighlighted input
|
||||
|
@ -7,12 +7,6 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
|
||||
/*
|
||||
Welcome to the UnityExplorer C# Console!
|
||||
Use the Help dropdown to see detailed examples of how to use this console.
|
||||
To see your output, use the Log panel or a Console Log window.
|
||||
*/
|
||||
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
public class ScriptInteraction : InteractiveBase
|
||||
@ -76,4 +70,4 @@ namespace UnityExplorer.CSConsole
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ namespace UnityExplorer.CacheObject
|
||||
public CacheConfigEntry(IConfigElement configElement)
|
||||
{
|
||||
this.RefConfigElement = configElement;
|
||||
this.FallbackType = configElement.ElementType;
|
||||
|
||||
this.NameLabelText = $"<color=cyan>{configElement.Name}</color>" +
|
||||
$"\r\n<color=grey><i>{configElement.Description}</i></color>";
|
||||
|
||||
this.FallbackType = configElement.ElementType;
|
||||
this.NameLabelTextRaw = string.Empty;
|
||||
|
||||
configElement.OnValueChangedNotify += UpdateValueFromSource;
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ namespace UnityExplorer.CacheObject
|
||||
var kvpCell = cell as CacheKeyValuePairCell;
|
||||
|
||||
kvpCell.NameLabel.text = $"{DictIndex}:";
|
||||
kvpCell.HiddenNameLabel.Text = "";
|
||||
kvpCell.Image.color = DictIndex % 2 == 0 ? CacheListEntryCell.EvenColor : CacheListEntryCell.OddColor;
|
||||
|
||||
if (KeyInputWanted)
|
||||
|
@ -28,6 +28,7 @@ namespace UnityExplorer.CacheObject
|
||||
var listCell = cell as CacheListEntryCell;
|
||||
|
||||
listCell.NameLabel.text = $"{ListIndex}:";
|
||||
listCell.HiddenNameLabel.Text = "";
|
||||
listCell.Image.color = ListIndex % 2 == 0 ? CacheListEntryCell.EvenColor : CacheListEntryCell.OddColor;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ namespace UnityExplorer.CacheObject
|
||||
this.Owner = inspector;
|
||||
this.NameLabelText = SignatureHighlighter.Parse(member.DeclaringType, false, member);
|
||||
this.NameForFiltering = $"{member.DeclaringType.Name}.{member.Name}";
|
||||
this.NameLabelTextRaw = NameForFiltering;
|
||||
}
|
||||
|
||||
public override void ReleasePooledObjects()
|
||||
|
@ -30,15 +30,14 @@ namespace UnityExplorer.CacheObject
|
||||
try
|
||||
{
|
||||
var methodInfo = MethodInfo;
|
||||
|
||||
if (methodInfo.IsGenericMethod)
|
||||
methodInfo = MethodInfo.MakeGenericMethod(Evaluator.TryParseGenericArguments());
|
||||
|
||||
if (Arguments.Length > 0)
|
||||
return methodInfo.Invoke(DeclaringInstance, Evaluator.TryParseArguments());
|
||||
|
||||
var ret = methodInfo.Invoke(DeclaringInstance, ArgumentUtility.EmptyArgs);
|
||||
|
||||
object ret;
|
||||
if (HasArguments)
|
||||
ret = methodInfo.Invoke(DeclaringInstance, Evaluator.TryParseArguments());
|
||||
else
|
||||
ret = methodInfo.Invoke(DeclaringInstance, ArgumentUtility.EmptyArgs);
|
||||
HadException = false;
|
||||
LastException = null;
|
||||
return ret;
|
||||
|
@ -47,6 +47,7 @@ namespace UnityExplorer.CacheObject
|
||||
public bool SubContentShowWanted { get; private set; }
|
||||
|
||||
public string NameLabelText { get; protected set; }
|
||||
public string NameLabelTextRaw { get; protected set; }
|
||||
public string ValueLabelText { get; protected set; }
|
||||
|
||||
public abstract bool ShouldAutoEvaluate { get; }
|
||||
@ -260,6 +261,8 @@ namespace UnityExplorer.CacheObject
|
||||
public virtual void SetDataToCell(CacheObjectCell cell)
|
||||
{
|
||||
cell.NameLabel.text = NameLabelText;
|
||||
if (cell.HiddenNameLabel != null)
|
||||
cell.HiddenNameLabel.Text = NameLabelTextRaw;
|
||||
cell.ValueLabel.gameObject.SetActive(true);
|
||||
|
||||
cell.SubContentHolder.gameObject.SetActive(SubContentShowWanted);
|
||||
|
@ -45,6 +45,7 @@ namespace UnityExplorer.CacheObject.Views
|
||||
public LayoutElement RightGroupLayout;
|
||||
|
||||
public Text NameLabel;
|
||||
public InputFieldRef HiddenNameLabel;
|
||||
public Text TypeLabel;
|
||||
public Text ValueLabel;
|
||||
public Toggle Toggle;
|
||||
@ -116,8 +117,19 @@ namespace UnityExplorer.CacheObject.Views
|
||||
|
||||
NameLabel = UIFactory.CreateLabel(horiRow, "NameLabel", "<notset>", TextAnchor.MiddleLeft);
|
||||
NameLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
UIFactory.SetLayoutElement(NameLabel.gameObject, minHeight: 25, minWidth: 20, flexibleHeight: 300, flexibleWidth: 0);
|
||||
NameLayout = NameLabel.GetComponent<LayoutElement>();
|
||||
NameLayout = UIFactory.SetLayoutElement(NameLabel.gameObject, minHeight: 25, minWidth: 20, flexibleHeight: 300, flexibleWidth: 0);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(NameLabel.gameObject, true, true, true, true);
|
||||
|
||||
HiddenNameLabel = UIFactory.CreateInputField(NameLabel.gameObject, "HiddenNameLabel", "");
|
||||
var hiddenRect = HiddenNameLabel.Component.GetComponent<RectTransform>();
|
||||
hiddenRect.anchorMin = Vector2.zero;
|
||||
hiddenRect.anchorMax = Vector2.one;
|
||||
HiddenNameLabel.Component.readOnly = true;
|
||||
HiddenNameLabel.Component.lineType = UnityEngine.UI.InputField.LineType.MultiLineNewline;
|
||||
HiddenNameLabel.Component.textComponent.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
HiddenNameLabel.Component.gameObject.GetComponent<Image>().color = Color.clear;
|
||||
HiddenNameLabel.Component.textComponent.color = Color.clear;
|
||||
UIFactory.SetLayoutElement(HiddenNameLabel.Component.gameObject, minHeight: 25, minWidth: 20, flexibleHeight: 300, flexibleWidth: 0);
|
||||
|
||||
// Right vertical group
|
||||
|
||||
|
@ -116,7 +116,7 @@ namespace UnityExplorer.Core.Config
|
||||
Reflection_Signature_Blacklist = new ConfigElement<string>("Member Signature Blacklist",
|
||||
"Use this to blacklist certain member signatures if they are known to cause a crash or other issues.\r\n" +
|
||||
"Seperate signatures with a semicolon ';'.\r\n" +
|
||||
"For example, to blacklist Camera.main, you would add 'Camera.main;'",
|
||||
"For example, to blacklist Camera.main, you would add 'UnityEngine.Camera.main;'",
|
||||
"");
|
||||
|
||||
// Internal configs (panel save data)
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
@ -6,8 +7,6 @@ using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.UI;
|
||||
using BF = System.Reflection.BindingFlags;
|
||||
|
||||
|
||||
namespace UnityExplorer.Core.Input
|
||||
{
|
||||
@ -149,18 +148,97 @@ namespace UnityExplorer.Core.Input
|
||||
|
||||
// Patches
|
||||
|
||||
private static void SetupPatches()
|
||||
public static void SetupPatches()
|
||||
{
|
||||
try
|
||||
{
|
||||
ExplorerCore.Loader.SetupCursorPatches();
|
||||
PrefixPropertySetter(typeof(Cursor),
|
||||
"lockState",
|
||||
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_set_lockState))));
|
||||
|
||||
PrefixPropertySetter(typeof(Cursor),
|
||||
"visible",
|
||||
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_set_visible))));
|
||||
|
||||
PrefixPropertySetter(typeof(EventSystem),
|
||||
"current",
|
||||
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_EventSystem_set_current))));
|
||||
|
||||
PrefixMethod(typeof(EventSystem),
|
||||
"SetSelectedGameObject",
|
||||
// some games use a modified version of uGUI that includes this extra int argument on this method.
|
||||
new Type[] { typeof(GameObject), typeof(BaseEventData), typeof(int) },
|
||||
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_EventSystem_SetSelectedGameObject))),
|
||||
// most games use these arguments, we'll use them as our "backup".
|
||||
new Type[] { typeof(GameObject), typeof(BaseEventData) });
|
||||
|
||||
//// Not sure if this one is needed.
|
||||
//PrefixMethod(typeof(PointerInputModule),
|
||||
// "ClearSelection",
|
||||
// new Type[0],
|
||||
// new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_PointerInputModule_ClearSelection))));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrefixMethod(Type type, string method, Type[] arguments, HarmonyMethod prefix, Type[] backupArgs = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var methodInfo = type.GetMethod(method, ReflectionUtility.FLAGS, null, arguments, null);
|
||||
if (methodInfo == null)
|
||||
{
|
||||
if (backupArgs != null)
|
||||
methodInfo = type.GetMethod(method, ReflectionUtility.FLAGS, null, backupArgs, null);
|
||||
|
||||
if (methodInfo == null)
|
||||
throw new MissingMethodException($"Could not find method for patching - '{type.FullName}.{method}'!");
|
||||
}
|
||||
|
||||
var processor = ExplorerCore.Harmony.CreateProcessor(methodInfo);
|
||||
processor.AddPrefix(prefix);
|
||||
processor.Patch();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log($"Exception setting up Cursor patches: {e.GetType()}, {e.Message}");
|
||||
ExplorerCore.LogWarning($"Unable to patch {type.Name}.{method}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrefixPropertySetter(Type type, string property, HarmonyMethod prefix)
|
||||
{
|
||||
try
|
||||
{
|
||||
var processor = ExplorerCore.Harmony.CreateProcessor(type.GetProperty(property, ReflectionUtility.FLAGS).GetSetMethod());
|
||||
processor.AddPrefix(prefix);
|
||||
processor.Patch();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log($"Unable to patch {type.Name}.set_{property}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent setting non-UnityExplorer objects as selected when menu is open
|
||||
|
||||
public static bool Prefix_EventSystem_SetSelectedGameObject(GameObject __0)
|
||||
{
|
||||
if (!UIManager.ShowMenu || !UIManager.CanvasRoot)
|
||||
return true;
|
||||
|
||||
return __0 && __0.transform.root.gameObject.GetInstanceID() == UIManager.CanvasRoot.GetInstanceID();
|
||||
}
|
||||
|
||||
//public static bool Prefix_PointerInputModule_ClearSelection()
|
||||
//{
|
||||
// return !(UIManager.ShowMenu && UIManager.CanvasRoot);
|
||||
//}
|
||||
|
||||
// Force EventSystem.current to be UnityExplorer's when menu is open
|
||||
|
||||
public static void Prefix_EventSystem_set_current(ref EventSystem value)
|
||||
{
|
||||
if (!settingEventSystem && value)
|
||||
|
@ -12,6 +12,8 @@ namespace UnityExplorer.Core.Input
|
||||
{
|
||||
public InputSystem()
|
||||
{
|
||||
SetupSupportedDevices();
|
||||
|
||||
m_kbCurrentProp = TKeyboard.GetProperty("current");
|
||||
m_kbIndexer = TKeyboard.GetProperty("Item", new Type[] { TKey });
|
||||
|
||||
@ -32,7 +34,37 @@ namespace UnityExplorer.Core.Input
|
||||
.GetMethod("ReadValue");
|
||||
}
|
||||
|
||||
#region reflection cache
|
||||
internal static void SetupSupportedDevices()
|
||||
{
|
||||
try
|
||||
{
|
||||
// typeof(InputSystem)
|
||||
Type TInputSystem = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputSystem");
|
||||
// InputSystem.settings
|
||||
var settings = TInputSystem.GetProperty("settings", BindingFlags.Public | BindingFlags.Static).GetValue(null, null);
|
||||
// typeof(InputSettings)
|
||||
Type TSettings = settings.GetActualType();
|
||||
// InputSettings.supportedDevices
|
||||
PropertyInfo supportedProp = TSettings.GetProperty("supportedDevices", BindingFlags.Public | BindingFlags.Instance);
|
||||
var supportedDevices = supportedProp.GetValue(settings, null);
|
||||
// An empty supportedDevices list means all devices are supported.
|
||||
#if CPP
|
||||
// weird hack for il2cpp, use the implicit operator and cast Il2CppStringArray to ReadOnlyArray<string>
|
||||
var args = new object[] { new UnhollowerBaseLib.Il2CppStringArray(0) };
|
||||
var method = supportedDevices.GetActualType().GetMethod("op_Implicit", BindingFlags.Static | BindingFlags.Public);
|
||||
supportedProp.SetValue(settings, method.Invoke(null, args), null);
|
||||
#else
|
||||
supportedProp.SetValue(settings, Activator.CreateInstance(supportedDevices.GetActualType(), new object[] { new string[0] }), null);
|
||||
#endif
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception setting up InputSystem.settings.supportedDevices list!");
|
||||
ExplorerCore.Log(ex);
|
||||
}
|
||||
}
|
||||
|
||||
#region reflection cache
|
||||
|
||||
public static Type TKeyboard => m_tKeyboard ?? (m_tKeyboard = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.Keyboard"));
|
||||
private static Type m_tKeyboard;
|
||||
@ -73,7 +105,7 @@ namespace UnityExplorer.Core.Input
|
||||
private static object m_scrollInfo;
|
||||
private static PropertyInfo m_scrollDeltaProp;
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
public Vector2 MousePosition
|
||||
{
|
||||
@ -138,6 +170,8 @@ namespace UnityExplorer.Core.Input
|
||||
|
||||
public bool GetMouseButtonDown(int btn)
|
||||
{
|
||||
if (CurrentMouse == null)
|
||||
return false;
|
||||
switch (btn)
|
||||
{
|
||||
case 0: return (bool)m_btnWasPressedProp.GetValue(LeftMouseButton, null);
|
||||
@ -149,6 +183,8 @@ namespace UnityExplorer.Core.Input
|
||||
|
||||
public bool GetMouseButton(int btn)
|
||||
{
|
||||
if (CurrentMouse == null)
|
||||
return false;
|
||||
switch (btn)
|
||||
{
|
||||
case 0: return (bool)m_btnIsPressedProp.GetValue(LeftMouseButton, null);
|
||||
|
@ -134,6 +134,9 @@ namespace UnityExplorer
|
||||
var type = obj.GetType();
|
||||
try
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
return type;
|
||||
|
||||
if (IsString(obj))
|
||||
return typeof(string);
|
||||
|
||||
@ -178,7 +181,8 @@ namespace UnityExplorer
|
||||
if (fullname.StartsWith("System."))
|
||||
fullname = $"Il2Cpp{fullname}";
|
||||
|
||||
AllTypes.TryGetValue(fullname, out Type monoType);
|
||||
if (!AllTypes.TryGetValue(fullname, out Type monoType))
|
||||
ExplorerCore.LogWarning($"Failed to get type by name '{fullname}'!");
|
||||
return monoType;
|
||||
}
|
||||
|
||||
@ -477,59 +481,38 @@ namespace UnityExplorer
|
||||
|
||||
#region Force-loading game modules
|
||||
|
||||
internal static string UnhollowedFolderPath => Path.GetFullPath(
|
||||
#if ML
|
||||
Path.Combine("MelonLoader", "Managed")
|
||||
#elif BIE
|
||||
Path.Combine(BepInEx.Paths.BepInExRootPath, "unhollowed")
|
||||
#else
|
||||
Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Modules")
|
||||
#endif
|
||||
);
|
||||
|
||||
// Helper for IL2CPP to try to make sure the Unhollowed game assemblies are actually loaded.
|
||||
|
||||
// Force loading all il2cpp modules
|
||||
|
||||
internal void TryLoadGameModules()
|
||||
{
|
||||
if (Directory.Exists(UnhollowedFolderPath))
|
||||
var dir = ExplorerCore.Loader.UnhollowedModulesFolder;
|
||||
if (Directory.Exists(dir))
|
||||
{
|
||||
var files = Directory.GetFiles(UnhollowedFolderPath);
|
||||
foreach (var filePath in files)
|
||||
{
|
||||
try
|
||||
{
|
||||
DoLoadModule(filePath, true);
|
||||
}
|
||||
catch //(Exception ex)
|
||||
{
|
||||
//ExplorerCore.LogWarning($"Failed to force-load module '{name}': {ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
foreach (var filePath in Directory.GetFiles(dir, "*.dll"))
|
||||
DoLoadModule(filePath);
|
||||
}
|
||||
else
|
||||
ExplorerCore.LogWarning($"Expected Unhollowed folder path does not exist: '{UnhollowedFolderPath}'");
|
||||
ExplorerCore.LogWarning($"Expected Unhollowed folder path does not exist: '{dir}'. " +
|
||||
$"If you are using the standalone release, you can specify the Unhollowed modules path when you call CreateInstance().");
|
||||
}
|
||||
|
||||
internal bool DoLoadModule(string fullPath, bool suppressWarning = false)
|
||||
internal bool DoLoadModule(string fullPath)
|
||||
{
|
||||
if (!File.Exists(fullPath))
|
||||
if (string.IsNullOrEmpty(fullPath) || !File.Exists(fullPath))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
Assembly.LoadFile(fullPath);
|
||||
//Assembly.Load(File.ReadAllBytes(fullPath));
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
catch //(Exception e)
|
||||
{
|
||||
if (!suppressWarning)
|
||||
Console.WriteLine($"Failed loading module '{Path.GetFileName(fullPath)}'! {e.ReflectionExToString()}");
|
||||
//ExplorerCore.LogWarning($"Failed loading module '{Path.GetFileName(fullPath)}'! {e.ReflectionExToString()}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -799,23 +782,24 @@ namespace UnityExplorer
|
||||
|
||||
// Some ugly reflection to use the il2cpp interface for the instance type
|
||||
|
||||
var type = list.GetType();
|
||||
var type = list.GetActualType();
|
||||
var key = type.AssemblyQualifiedName;
|
||||
|
||||
if (!getEnumeratorMethods.ContainsKey(key))
|
||||
{
|
||||
var method = type.GetMethod("System_Collections_IEnumerable_GetEnumerator", FLAGS)
|
||||
?? type.GetMethod("GetEnumerator");
|
||||
var method = type.GetMethod("GetEnumerator")
|
||||
?? type.GetMethod("System_Collections_IEnumerable_GetEnumerator", FLAGS);
|
||||
getEnumeratorMethods.Add(key, method);
|
||||
|
||||
// ensure the enumerator type is supported
|
||||
try
|
||||
{
|
||||
var test = getEnumeratorMethods[key].Invoke(list, null);
|
||||
test.GetType().GetMethod("MoveNext").Invoke(test, null);
|
||||
test.GetActualType().GetMethod("MoveNext").Invoke(test, null);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.Log($"IEnumerable failed to enumerate: {ex}");
|
||||
notSupportedTypes.Add(key);
|
||||
}
|
||||
}
|
||||
@ -824,7 +808,7 @@ namespace UnityExplorer
|
||||
throw new NotSupportedException($"The IEnumerable type '{type.FullName}' does not support MoveNext.");
|
||||
|
||||
cppEnumerator = getEnumeratorMethods[key].Invoke(list, null);
|
||||
var enumeratorType = cppEnumerator.GetType();
|
||||
var enumeratorType = cppEnumerator.GetActualType();
|
||||
|
||||
var enumInfoKey = enumeratorType.AssemblyQualifiedName;
|
||||
|
||||
@ -878,7 +862,7 @@ namespace UnityExplorer
|
||||
|
||||
try
|
||||
{
|
||||
var type = dictionary.GetType();
|
||||
var type = dictionary.GetActualType();
|
||||
|
||||
if (typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(type))
|
||||
{
|
||||
@ -888,22 +872,23 @@ namespace UnityExplorer
|
||||
|
||||
var keys = type.GetProperty("Keys").GetValue(dictionary, null);
|
||||
|
||||
var keyCollType = keys.GetType();
|
||||
var cacheKey = keys.GetType().AssemblyQualifiedName;
|
||||
var keyCollType = keys.GetActualType();
|
||||
var cacheKey = keyCollType.AssemblyQualifiedName;
|
||||
if (!getEnumeratorMethods.ContainsKey(cacheKey))
|
||||
{
|
||||
var method = keyCollType.GetMethod("System_Collections_IDictionary_GetEnumerator", FLAGS)
|
||||
?? keyCollType.GetMethod("GetEnumerator");
|
||||
var method = keyCollType.GetMethod("GetEnumerator")
|
||||
?? keyCollType.GetMethod("System_Collections_IDictionary_GetEnumerator", FLAGS);
|
||||
getEnumeratorMethods.Add(cacheKey, method);
|
||||
|
||||
// test support
|
||||
try
|
||||
{
|
||||
var test = getEnumeratorMethods[cacheKey].Invoke(keys, null);
|
||||
test.GetType().GetMethod("MoveNext").Invoke(test, null);
|
||||
test.GetActualType().GetMethod("MoveNext").Invoke(test, null);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.Log($"IDictionary failed to enumerate: {ex}");
|
||||
notSupportedTypes.Add(cacheKey);
|
||||
}
|
||||
}
|
||||
@ -914,16 +899,16 @@ namespace UnityExplorer
|
||||
var keyEnumerator = getEnumeratorMethods[cacheKey].Invoke(keys, null);
|
||||
var keyInfo = new EnumeratorInfo
|
||||
{
|
||||
current = keyEnumerator.GetType().GetProperty("Current"),
|
||||
moveNext = keyEnumerator.GetType().GetMethod("MoveNext"),
|
||||
current = keyEnumerator.GetActualType().GetProperty("Current"),
|
||||
moveNext = keyEnumerator.GetActualType().GetMethod("MoveNext"),
|
||||
};
|
||||
|
||||
var values = type.GetProperty("Values").GetValue(dictionary, null);
|
||||
var valueEnumerator = values.GetType().GetMethod("GetEnumerator").Invoke(values, null);
|
||||
var valueEnumerator = values.GetActualType().GetMethod("GetEnumerator").Invoke(values, null);
|
||||
var valueInfo = new EnumeratorInfo
|
||||
{
|
||||
current = valueEnumerator.GetType().GetProperty("Current"),
|
||||
moveNext = valueEnumerator.GetType().GetMethod("MoveNext"),
|
||||
current = valueEnumerator.GetActualType().GetProperty("Current"),
|
||||
moveNext = valueEnumerator.GetActualType().GetMethod("MoveNext"),
|
||||
};
|
||||
|
||||
dictEnumerator = EnumerateCppDict(keyInfo, keyEnumerator, valueInfo, valueEnumerator);
|
||||
|
57
src/Core/Reflection/Patches.cs
Normal file
57
src/Core/Reflection/Patches.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
public static class ReflectionPatches
|
||||
{
|
||||
public static void Init()
|
||||
{
|
||||
try
|
||||
{
|
||||
var method = typeof(Assembly).GetMethod(nameof(Assembly.GetTypes), new Type[0]);
|
||||
var processor = ExplorerCore.Harmony.CreateProcessor(method);
|
||||
processor.AddFinalizer(typeof(ReflectionPatches).GetMethod(nameof(Assembly_GetTypes)));
|
||||
processor.Patch();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception setting up Reflection patch: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Type[] emptyTypes = new Type[0];
|
||||
|
||||
public static Exception Assembly_GetTypes(Assembly __instance, Exception __exception, ref Type[] __result)
|
||||
{
|
||||
if (__exception != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
__result = __instance.GetExportedTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException e)
|
||||
{
|
||||
try
|
||||
{
|
||||
__result = e.Types.Where(it => it != null).ToArray();
|
||||
}
|
||||
catch
|
||||
{
|
||||
__result = emptyTypes;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
__result = emptyTypes;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -27,6 +27,8 @@ namespace UnityExplorer
|
||||
new ReflectionUtility();
|
||||
#endif
|
||||
Instance.Initialize();
|
||||
|
||||
ReflectionPatches.Init();
|
||||
}
|
||||
|
||||
protected virtual void Initialize()
|
||||
|
@ -32,16 +32,6 @@ namespace UnityExplorer
|
||||
return new AssetBundle(ptr);
|
||||
}
|
||||
|
||||
// static void UnloadAllAssetBundles(bool unloadAllObjects);
|
||||
|
||||
internal delegate void d_UnloadAllAssetBundles(bool unloadAllObjects);
|
||||
|
||||
public static void UnloadAllAssetBundles(bool unloadAllObjects)
|
||||
{
|
||||
var iCall = ICallManager.GetICall<d_UnloadAllAssetBundles>("UnityEngine.AssetBundle::UnloadAllAssetBundles");
|
||||
iCall.Invoke(unloadAllObjects);
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~ Instance ~~~~~~~~~~~~
|
||||
|
||||
private readonly IntPtr m_bundlePtr = IntPtr.Zero;
|
||||
@ -78,7 +68,8 @@ namespace UnityExplorer
|
||||
return new UnityEngine.Object(ptr).TryCast<T>();
|
||||
}
|
||||
|
||||
// public extern void Unload(bool unloadAllLoadedObjects);
|
||||
// Unload(bool unloadAllLoadedObjects);
|
||||
|
||||
internal delegate void d_Unload(IntPtr _this, bool unloadAllLoadedObjects);
|
||||
|
||||
public void Unload(bool unloadAssets = true)
|
||||
|
@ -7,7 +7,6 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||
{
|
||||
[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "External methods")]
|
||||
public static class ICallManager
|
||||
{
|
||||
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
|
@ -6,8 +6,8 @@ using System.Linq;
|
||||
using UnhollowerBaseLib;
|
||||
using UnityEngine;
|
||||
|
||||
// CREDIT HerpDerpenstine
|
||||
// https://github.com/LavaGang/MelonLoader/blob/master/MelonLoader.Support.Il2Cpp/MelonCoroutines.cs
|
||||
// Credit to HerpDerpenstine and knah
|
||||
// https://github.com/LavaGang/MelonLoader/blob/master/SM_Il2Cpp/Coroutines.cs
|
||||
|
||||
namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||
{
|
||||
|
@ -73,6 +73,7 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||
return ScriptableObject.CreateInstance(Il2CppType.From(type));
|
||||
}
|
||||
|
||||
// Pretty disgusting but couldn't figure out a cleaner way yet unfortunately
|
||||
public override void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List<RaycastResult> list)
|
||||
{
|
||||
var il2cppList = new Il2CppSystem.Collections.Generic.List<RaycastResult>();
|
||||
@ -97,15 +98,17 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||
|
||||
internal delegate IntPtr d_FindObjectsOfTypeAll(IntPtr type);
|
||||
|
||||
internal static readonly string[] findObjectsOfTypeAllSignatures = new[]
|
||||
{
|
||||
"UnityEngine.Resources::FindObjectsOfTypeAll",
|
||||
"UnityEngine.ResourcesAPIInternal::FindObjectsOfTypeAll" // Unity 2020+ updated to this
|
||||
};
|
||||
|
||||
public override UnityEngine.Object[] FindObjectsOfTypeAll(Type type)
|
||||
{
|
||||
var iCall = ICallManager.GetICallUnreliable<d_FindObjectsOfTypeAll>(new[]
|
||||
{
|
||||
"UnityEngine.Resources::FindObjectsOfTypeAll",
|
||||
"UnityEngine.ResourcesAPIInternal::FindObjectsOfTypeAll" // Unity 2020+ updated to this
|
||||
});
|
||||
|
||||
return new Il2CppReferenceArray<UnityEngine.Object>(iCall.Invoke(Il2CppType.From(type).Pointer));
|
||||
return new Il2CppReferenceArray<UnityEngine.Object>(
|
||||
ICallManager.GetICallUnreliable<d_FindObjectsOfTypeAll>(findObjectsOfTypeAllSignatures)
|
||||
.Invoke(Il2CppType.From(type).Pointer));
|
||||
}
|
||||
|
||||
// Scene.GetRootGameObjects();
|
||||
@ -117,22 +120,17 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||
if (!scene.isLoaded)
|
||||
return new GameObject[0];
|
||||
|
||||
int handle = scene.handle;
|
||||
|
||||
if (handle == -1)
|
||||
if (scene.handle == -1)
|
||||
return new GameObject[0];
|
||||
|
||||
int count = GetRootCount(handle);
|
||||
int count = GetRootCount(scene.handle);
|
||||
|
||||
if (count < 1)
|
||||
return new GameObject[0];
|
||||
|
||||
var list = new Il2CppSystem.Collections.Generic.List<GameObject>(count);
|
||||
|
||||
var iCall = ICallManager.GetICall<d_GetRootGameObjects>("UnityEngine.SceneManagement.Scene::GetRootGameObjectsInternal");
|
||||
|
||||
iCall.Invoke(handle, list.Pointer);
|
||||
|
||||
iCall.Invoke(scene.handle, list.Pointer);
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
|
@ -38,19 +38,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||
return new Il2CppStructArray<byte>(ptr);
|
||||
}
|
||||
|
||||
// bool ImageConversion.LoadImage(this Texture2D tex, byte[] data, bool markNonReadable);
|
||||
|
||||
internal delegate bool d_LoadImage(IntPtr tex, IntPtr data, bool markNonReadable);
|
||||
|
||||
public override bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable)
|
||||
{
|
||||
var il2cppArray = (Il2CppStructArray<byte>)data;
|
||||
|
||||
var iCall = ICallManager.GetICall<d_LoadImage>("UnityEngine.ImageConversion::LoadImage");
|
||||
|
||||
return iCall.Invoke(tex.Pointer, il2cppArray.Pointer, markNonReadable);
|
||||
}
|
||||
|
||||
// Sprite Sprite.Create
|
||||
|
||||
public override Sprite CreateSprite(Texture2D texture)
|
||||
|
@ -10,6 +10,7 @@ using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer;
|
||||
|
||||
namespace UnityExplorer.Core.Runtime.Mono
|
||||
{
|
||||
@ -18,7 +19,6 @@ namespace UnityExplorer.Core.Runtime.Mono
|
||||
public override void Initialize()
|
||||
{
|
||||
ExplorerCore.Context = RuntimeContext.Mono;
|
||||
//Reflection = new MonoReflection();
|
||||
TextureUtil = new MonoTextureUtil();
|
||||
}
|
||||
|
||||
@ -28,60 +28,35 @@ namespace UnityExplorer.Core.Runtime.Mono
|
||||
}
|
||||
|
||||
private void Application_logMessageReceived(string condition, string stackTrace, LogType type)
|
||||
{
|
||||
ExplorerCore.LogUnity(condition, type);
|
||||
}
|
||||
=> ExplorerCore.LogUnity(condition, type);
|
||||
|
||||
public override void StartCoroutine(IEnumerator routine)
|
||||
{
|
||||
ExplorerBehaviour.Instance.StartCoroutine(routine);
|
||||
}
|
||||
public override void StartCoroutine(IEnumerator routine)
|
||||
=> ExplorerBehaviour.Instance.StartCoroutine(routine);
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override T AddComponent<T>(GameObject obj, Type type)
|
||||
{
|
||||
return (T)obj.AddComponent(type);
|
||||
}
|
||||
public override T AddComponent<T>(GameObject obj, Type type)
|
||||
=> (T)obj.AddComponent(type);
|
||||
|
||||
public override ScriptableObject CreateScriptable(Type type)
|
||||
{
|
||||
return ScriptableObject.CreateInstance(type);
|
||||
}
|
||||
public override ScriptableObject CreateScriptable(Type type)
|
||||
=> ScriptableObject.CreateInstance(type);
|
||||
|
||||
public override void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List<RaycastResult> list)
|
||||
{
|
||||
raycaster.Raycast(data, list);
|
||||
}
|
||||
=> raycaster.Raycast(data, list);
|
||||
|
||||
public override string LayerToName(int layer)
|
||||
public override string LayerToName(int layer)
|
||||
=> LayerMask.LayerToName(layer);
|
||||
|
||||
public override UnityEngine.Object[] FindObjectsOfTypeAll(Type type)
|
||||
public override UnityEngine.Object[] FindObjectsOfTypeAll(Type type)
|
||||
=> Resources.FindObjectsOfTypeAll(type);
|
||||
|
||||
//private static readonly FieldInfo fi_Scene_handle = typeof(Scene).GetField("m_Handle", ReflectionUtility.AllFlags);
|
||||
public override GameObject[] GetRootGameObjects(Scene scene)
|
||||
=> scene.isLoaded ? scene.GetRootGameObjects() : new GameObject[0];
|
||||
|
||||
//public override int GetSceneHandle(Scene scene)
|
||||
//{
|
||||
// return (int)fi_Scene_handle.GetValue(scene);
|
||||
//}
|
||||
|
||||
public override GameObject[] GetRootGameObjects(Scene scene)
|
||||
{
|
||||
if (!scene.isLoaded)
|
||||
return new GameObject[0];
|
||||
|
||||
return scene.GetRootGameObjects();
|
||||
}
|
||||
|
||||
public override int GetRootCount(Scene scene)
|
||||
{
|
||||
return scene.rootCount;
|
||||
}
|
||||
public override int GetRootCount(Scene scene)
|
||||
=> scene.rootCount;
|
||||
|
||||
public override void SetColorBlock(Selectable selectable, Color? normal = null, Color? highlighted = null, Color? pressed = null,
|
||||
Color? disabled = null)
|
||||
@ -103,59 +78,42 @@ namespace UnityExplorer.Core.Runtime.Mono
|
||||
SetColorBlock(selectable, colors);
|
||||
}
|
||||
|
||||
public override void SetColorBlock(Selectable selectable, ColorBlock colors)
|
||||
{
|
||||
selectable.colors = colors;
|
||||
}
|
||||
public override void SetColorBlock(Selectable selectable, ColorBlock colors)
|
||||
=> selectable.colors = colors;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MonoExtensions
|
||||
{
|
||||
// Helpers to use the same style of AddListener that IL2CPP uses.
|
||||
|
||||
public static void AddListener(this UnityEvent _event, Action listener)
|
||||
{
|
||||
_event.AddListener(new UnityAction(listener));
|
||||
}
|
||||
=> _event.AddListener(new UnityAction(listener));
|
||||
|
||||
public static void AddListener<T>(this UnityEvent<T> _event, Action<T> listener)
|
||||
{
|
||||
_event.AddListener(new UnityAction<T>(listener));
|
||||
}
|
||||
=> _event.AddListener(new UnityAction<T>(listener));
|
||||
|
||||
public static void RemoveListener(this UnityEvent _event, Action listener)
|
||||
{
|
||||
_event.RemoveListener(new UnityAction(listener));
|
||||
}
|
||||
=> _event.RemoveListener(new UnityAction(listener));
|
||||
|
||||
public static void RemoveListener<T>(this UnityEvent<T> _event, Action<T> listener)
|
||||
{
|
||||
_event.RemoveListener(new UnityAction<T>(listener));
|
||||
}
|
||||
=> _event.RemoveListener(new UnityAction<T>(listener));
|
||||
|
||||
public static void Clear(this StringBuilder sb)
|
||||
{
|
||||
sb.Remove(0, sb.Length);
|
||||
}
|
||||
// Doesn't exist in NET 3.5
|
||||
|
||||
private static PropertyInfo pi_childControlHeight;
|
||||
public static void Clear(this StringBuilder sb)
|
||||
=> sb.Remove(0, sb.Length);
|
||||
|
||||
// These properties don't exist in some earlier games, so null check before trying to set them.
|
||||
|
||||
public static void SetChildControlHeight(this HorizontalOrVerticalLayoutGroup group, bool value)
|
||||
{
|
||||
if (pi_childControlHeight == null)
|
||||
pi_childControlHeight = group.GetType().GetProperty("childControlHeight");
|
||||
=> ReflectionUtility.GetPropertyInfo(typeof(HorizontalOrVerticalLayoutGroup), "childControlHeight")
|
||||
?.SetValue(group, value, null);
|
||||
|
||||
pi_childControlHeight?.SetValue(group, value, null);
|
||||
}
|
||||
|
||||
private static PropertyInfo pi_childControlWidth;
|
||||
|
||||
public static void SetChildControlWidth(this HorizontalOrVerticalLayoutGroup group, bool value)
|
||||
{
|
||||
if (pi_childControlWidth == null)
|
||||
pi_childControlWidth = group.GetType().GetProperty("childControlWidth");
|
||||
|
||||
pi_childControlWidth?.SetValue(group, value, null);
|
||||
}
|
||||
=> ReflectionUtility.GetPropertyInfo(typeof(HorizontalOrVerticalLayoutGroup), "childControlWidth")
|
||||
?.SetValue(group, value, null);
|
||||
}
|
||||
|
||||
#endif
|
@ -12,41 +12,28 @@ namespace UnityExplorer.Core.Runtime.Mono
|
||||
public class MonoTextureUtil : TextureUtilProvider
|
||||
{
|
||||
public override void Blit(Texture2D tex, RenderTexture rt)
|
||||
{
|
||||
Graphics.Blit(tex, rt);
|
||||
}
|
||||
=> Graphics.Blit(tex, rt);
|
||||
|
||||
public override Sprite CreateSprite(Texture2D texture)
|
||||
{
|
||||
return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
|
||||
}
|
||||
=> Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
|
||||
|
||||
public override bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable)
|
||||
{
|
||||
return tex.LoadImage(data, markNonReadable);
|
||||
}
|
||||
//public override bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable)
|
||||
// => tex.LoadImage(data, markNonReadable);
|
||||
|
||||
public override Texture2D NewTexture2D(int width, int height)
|
||||
{
|
||||
return new Texture2D(width, height);
|
||||
}
|
||||
=> new Texture2D(width, height);
|
||||
|
||||
public override byte[] EncodeToPNG(Texture2D tex)
|
||||
{
|
||||
return EncodeToPNGSafe(tex);
|
||||
}
|
||||
=> EncodeToPNGSafe(tex);
|
||||
|
||||
private static MethodInfo EncodeToPNGMethod => m_encodeToPNGMethod ?? GetEncodeToPNGMethod();
|
||||
private static MethodInfo m_encodeToPNGMethod;
|
||||
|
||||
public static byte[] EncodeToPNGSafe(Texture2D tex)
|
||||
{
|
||||
var method = EncodeToPNGMethod;
|
||||
|
||||
if (method.IsStatic)
|
||||
return (byte[])method.Invoke(null, new object[] { tex });
|
||||
else
|
||||
return (byte[])method.Invoke(tex, ArgumentUtility.EmptyArgs);
|
||||
return EncodeToPNGMethod.IsStatic
|
||||
? (byte[])EncodeToPNGMethod.Invoke(null, new object[] { tex })
|
||||
: (byte[])EncodeToPNGMethod.Invoke(tex, ArgumentUtility.EmptyArgs);
|
||||
}
|
||||
|
||||
private static MethodInfo GetEncodeToPNGMethod()
|
||||
|
@ -40,8 +40,6 @@ namespace UnityExplorer
|
||||
|
||||
public abstract void Update();
|
||||
|
||||
//public virtual bool IsReferenceEqual(object a, object b) => ReferenceEquals(a, b);
|
||||
|
||||
// Unity API handlers
|
||||
|
||||
public abstract T AddComponent<T>(GameObject obj, Type type) where T : Component;
|
||||
@ -54,8 +52,6 @@ namespace UnityExplorer
|
||||
|
||||
public abstract void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List<RaycastResult> list);
|
||||
|
||||
//public abstract int GetSceneHandle(Scene scene);
|
||||
|
||||
public abstract GameObject[] GetRootGameObjects(Scene scene);
|
||||
|
||||
public abstract int GetRootCount(Scene scene);
|
||||
|
@ -22,7 +22,7 @@ namespace UnityExplorer.Core.Runtime
|
||||
|
||||
public abstract void Blit(Texture2D tex, RenderTexture rt);
|
||||
|
||||
public abstract bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable);
|
||||
//public abstract bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable);
|
||||
|
||||
public abstract Sprite CreateSprite(Texture2D texture);
|
||||
|
||||
@ -43,27 +43,22 @@ namespace UnityExplorer.Core.Runtime
|
||||
}
|
||||
}
|
||||
|
||||
public static bool LoadImage(Texture2D tex, string filePath, bool markNonReadable)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
return false;
|
||||
|
||||
return Instance.LoadImage(tex, File.ReadAllBytes(filePath), markNonReadable);
|
||||
}
|
||||
//public static bool LoadImage(Texture2D tex, string filePath, bool markNonReadable)
|
||||
//{
|
||||
// if (!File.Exists(filePath))
|
||||
// return false;
|
||||
//
|
||||
// return Instance.LoadImage(tex, File.ReadAllBytes(filePath), markNonReadable);
|
||||
//}
|
||||
|
||||
public static Texture2D Copy(Texture2D orig, Rect rect)
|
||||
{
|
||||
Color[] pixels;
|
||||
|
||||
if (!IsReadable(orig))
|
||||
orig = ForceReadTexture(orig);
|
||||
|
||||
pixels = orig.GetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
|
||||
|
||||
Color[] pixels = orig.GetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
|
||||
Texture2D newTex = Instance.NewTexture2D((int)rect.width, (int)rect.height);
|
||||
|
||||
newTex.SetPixels(pixels);
|
||||
|
||||
return newTex;
|
||||
}
|
||||
|
||||
@ -92,7 +87,7 @@ namespace UnityExplorer.Core.Runtime
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log("Exception on ForceReadTexture: " + e.ToString());
|
||||
ExplorerCore.Log($"Exception on ForceReadTexture: {e.ToString()}");
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@ -103,13 +98,11 @@ namespace UnityExplorer.Core.Runtime
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
byte[] data;
|
||||
string savepath = dir + @"\" + name + ".png";
|
||||
string savepath = $@"{dir}\{name}.png";
|
||||
|
||||
// Make sure we can EncodeToPNG it.
|
||||
if (tex.format != TextureFormat.ARGB32 || !IsReadable(tex))
|
||||
{
|
||||
tex = ForceReadTexture(tex);
|
||||
}
|
||||
|
||||
if (isDTXnmNormal)
|
||||
{
|
||||
@ -120,13 +113,9 @@ namespace UnityExplorer.Core.Runtime
|
||||
data = Instance.EncodeToPNG(tex);
|
||||
|
||||
if (data == null || !data.Any())
|
||||
{
|
||||
ExplorerCore.LogWarning("Couldn't get any data for the texture!");
|
||||
}
|
||||
else
|
||||
{
|
||||
File.WriteAllBytes(savepath, data);
|
||||
}
|
||||
}
|
||||
|
||||
// Converts DTXnm-format Normal Map to RGBA-format Normal Map.
|
||||
|
@ -14,112 +14,31 @@ using UnhollowerBaseLib;
|
||||
|
||||
namespace UnityExplorer.Tests
|
||||
{
|
||||
public class TestIndexer : IList<int>
|
||||
{
|
||||
private readonly List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
|
||||
|
||||
public int Count => list.Count;
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
int IList<int>.this[int index]
|
||||
{
|
||||
get => list[index];
|
||||
set => list[index] = value;
|
||||
}
|
||||
|
||||
public int IndexOf(int item) => list.IndexOf(item);
|
||||
public bool Contains(int item) => list.Contains(item);
|
||||
|
||||
public void Add(int item) => list.Add(item);
|
||||
public void Insert(int index, int item) => list.Insert(index, item);
|
||||
|
||||
public bool Remove(int item) => list.Remove(item);
|
||||
public void RemoveAt(int index) => list.RemoveAt(index);
|
||||
|
||||
public void Clear() => list.Clear();
|
||||
|
||||
public void CopyTo(int[] array, int arrayIndex) => list.CopyTo(array, arrayIndex);
|
||||
|
||||
public IEnumerator<int> GetEnumerator() => list.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => list.GetEnumerator();
|
||||
}
|
||||
|
||||
public static class TestClass
|
||||
{
|
||||
public static readonly TestIndexer AAAAATest = new TestIndexer();
|
||||
|
||||
public static void ATestMethod(string s, float f, Vector3 vector, DateTime date, Quaternion quater, bool b, CameraClearFlags enumvalue)
|
||||
static TestClass()
|
||||
{
|
||||
ExplorerCore.Log($"{s}, {f}, {vector.ToString()}, {date}, {quater.eulerAngles.ToString()}, {b}, {enumvalue}");
|
||||
Init_Mono();
|
||||
#if CPP
|
||||
Init_IL2CPP();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static List<int> AWritableList = new List<int> { 1, 2, 3, 4, 5 };
|
||||
public static Dictionary<string, int> AWritableDict = new Dictionary<string, int> { { "one", 1 }, { "two", 2 } };
|
||||
|
||||
public static IEnumerable ANestedList = new List<List<List<string>>>
|
||||
{
|
||||
new List<List<string>>
|
||||
{
|
||||
new List<string>
|
||||
{
|
||||
"one",
|
||||
"two",
|
||||
"one",
|
||||
"two",
|
||||
"one",
|
||||
"two",
|
||||
"one",
|
||||
"two",
|
||||
"one",
|
||||
"two",
|
||||
"one",
|
||||
"two",
|
||||
"one",
|
||||
"two",
|
||||
"one",
|
||||
"two",
|
||||
},
|
||||
new List<string>
|
||||
{
|
||||
"three",
|
||||
"four",
|
||||
}
|
||||
},
|
||||
new List<List<string>>
|
||||
{
|
||||
new List<string>
|
||||
{
|
||||
"five"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static IDictionary ARandomDictionary = new Dictionary<object, object>
|
||||
{
|
||||
{ 1, 2 },
|
||||
{ "one", "two" },
|
||||
{ true, false },
|
||||
{ new Vector3(0,1,2), new Vector3(1,2,3) },
|
||||
{ CameraClearFlags.Depth, CameraClearFlags.Color },
|
||||
{ "################################################\r\n##########", null },
|
||||
{ "subdict", new Dictionary<object,object> { { "key", "value" } } }
|
||||
};
|
||||
|
||||
public static Hashtable TestHashtable = new Hashtable
|
||||
{
|
||||
{ "one", "value" },
|
||||
{ "two", "value" },
|
||||
{ "three", "value" },
|
||||
};
|
||||
|
||||
public const int ConstantInt = 5;
|
||||
|
||||
public static Color AColor = Color.magenta;
|
||||
public static Color32 AColor32 = Color.red;
|
||||
|
||||
// Test enumerables
|
||||
public static List<object> ListOfInts;
|
||||
public static List<List<List<string>>> NestedList;
|
||||
public static IDictionary MixedDictionary;
|
||||
public static Hashtable Hashtable;
|
||||
public static byte[] ByteArray = new byte[16];
|
||||
public static string LongString = new string('#', 10000);
|
||||
public static List<string> BigList = new List<string>(10000);
|
||||
public static List<short> ABigList = new List<short>(10000);
|
||||
|
||||
// Test const behaviour (should be a readonly field)
|
||||
public const int ConstantInt5 = 5;
|
||||
|
||||
// Testing other InteractiveValues
|
||||
public static Color Color = Color.magenta;
|
||||
public static Color32 Color32 = Color.red;
|
||||
public static string ALongString = new string('#', 10000);
|
||||
|
||||
public static List<object> RandomList
|
||||
{
|
||||
@ -133,25 +52,7 @@ namespace UnityExplorer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
private static void TestGeneric<T>()
|
||||
{
|
||||
ExplorerCore.Log("Test1 " + typeof(T).FullName);
|
||||
}
|
||||
|
||||
private static void TestGenericClass<T>() where T : class
|
||||
{
|
||||
ExplorerCore.Log("Test2 " + typeof(T).FullName);
|
||||
}
|
||||
|
||||
private static void TestComponent<T>() where T : Component
|
||||
{
|
||||
ExplorerCore.Log("Test3 " + typeof(T).FullName);
|
||||
}
|
||||
|
||||
private static void TestStruct<T>() where T : struct
|
||||
{
|
||||
ExplorerCore.Log("Test3 " + typeof(T).FullName);
|
||||
}
|
||||
// Test methods
|
||||
|
||||
private static object GetRandomObject()
|
||||
{
|
||||
@ -165,109 +66,133 @@ namespace UnityExplorer.Tests
|
||||
case 2: return true;
|
||||
case 3: return "hello";
|
||||
case 4: return 50.5f;
|
||||
case 5: return UnityEngine.CameraClearFlags.Color;
|
||||
case 6: return new List<string> { "sub list", "lol" };
|
||||
case 5: return CameraClearFlags.Color;
|
||||
case 6: return new List<string> { "one", "two" };
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void TestComponent<T>() where T : Component
|
||||
{
|
||||
ExplorerCore.Log($"Test3 {typeof(T).FullName}");
|
||||
}
|
||||
|
||||
public static void TestArgumentParse(string s, int i, Color color, CameraClearFlags flags, Vector3 vector, Quaternion quaternion)
|
||||
{
|
||||
ExplorerCore.Log($"{s}, {i}, {color.ToString()}, {flags}, {vector.ToString()}, {quaternion.ToString()}");
|
||||
}
|
||||
|
||||
private static void Init_Mono()
|
||||
{
|
||||
ExplorerCore.Log($"1: Basic list");
|
||||
ListOfInts = new List<object> { 1, 2, 3, 4, 5 };
|
||||
|
||||
ExplorerCore.Log($"2: Nested list");
|
||||
NestedList = new List<List<List<string>>>
|
||||
{
|
||||
new List<List<string>> {
|
||||
new List<string> { "1", "2", "3" },
|
||||
new List<string> { "4", "5", "6" },
|
||||
},
|
||||
new List<List<string>>
|
||||
{
|
||||
new List<string> { "7", "8", "9" }
|
||||
}
|
||||
};
|
||||
|
||||
ExplorerCore.Log($"3: Dictionary");
|
||||
MixedDictionary = new Dictionary<object, object>
|
||||
{
|
||||
{ 1, 2 },
|
||||
{ "one", "two" },
|
||||
{ true, false },
|
||||
{ new Vector3(0,1,2), new Vector3(1,2,3) },
|
||||
{ CameraClearFlags.Depth, CameraClearFlags.Color },
|
||||
{ "################################################\r\n##########", null },
|
||||
{ "subdict", new Dictionary<object,object> { { "key", "value" } } }
|
||||
};
|
||||
|
||||
ExplorerCore.Log($"4: Hashtable");
|
||||
Hashtable = new Hashtable { { "One", 1 }, { "Two", 2 } };
|
||||
|
||||
ExplorerCore.Log($"5: Big list");
|
||||
for (int i = 0; i < ABigList.Capacity; i++)
|
||||
ABigList.Add((short)UnityEngine.Random.Range(0, short.MaxValue));
|
||||
|
||||
ExplorerCore.Log("Finished TestClass Init_Mono");
|
||||
}
|
||||
|
||||
#if CPP
|
||||
|
||||
public static Il2CppSystem.Collections.IList IL2CPP_IList;
|
||||
public static Il2CppSystem.Collections.Generic.List<string> IL2CPP_ListString;
|
||||
public static Il2CppSystem.Collections.Generic.HashSet<string> IL2CPP_HashSet;
|
||||
|
||||
public static Il2CppSystem.Collections.Generic.Dictionary<string, string> IL2CPP_Dict;
|
||||
public static Il2CppSystem.Collections.Hashtable IL2CPP_HashTable;
|
||||
public static Il2CppSystem.Collections.IDictionary IL2CPP_IDict;
|
||||
|
||||
public static string IL2CPP_systemString = "Test";
|
||||
public static Il2CppSystem.Object IL2CPP_objectString = "string boxed as cpp object";
|
||||
public static Il2CppSystem.String IL2CPP_il2cppString = "string boxed as cpp string";
|
||||
public static string nullString = null;
|
||||
|
||||
public static List<Il2CppSystem.Object> IL2CPP_listOfBoxedObjects;
|
||||
public static Il2CppStructArray<int> IL2CPP_structArray;
|
||||
public static Il2CppStringArray IL2CPP_stringArray;
|
||||
public static Il2CppReferenceArray<Il2CppSystem.Object> IL2CPP_ReferenceArray;
|
||||
public static Il2CppSystem.Collections.IDictionary IL2CPP_IDict;
|
||||
public static Il2CppSystem.Collections.IList IL2CPP_IList;
|
||||
public static Dictionary<Il2CppSystem.String, Il2CppSystem.Object> CppBoxedDict;
|
||||
|
||||
public static Il2CppSystem.Collections.Generic.HashSet<string> IL2CPP_HashSet;
|
||||
public static Il2CppSystem.Collections.Generic.Dictionary<string, string> IL2CPP_Dict;
|
||||
public static Il2CppSystem.Collections.Hashtable IL2CPP_HashTable;
|
||||
public static Il2CppSystem.Object cppBoxedInt;
|
||||
public static Il2CppSystem.Int32 cppInt;
|
||||
public static Il2CppSystem.Decimal cppDecimal;
|
||||
public static Il2CppSystem.Object cppDecimalBoxed;
|
||||
public static Il2CppSystem.Object cppVector3Boxed;
|
||||
public static string IL2CPP_systemString = "Test";
|
||||
public static Il2CppSystem.Object IL2CPP_objectString = "string boxed as cpp object";
|
||||
public static Il2CppSystem.String IL2CPP_il2cppString = "string boxed as cpp string";
|
||||
public static string nullString = null;
|
||||
|
||||
public static Il2CppSystem.Object RandomBoxedColor
|
||||
private static void Init_IL2CPP()
|
||||
{
|
||||
get
|
||||
{
|
||||
int ran = UnityEngine.Random.Range(0, 3);
|
||||
switch (ran)
|
||||
{
|
||||
case 1: return new Color32().BoxIl2CppObject();
|
||||
case 2: return Color.magenta.BoxIl2CppObject();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Il2CppSystem.Collections.Hashtable cppHashset;
|
||||
|
||||
public static Dictionary<Il2CppSystem.String, Il2CppSystem.Object> CppBoxedDict;
|
||||
|
||||
#endif
|
||||
|
||||
static TestClass()
|
||||
{
|
||||
for (int i = 0; i < BigList.Capacity; i++)
|
||||
BigList.Add(i.ToString());
|
||||
|
||||
#if CPP
|
||||
ExplorerCore.Log($"IL2CPP 1: Il2Cpp Dictionary<string, string>");
|
||||
IL2CPP_Dict = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
|
||||
IL2CPP_Dict.Add("key1", "value1");
|
||||
IL2CPP_Dict.Add("key2", "value2");
|
||||
IL2CPP_Dict.Add("key3", "value3");
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 2: Il2Cpp Hashtable");
|
||||
IL2CPP_HashTable = new Il2CppSystem.Collections.Hashtable();
|
||||
IL2CPP_HashTable.Add("key1", "value1");
|
||||
IL2CPP_HashTable.Add("key2", "value2");
|
||||
IL2CPP_HashTable.Add("key3", "value3");
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 3: Il2Cpp IDictionary");
|
||||
var dict2 = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
|
||||
dict2.Add("key1", "value1");
|
||||
IL2CPP_IDict = dict2.TryCast<Il2CppSystem.Collections.IDictionary>();
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 4: Il2Cpp List of Il2Cpp Object");
|
||||
var list = new Il2CppSystem.Collections.Generic.List<Il2CppSystem.Object>(5);
|
||||
list.Add("one");
|
||||
list.Add("two");
|
||||
IL2CPP_IList = list.TryCast<Il2CppSystem.Collections.IList>();
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 5: Il2Cpp List of strings");
|
||||
IL2CPP_ListString = new Il2CppSystem.Collections.Generic.List<string>();
|
||||
IL2CPP_ListString.Add("hello,");
|
||||
IL2CPP_ListString.Add("world!");
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 6: Il2Cpp HashSet of strings");
|
||||
IL2CPP_HashSet = new Il2CppSystem.Collections.Generic.HashSet<string>();
|
||||
IL2CPP_HashSet.Add("one");
|
||||
IL2CPP_HashSet.Add("two");
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 7: Dictionary of Il2Cpp String and Il2Cpp Object");
|
||||
CppBoxedDict = new Dictionary<Il2CppSystem.String, Il2CppSystem.Object>();
|
||||
CppBoxedDict.Add("1", new Il2CppSystem.Int32 { m_value = 1 }.BoxIl2CppObject());
|
||||
CppBoxedDict.Add("2", new Il2CppSystem.Int32 { m_value = 2 }.BoxIl2CppObject());
|
||||
CppBoxedDict.Add("3", new Il2CppSystem.Int32 { m_value = 3 }.BoxIl2CppObject());
|
||||
CppBoxedDict.Add("4", new Il2CppSystem.Int32 { m_value = 4 }.BoxIl2CppObject());
|
||||
|
||||
cppDecimal = new Il2CppSystem.Decimal(1f);
|
||||
cppDecimalBoxed = new Il2CppSystem.Decimal(1f).BoxIl2CppObject();
|
||||
cppVector3Boxed = Vector3.down.BoxIl2CppObject();
|
||||
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 8: List of boxed Il2Cpp Objects");
|
||||
IL2CPP_listOfBoxedObjects = new List<Il2CppSystem.Object>();
|
||||
IL2CPP_listOfBoxedObjects.Add((Il2CppSystem.String)"boxedString");
|
||||
IL2CPP_listOfBoxedObjects.Add(new Il2CppSystem.Int32 { m_value = 5 }.BoxIl2CppObject());
|
||||
IL2CPP_listOfBoxedObjects.Add(Color.red.BoxIl2CppObject());
|
||||
|
||||
// boxed enum test
|
||||
try
|
||||
{
|
||||
var cppType = Il2CppType.Of<CameraClearFlags>();
|
||||
@ -283,9 +208,10 @@ namespace UnityExplorer.Tests
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Test fail: {ex}");
|
||||
ExplorerCore.LogWarning($"Boxed enum test fail: {ex}");
|
||||
}
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 9: Il2Cpp struct array of ints");
|
||||
IL2CPP_structArray = new UnhollowerBaseLib.Il2CppStructArray<int>(5);
|
||||
IL2CPP_structArray[0] = 0;
|
||||
IL2CPP_structArray[1] = 1;
|
||||
@ -293,24 +219,21 @@ namespace UnityExplorer.Tests
|
||||
IL2CPP_structArray[3] = 3;
|
||||
IL2CPP_structArray[4] = 4;
|
||||
|
||||
IL2CPP_stringArray = new UnhollowerBaseLib.Il2CppStringArray(2);
|
||||
IL2CPP_stringArray[0] = "hello, ";
|
||||
IL2CPP_stringArray[1] = "world!";
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 10: Il2Cpp reference array of boxed objects");
|
||||
IL2CPP_ReferenceArray = new UnhollowerBaseLib.Il2CppReferenceArray<Il2CppSystem.Object>(3);
|
||||
IL2CPP_ReferenceArray[0] = new Il2CppSystem.Int32 { m_value = 5 }.BoxIl2CppObject();
|
||||
IL2CPP_ReferenceArray[1] = null;
|
||||
IL2CPP_ReferenceArray[2] = (Il2CppSystem.String)"whats up";
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 11: Misc il2cpp members");
|
||||
cppBoxedInt = new Il2CppSystem.Int32() { m_value = 5 }.BoxIl2CppObject();
|
||||
cppInt = new Il2CppSystem.Int32 { m_value = 420 };
|
||||
cppDecimal = new Il2CppSystem.Decimal(1f);
|
||||
cppDecimalBoxed = new Il2CppSystem.Decimal(1f).BoxIl2CppObject();
|
||||
cppVector3Boxed = Vector3.down.BoxIl2CppObject();
|
||||
|
||||
cppHashset = new Il2CppSystem.Collections.Hashtable();
|
||||
cppHashset.Add("key1", "itemOne");
|
||||
cppHashset.Add("key2", "itemTwo");
|
||||
cppHashset.Add("key3", "itemThree");
|
||||
|
||||
#endif
|
||||
ExplorerCore.Log($"Finished Init_Il2Cpp");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ namespace UnityExplorer
|
||||
/// </summary>
|
||||
public static bool ContainsIgnoreCase(this string _this, string s)
|
||||
{
|
||||
return ParseUtility.en_US.CompareInfo.IndexOf(_this, s, CompareOptions.IgnoreCase) >= 0;
|
||||
return CultureInfo.CurrentCulture.CompareInfo.IndexOf(_this, s, CompareOptions.IgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -10,8 +10,6 @@ namespace UnityExplorer
|
||||
{
|
||||
public static class ParseUtility
|
||||
{
|
||||
public static CultureInfo en_US = new CultureInfo("en-US");
|
||||
|
||||
private static readonly HashSet<Type> nonPrimitiveTypes = new HashSet<Type>
|
||||
{
|
||||
typeof(string),
|
||||
@ -19,20 +17,18 @@ namespace UnityExplorer
|
||||
typeof(DateTime),
|
||||
};
|
||||
|
||||
public const string NUMBER_FORMAT = "0.####";
|
||||
// Helper for formatting float/double/decimal numbers to maximum of 4 decimal points.
|
||||
// And also for formatting a sequence of those numbers, ie a Vector3, Color etc
|
||||
|
||||
public static readonly string NumberFormatString = $"0.####";
|
||||
private static readonly Dictionary<int, string> numSequenceStrings = new Dictionary<int, string>();
|
||||
|
||||
// Helper for formatting float/double/decimal numbers to maximum of 4 decimal points.
|
||||
public static string FormatDecimalSequence(params object[] numbers)
|
||||
{
|
||||
if (numbers.Length <= 0)
|
||||
return null;
|
||||
|
||||
int count = numbers.Length;
|
||||
var formatString = GetSequenceFormatString(count);
|
||||
|
||||
return string.Format(en_US, formatString, numbers);
|
||||
return string.Format(CultureInfo.CurrentCulture, GetSequenceFormatString(numbers.Length), numbers);
|
||||
}
|
||||
|
||||
public static string GetSequenceFormatString(int count)
|
||||
@ -46,19 +42,19 @@ namespace UnityExplorer
|
||||
string[] strings = new string[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
strings[i] = $"{{{i}:{NUMBER_FORMAT}}}";
|
||||
strings[i] = $"{{{i}:{NumberFormatString}}}";
|
||||
|
||||
string s = string.Join(", ", strings);
|
||||
|
||||
numSequenceStrings.Add(count, s);
|
||||
return s;
|
||||
string ret = string.Join(" ", strings);
|
||||
numSequenceStrings.Add(count, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Main parsing API
|
||||
|
||||
public static bool CanParse(Type type)
|
||||
{
|
||||
if (string.IsNullOrEmpty(type.FullName))
|
||||
return false;
|
||||
return type.IsPrimitive || type.IsEnum || nonPrimitiveTypes.Contains(type) || customTypes.ContainsKey(type.FullName);
|
||||
return !string.IsNullOrEmpty(type?.FullName)
|
||||
&& (type.IsPrimitive || type.IsEnum || nonPrimitiveTypes.Contains(type) || customTypes.ContainsKey(type.FullName));
|
||||
}
|
||||
|
||||
public static bool TryParse(string input, Type type, out object obj, out Exception parseException)
|
||||
@ -143,7 +139,7 @@ namespace UnityExplorer
|
||||
else if (formattedTypes.Contains(type))
|
||||
{
|
||||
return ReflectionUtility.GetMethodInfo(type, "ToString", new Type[] { typeof(string), typeof(IFormatProvider) })
|
||||
.Invoke(obj, new object[] { NUMBER_FORMAT, en_US })
|
||||
.Invoke(obj, new object[] { NumberFormatString, CultureInfo.CurrentCulture })
|
||||
as string;
|
||||
}
|
||||
else
|
||||
@ -166,9 +162,7 @@ namespace UnityExplorer
|
||||
try
|
||||
{
|
||||
if (type.IsEnum)
|
||||
{
|
||||
typeInputExamples.Add(type.AssemblyQualifiedName, Enum.GetNames(type).First());
|
||||
}
|
||||
else
|
||||
{
|
||||
var instance = Activator.CreateInstance(type);
|
||||
@ -222,10 +216,10 @@ namespace UnityExplorer
|
||||
{
|
||||
Vector2 vector = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
var split = input.Split(' ');
|
||||
|
||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
||||
vector.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||
vector.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||
|
||||
return vector;
|
||||
}
|
||||
@ -244,11 +238,11 @@ namespace UnityExplorer
|
||||
{
|
||||
Vector3 vector = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
var split = input.Split(' ');
|
||||
|
||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
||||
vector.z = float.Parse(split[2].Trim(), en_US);
|
||||
vector.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||
vector.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||
vector.z = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||
|
||||
return vector;
|
||||
}
|
||||
@ -267,12 +261,12 @@ namespace UnityExplorer
|
||||
{
|
||||
Vector4 vector = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
var split = input.Split(' ');
|
||||
|
||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
||||
vector.z = float.Parse(split[2].Trim(), en_US);
|
||||
vector.w = float.Parse(split[3].Trim(), en_US);
|
||||
vector.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||
vector.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||
vector.z = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||
vector.w = float.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||
|
||||
return vector;
|
||||
}
|
||||
@ -291,22 +285,22 @@ namespace UnityExplorer
|
||||
{
|
||||
Vector3 vector = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
var split = input.Split(' ');
|
||||
|
||||
if (split.Length == 4)
|
||||
{
|
||||
Quaternion quat = default;
|
||||
quat.x = float.Parse(split[0].Trim(), en_US);
|
||||
quat.y = float.Parse(split[1].Trim(), en_US);
|
||||
quat.z = float.Parse(split[2].Trim(), en_US);
|
||||
quat.w = float.Parse(split[3].Trim(), en_US);
|
||||
quat.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||
quat.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||
quat.z = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||
quat.w = float.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||
return quat;
|
||||
}
|
||||
else
|
||||
{
|
||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
||||
vector.z = float.Parse(split[2].Trim(), en_US);
|
||||
vector.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||
vector.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||
vector.z = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||
return Quaternion.Euler(vector);
|
||||
}
|
||||
}
|
||||
@ -327,12 +321,12 @@ namespace UnityExplorer
|
||||
{
|
||||
Rect rect = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
var split = input.Split(' ');
|
||||
|
||||
rect.x = float.Parse(split[0].Trim(), en_US);
|
||||
rect.y = float.Parse(split[1].Trim(), en_US);
|
||||
rect.width = float.Parse(split[2].Trim(), en_US);
|
||||
rect.height = float.Parse(split[3].Trim(), en_US);
|
||||
rect.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||
rect.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||
rect.width = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||
rect.height = float.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||
|
||||
return rect;
|
||||
}
|
||||
@ -351,13 +345,13 @@ namespace UnityExplorer
|
||||
{
|
||||
Color color = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
var split = input.Split(' ');
|
||||
|
||||
color.r = float.Parse(split[0].Trim(), en_US);
|
||||
color.g = float.Parse(split[1].Trim(), en_US);
|
||||
color.b = float.Parse(split[2].Trim(), en_US);
|
||||
color.r = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||
color.g = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||
color.b = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||
if (split.Length > 3)
|
||||
color.a = float.Parse(split[3].Trim(), en_US);
|
||||
color.a = float.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||
else
|
||||
color.a = 1;
|
||||
|
||||
@ -378,13 +372,13 @@ namespace UnityExplorer
|
||||
{
|
||||
Color32 color = default;
|
||||
|
||||
var split = input.Split(',');
|
||||
var split = input.Split(' ');
|
||||
|
||||
color.r = byte.Parse(split[0].Trim(), en_US);
|
||||
color.g = byte.Parse(split[1].Trim(), en_US);
|
||||
color.b = byte.Parse(split[2].Trim(), en_US);
|
||||
color.r = byte.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||
color.g = byte.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||
color.b = byte.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||
if (split.Length > 3)
|
||||
color.a = byte.Parse(split[3].Trim(), en_US);
|
||||
color.a = byte.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||
else
|
||||
color.a = 255;
|
||||
|
||||
@ -397,7 +391,7 @@ namespace UnityExplorer
|
||||
return null;
|
||||
|
||||
// ints, this is fine
|
||||
return $"{color.r}, {color.g}, {color.b}, {color.a}";
|
||||
return $"{color.r} {color.g} {color.b} {color.a}";
|
||||
}
|
||||
|
||||
// Layermask (Int32)
|
||||
|
@ -20,13 +20,15 @@ namespace UnityExplorer
|
||||
public static class ExplorerCore
|
||||
{
|
||||
public const string NAME = "UnityExplorer";
|
||||
public const string VERSION = "4.1.8";
|
||||
public const string VERSION = "4.2.1";
|
||||
public const string AUTHOR = "Sinai";
|
||||
public const string GUID = "com.sinai.unityexplorer";
|
||||
|
||||
public static IExplorerLoader Loader { get; private set; }
|
||||
public static RuntimeContext Context { get; internal set; }
|
||||
|
||||
public static HarmonyLib.Harmony Harmony { get; } = new HarmonyLib.Harmony(GUID);
|
||||
|
||||
/// <summary>
|
||||
/// Initialize UnityExplorer with the provided Loader implementation.
|
||||
/// </summary>
|
||||
@ -47,10 +49,9 @@ namespace UnityExplorer
|
||||
Directory.CreateDirectory(Loader.ExplorerFolder);
|
||||
|
||||
ConfigManager.Init(Loader.ConfigHandler);
|
||||
|
||||
ReflectionUtility.Init();
|
||||
|
||||
RuntimeProvider.Init();
|
||||
|
||||
SceneHandler.Init();
|
||||
InputManager.Init();
|
||||
|
||||
|
@ -8,20 +8,10 @@
|
||||
<InputAssemblies Include="..\lib\mcs-unity\mcs\bin\Release\mcs.dll" />
|
||||
<InputAssemblies Include="packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- MonoMod for MelonLoader 0.3.0 -->
|
||||
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
|
||||
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.dll" />
|
||||
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Mdb.dll" />
|
||||
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Pdb.dll" />
|
||||
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Rocks.dll" />
|
||||
<InputAssemblies Include="packages\MonoMod.RuntimeDetour.20.1.1.4\lib\net35\MonoMod.RuntimeDetour.dll" />
|
||||
<InputAssemblies Include="packages\MonoMod.Utils.20.1.1.4\lib\net35\MonoMod.Utils.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Required references for ILRepack -->
|
||||
<ItemGroup>
|
||||
<ReferenceFolders Include="packages\HarmonyX.2.4.2\lib\net35\" />
|
||||
<ReferenceFolders Include="packages\HarmonyX.2.5.2\lib\net35\" />
|
||||
<ReferenceFolders Include="..\lib\BepInEx.6.IL2CPP\" />
|
||||
<ReferenceFolders Include="..\lib\BepInEx.6.Mono\" />
|
||||
<ReferenceFolders Include="..\lib\BepInEx.5\" />
|
||||
|
@ -47,6 +47,7 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
public ScrollPool<CacheMemberCell> MemberScrollPool { get; private set; }
|
||||
|
||||
public InputFieldRef HiddenNameText;
|
||||
public Text NameText;
|
||||
public Text AssemblyText;
|
||||
private Toggle autoUpdateToggle;
|
||||
@ -125,6 +126,7 @@ namespace UnityExplorer.Inspectors
|
||||
currentBaseTabText = $"{prefix} {SignatureHighlighter.Parse(TargetType, false)}";
|
||||
Tab.TabText.text = currentBaseTabText;
|
||||
NameText.text = SignatureHighlighter.Parse(TargetType, true);
|
||||
HiddenNameText.Text = TargetType.FullName;
|
||||
|
||||
string asmText;
|
||||
if (TargetType.Assembly is AssemblyBuilder || string.IsNullOrEmpty(TargetType.Assembly.Location))
|
||||
@ -332,8 +334,27 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
// Class name, assembly
|
||||
|
||||
NameText = UIFactory.CreateLabel(UIRoot, "Title", "not set", TextAnchor.MiddleLeft, fontSize: 17);
|
||||
UIFactory.SetLayoutElement(NameText.gameObject, minHeight: 25, flexibleHeight: 0);
|
||||
var titleHolder = UIFactory.CreateUIObject("TitleHolder", UIRoot);
|
||||
UIFactory.SetLayoutElement(titleHolder, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
|
||||
NameText = UIFactory.CreateLabel(titleHolder, "VisibleTitle", "NotSet", TextAnchor.MiddleLeft);
|
||||
var namerect = NameText.GetComponent<RectTransform>();
|
||||
namerect.anchorMin = new Vector2(0, 0);
|
||||
namerect.anchorMax = new Vector2(1, 1);
|
||||
NameText.fontSize = 17;
|
||||
UIFactory.SetLayoutElement(NameText.gameObject, minHeight: 35, flexibleHeight: 0, minWidth: 300, flexibleWidth: 9999);
|
||||
|
||||
HiddenNameText = UIFactory.CreateInputField(titleHolder, "Title", "not set");
|
||||
var hiddenrect = HiddenNameText.Component.gameObject.GetComponent<RectTransform>();
|
||||
hiddenrect.anchorMin = new Vector2(0, 0);
|
||||
hiddenrect.anchorMax = new Vector2(1, 1);
|
||||
HiddenNameText.Component.readOnly = true;
|
||||
HiddenNameText.Component.lineType = InputField.LineType.MultiLineNewline;
|
||||
HiddenNameText.Component.gameObject.GetComponent<Image>().color = Color.clear;
|
||||
HiddenNameText.Component.textComponent.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
HiddenNameText.Component.textComponent.fontSize = 17;
|
||||
HiddenNameText.Component.textComponent.color = Color.clear;
|
||||
UIFactory.SetLayoutElement(HiddenNameText.Component.gameObject, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
|
||||
AssemblyText = UIFactory.CreateLabel(UIRoot, "AssemblyLabel", "not set", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(AssemblyText.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
|
@ -39,6 +39,8 @@ namespace UnityExplorer
|
||||
=> Log;
|
||||
#endif
|
||||
|
||||
public string UnhollowedModulesFolder => Path.Combine(Paths.BepInExRootPath, "unhollowed");
|
||||
|
||||
public ConfigHandler ConfigHandler => _configHandler;
|
||||
private BepInExConfigHandler _configHandler;
|
||||
|
||||
@ -51,8 +53,7 @@ namespace UnityExplorer
|
||||
public Action<object> OnLogWarning => LogSource.LogWarning;
|
||||
public Action<object> OnLogError => LogSource.LogError;
|
||||
|
||||
// Init common to Mono and Il2Cpp
|
||||
internal void UniversalInit()
|
||||
private void Init()
|
||||
{
|
||||
Instance = this;
|
||||
_configHandler = new BepInExConfigHandler();
|
||||
@ -62,57 +63,15 @@ namespace UnityExplorer
|
||||
#if MONO // Mono
|
||||
internal void Awake()
|
||||
{
|
||||
UniversalInit();
|
||||
Init();
|
||||
}
|
||||
|
||||
#else // Il2Cpp
|
||||
public override void Load()
|
||||
{
|
||||
UniversalInit();
|
||||
Init();
|
||||
}
|
||||
#endif
|
||||
|
||||
public void SetupCursorPatches()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.HarmonyInstance.PatchAll();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(EventSystem), "current", MethodType.Setter)]
|
||||
public class PATCH_EventSystem_current
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix_EventSystem_set_current(ref EventSystem value)
|
||||
{
|
||||
CursorUnlocker.Prefix_EventSystem_set_current(ref value);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(Cursor), "lockState", MethodType.Setter)]
|
||||
public class PATCH_Cursor_lockState
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix_set_lockState(ref CursorLockMode value)
|
||||
{
|
||||
CursorUnlocker.Prefix_set_lockState(ref value);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(Cursor), "visible", MethodType.Setter)]
|
||||
public class PATCH_Cursor_visible
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix_set_visible(ref bool value)
|
||||
{
|
||||
CursorUnlocker.Prefix_set_visible(ref value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -9,13 +9,12 @@ namespace UnityExplorer
|
||||
public interface IExplorerLoader
|
||||
{
|
||||
string ExplorerFolder { get; }
|
||||
string UnhollowedModulesFolder { get; }
|
||||
|
||||
ConfigHandler ConfigHandler { get; }
|
||||
|
||||
Action<object> OnLogMessage { get; }
|
||||
Action<object> OnLogWarning { get; }
|
||||
Action<object> OnLogError { get; }
|
||||
|
||||
void SetupCursorPatches();
|
||||
}
|
||||
}
|
||||
|
@ -1,86 +0,0 @@
|
||||
#if ML
|
||||
using System;
|
||||
using System.IO;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityExplorer;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.Loader.ML;
|
||||
#if ML_LEGACY
|
||||
using Harmony;
|
||||
#else
|
||||
using HarmonyLib;
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
|
||||
#endif
|
||||
|
||||
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
|
||||
[assembly: MelonGame(null, null)]
|
||||
[assembly: MelonColor(ConsoleColor.DarkCyan)]
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
public class ExplorerMelonMod : MelonMod, IExplorerLoader
|
||||
{
|
||||
public static ExplorerMelonMod Instance;
|
||||
|
||||
public string ExplorerFolder => Path.Combine("Mods", ExplorerCore.NAME);
|
||||
|
||||
public ConfigHandler ConfigHandler => _configHandler;
|
||||
public MelonLoaderConfigHandler _configHandler;
|
||||
|
||||
public Action<object> OnLogMessage => MelonLogger.Msg;
|
||||
public Action<object> OnLogWarning => MelonLogger.Warning;
|
||||
public Action<object> OnLogError => MelonLogger.Error;
|
||||
|
||||
public override void OnApplicationStart()
|
||||
{
|
||||
Instance = this;
|
||||
_configHandler = new MelonLoaderConfigHandler();
|
||||
|
||||
ExplorerCore.Init(this);
|
||||
}
|
||||
|
||||
public void SetupCursorPatches()
|
||||
{
|
||||
try
|
||||
{
|
||||
PrefixProperty(typeof(Cursor),
|
||||
"lockState",
|
||||
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_set_lockState))));
|
||||
|
||||
PrefixProperty(typeof(Cursor),
|
||||
"visible",
|
||||
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_set_visible))));
|
||||
|
||||
PrefixProperty(typeof(EventSystem),
|
||||
"current",
|
||||
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(CursorUnlocker.Prefix_EventSystem_set_current))));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
|
||||
private void PrefixProperty(Type type, string property, HarmonyMethod prefix)
|
||||
{
|
||||
try
|
||||
{
|
||||
var prop = type.GetProperty(property);
|
||||
#if ML_LEGACY
|
||||
this.Harmony.Patch(prop.GetSetMethod(), prefix: prefix);
|
||||
#else
|
||||
HarmonyInstance.Patch(prop.GetSetMethod(), prefix: prefix);
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log($"Unable to patch {type.Name}.set_{property}: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -1,206 +0,0 @@
|
||||
#if ML
|
||||
|
||||
#if !ML_LEGACY // ML 0.3.1+ config handler
|
||||
|
||||
using MelonLoader;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
|
||||
namespace UnityExplorer.Loader.ML
|
||||
{
|
||||
public class MelonLoaderConfigHandler : ConfigHandler
|
||||
{
|
||||
internal const string CTG_NAME = "UnityExplorer";
|
||||
|
||||
internal MelonPreferences_Category prefCategory;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
prefCategory = MelonPreferences.CreateCategory(CTG_NAME, $"{CTG_NAME} Settings", false, true);
|
||||
}
|
||||
|
||||
public override void LoadConfig()
|
||||
{
|
||||
foreach (var entry in ConfigManager.ConfigElements)
|
||||
{
|
||||
var key = entry.Key;
|
||||
if (prefCategory.GetEntry(key) is MelonPreferences_Entry)
|
||||
{
|
||||
var config = entry.Value;
|
||||
config.BoxedValue = config.GetLoaderConfigValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void RegisterConfigElement<T>(ConfigElement<T> config)
|
||||
{
|
||||
var entry = prefCategory.CreateEntry(config.Name, config.Value, null, config.Description, config.IsInternal, false);
|
||||
|
||||
entry.OnValueChangedUntyped += () =>
|
||||
{
|
||||
if ((entry.Value == null && config.Value == null) || config.Value.Equals(entry.Value))
|
||||
return;
|
||||
|
||||
config.Value = entry.Value;
|
||||
};
|
||||
}
|
||||
|
||||
public override void SetConfigValue<T>(ConfigElement<T> config, T value)
|
||||
{
|
||||
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
|
||||
{
|
||||
entry.Value = value;
|
||||
//entry.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public override T GetConfigValue<T>(ConfigElement<T> config)
|
||||
{
|
||||
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
|
||||
return entry.Value;
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public override void OnAnyConfigChanged()
|
||||
{
|
||||
}
|
||||
|
||||
public override void SaveConfig()
|
||||
{
|
||||
MelonPreferences.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // ML 0.3.0 config handler
|
||||
|
||||
using MelonLoader;
|
||||
using MelonLoader.Tomlyn.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
|
||||
namespace UnityExplorer.Loader.ML
|
||||
{
|
||||
public class MelonLoaderConfigHandler : ConfigHandler
|
||||
{
|
||||
internal const string CTG_NAME = "UnityExplorer";
|
||||
|
||||
internal MelonPreferences_Category prefCategory;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
prefCategory = MelonPreferences.CreateCategory(CTG_NAME, $"{CTG_NAME} Settings");
|
||||
|
||||
try { MelonPreferences.Mapper.RegisterMapper(KeycodeReader, KeycodeWriter); } catch { }
|
||||
try { MelonPreferences.Mapper.RegisterMapper(AnchorReader, AnchorWriter); } catch { }
|
||||
}
|
||||
|
||||
public override void LoadConfig()
|
||||
{
|
||||
foreach (var entry in ConfigManager.ConfigElements)
|
||||
{
|
||||
var key = entry.Key;
|
||||
if (prefCategory.GetEntry(key) is MelonPreferences_Entry)
|
||||
{
|
||||
var config = entry.Value;
|
||||
config.BoxedValue = config.GetLoaderConfigValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void RegisterConfigElement<T>(ConfigElement<T> config)
|
||||
{
|
||||
var entry = prefCategory.CreateEntry(config.Name, config.Value, null, config.IsInternal) as MelonPreferences_Entry<T>;
|
||||
|
||||
entry.OnValueChangedUntyped += () =>
|
||||
{
|
||||
if ((entry.Value == null && config.Value == null) || config.Value.Equals(entry.Value))
|
||||
return;
|
||||
|
||||
config.Value = entry.Value;
|
||||
};
|
||||
}
|
||||
|
||||
public override void SetConfigValue<T>(ConfigElement<T> config, T value)
|
||||
{
|
||||
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
|
||||
{
|
||||
entry.Value = value;
|
||||
entry.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public override T GetConfigValue<T>(ConfigElement<T> config)
|
||||
{
|
||||
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
|
||||
return entry.Value;
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public override void OnAnyConfigChanged()
|
||||
{
|
||||
}
|
||||
|
||||
public override void SaveConfig()
|
||||
{
|
||||
MelonPreferences.Save();
|
||||
}
|
||||
|
||||
// Enum config handlers
|
||||
|
||||
public static KeyCode KeycodeReader(TomlObject value)
|
||||
{
|
||||
try
|
||||
{
|
||||
KeyCode kc = (KeyCode)Enum.Parse(typeof(KeyCode), (value as TomlString).Value);
|
||||
|
||||
if (kc == default)
|
||||
throw new Exception();
|
||||
|
||||
return kc;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return KeyCode.F7;
|
||||
}
|
||||
}
|
||||
|
||||
public static TomlObject KeycodeWriter(KeyCode value)
|
||||
{
|
||||
return MelonPreferences.Mapper.ToToml(value.ToString());
|
||||
}
|
||||
|
||||
public static UI.UIManager.VerticalAnchor AnchorReader(TomlObject value)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (UI.UIManager.VerticalAnchor)Enum.Parse(typeof(UI.UIManager.VerticalAnchor), (value as TomlString).Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return UI.UIManager.VerticalAnchor.Top;
|
||||
}
|
||||
}
|
||||
|
||||
public static TomlObject AnchorWriter(UI.UIManager.VerticalAnchor anchor)
|
||||
{
|
||||
return MelonPreferences.Mapper.ToToml(anchor.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
47
src/Loader/MelonLoader/ExplorerMelonMod.cs
Normal file
47
src/Loader/MelonLoader/ExplorerMelonMod.cs
Normal file
@ -0,0 +1,47 @@
|
||||
#if ML
|
||||
using System;
|
||||
using System.IO;
|
||||
using MelonLoader;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityExplorer;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.Loader.ML;
|
||||
using HarmonyLib;
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
|
||||
|
||||
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
|
||||
[assembly: MelonGame(null, null)]
|
||||
[assembly: MelonColor(ConsoleColor.DarkCyan)]
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
public class ExplorerMelonMod : MelonMod, IExplorerLoader
|
||||
{
|
||||
public static ExplorerMelonMod Instance;
|
||||
|
||||
public string ExplorerFolder => Path.Combine("Mods", ExplorerCore.NAME);
|
||||
|
||||
public string UnhollowedModulesFolder => Path.Combine(
|
||||
Path.GetDirectoryName(MelonHandler.ModsDirectory),
|
||||
Path.Combine("MelonLoader", "Managed"));
|
||||
|
||||
public ConfigHandler ConfigHandler => _configHandler;
|
||||
public MelonLoaderConfigHandler _configHandler;
|
||||
|
||||
public Action<object> OnLogMessage => MelonLogger.Msg;
|
||||
public Action<object> OnLogWarning => MelonLogger.Warning;
|
||||
public Action<object> OnLogError => MelonLogger.Error;
|
||||
|
||||
public override void OnApplicationStart()
|
||||
{
|
||||
Instance = this;
|
||||
_configHandler = new MelonLoaderConfigHandler();
|
||||
|
||||
ExplorerCore.Init(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
94
src/Loader/MelonLoader/MelonLoaderConfigHandler.cs
Normal file
94
src/Loader/MelonLoader/MelonLoaderConfigHandler.cs
Normal file
@ -0,0 +1,94 @@
|
||||
#if ML
|
||||
using MelonLoader;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
|
||||
namespace UnityExplorer.Loader.ML
|
||||
{
|
||||
public class MelonLoaderConfigHandler : ConfigHandler
|
||||
{
|
||||
internal const string CTG_NAME = "UnityExplorer";
|
||||
|
||||
internal MelonPreferences_Category prefCategory;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
prefCategory = MelonPreferences.CreateCategory(CTG_NAME, $"{CTG_NAME} Settings", false, true);
|
||||
}
|
||||
|
||||
public override void LoadConfig()
|
||||
{
|
||||
foreach (var entry in ConfigManager.ConfigElements)
|
||||
{
|
||||
var key = entry.Key;
|
||||
if (prefCategory.GetEntry(key) is MelonPreferences_Entry)
|
||||
{
|
||||
var config = entry.Value;
|
||||
config.BoxedValue = config.GetLoaderConfigValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This wrapper exists to handle the arbitrary "LemonAction" delegates which ML now uses in 0.4.4+.
|
||||
// Reflection is required since the delegate type changed between 0.4.3 and 0.4.4.
|
||||
// A wrapper class is required to link the MelonPreferences_Entry and the delegate instance.
|
||||
public class EntryDelegateWrapper<T>
|
||||
{
|
||||
public MelonPreferences_Entry<T> entry;
|
||||
public ConfigElement<T> config;
|
||||
|
||||
public EntryDelegateWrapper(MelonPreferences_Entry<T> entry, ConfigElement<T> config)
|
||||
{
|
||||
this.entry = entry;
|
||||
this.config = config;
|
||||
var evt = entry.GetType().GetEvent("OnValueChangedUntyped");
|
||||
evt.AddEventHandler(entry, Delegate.CreateDelegate(evt.EventHandlerType, this, GetType().GetMethod("OnChanged")));
|
||||
}
|
||||
|
||||
public void OnChanged()
|
||||
{
|
||||
if ((entry.Value == null && config.Value == null) || config.Value.Equals(entry.Value))
|
||||
return;
|
||||
config.Value = entry.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void RegisterConfigElement<T>(ConfigElement<T> config)
|
||||
{
|
||||
var entry = prefCategory.CreateEntry(config.Name, config.Value, null, config.Description, config.IsInternal, false);
|
||||
new EntryDelegateWrapper<T>(entry, config);
|
||||
}
|
||||
|
||||
public override void SetConfigValue<T>(ConfigElement<T> config, T value)
|
||||
{
|
||||
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
|
||||
{
|
||||
entry.Value = value;
|
||||
//entry.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public override T GetConfigValue<T>(ConfigElement<T> config)
|
||||
{
|
||||
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
|
||||
return entry.Value;
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public override void OnAnyConfigChanged()
|
||||
{
|
||||
}
|
||||
|
||||
public override void SaveConfig()
|
||||
{
|
||||
MelonPreferences.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -18,26 +18,43 @@ namespace UnityExplorer
|
||||
public class ExplorerStandalone : IExplorerLoader
|
||||
{
|
||||
/// <summary>
|
||||
/// Call this to initialize UnityExplorer without adding a log listener.
|
||||
/// Call this to initialize UnityExplorer without adding a log listener or Unhollowed modules path.
|
||||
/// The default Unhollowed path "UnityExplorer\Modules\" will be used.
|
||||
/// </summary>
|
||||
/// <returns>The new (or active, if one exists) instance of ExplorerStandalone.</returns>
|
||||
public static ExplorerStandalone CreateInstance()
|
||||
=> CreateInstance(null);
|
||||
public static ExplorerStandalone CreateInstance() => CreateInstance(null, null);
|
||||
|
||||
/// <summary>
|
||||
/// Call this to initialize UnityExplorer and add a listener for UnityExplorer's log messages.
|
||||
/// Call this to initialize UnityExplorer and add a listener for UnityExplorer's log messages, without specifying an Unhollowed modules path.
|
||||
/// The default Unhollowed path "UnityExplorer\Modules\" will be used.
|
||||
/// </summary>
|
||||
/// <param name="logListener">Your log listener to handle UnityExplorer logs.</param>
|
||||
/// <returns>The new (or active, if one exists) instance of ExplorerStandalone.</returns>
|
||||
public static ExplorerStandalone CreateInstance(Action<string, LogType> logListener)
|
||||
public static ExplorerStandalone CreateInstance(Action<string, LogType> logListener) => CreateInstance(logListener, null);
|
||||
|
||||
/// <summary>
|
||||
/// Call this to initialize UnityExplorer with the provided log listener and Unhollowed modules path.
|
||||
/// </summary>
|
||||
/// <param name="logListener">Your log listener to handle UnityExplorer logs.</param>
|
||||
/// <param name="unhollowedModulesPath">The path of the Unhollowed modules, either relative or absolute.</param>
|
||||
/// <returns>The new (or active, if one exists) instance of ExplorerStandalone.</returns>
|
||||
public static ExplorerStandalone CreateInstance(Action<string, LogType> logListener, string unhollowedModulesPath)
|
||||
{
|
||||
if (Instance != null)
|
||||
return Instance;
|
||||
|
||||
OnLog += logListener;
|
||||
|
||||
var instance = new ExplorerStandalone();
|
||||
instance.Init();
|
||||
instance.CheckExplorerFolder();
|
||||
|
||||
if (logListener != null)
|
||||
OnLog += logListener;
|
||||
|
||||
if (string.IsNullOrEmpty(unhollowedModulesPath) || !Directory.Exists(unhollowedModulesPath))
|
||||
instance._unhollowedPath = Path.Combine(instance.ExplorerFolder, "Modules");
|
||||
else
|
||||
instance._unhollowedPath = unhollowedModulesPath;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@ -48,8 +65,8 @@ namespace UnityExplorer
|
||||
/// </summary>
|
||||
public static event Action<string, LogType> OnLog;
|
||||
|
||||
public Harmony HarmonyInstance => s_harmony;
|
||||
public static readonly Harmony s_harmony = new Harmony(ExplorerCore.GUID);
|
||||
public string UnhollowedModulesFolder => _unhollowedPath;
|
||||
private string _unhollowedPath;
|
||||
|
||||
public ConfigHandler ConfigHandler => _configHandler;
|
||||
private StandaloneConfigHandler _configHandler;
|
||||
@ -58,19 +75,7 @@ namespace UnityExplorer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_explorerFolder == null)
|
||||
{
|
||||
s_explorerFolder =
|
||||
Path.Combine(
|
||||
Path.GetDirectoryName(
|
||||
Uri.UnescapeDataString(new Uri(Assembly.GetExecutingAssembly().CodeBase)
|
||||
.AbsolutePath)),
|
||||
"UnityExplorer");
|
||||
|
||||
if (!Directory.Exists(s_explorerFolder))
|
||||
Directory.CreateDirectory(s_explorerFolder);
|
||||
}
|
||||
|
||||
CheckExplorerFolder();
|
||||
return s_explorerFolder;
|
||||
}
|
||||
}
|
||||
@ -88,45 +93,18 @@ namespace UnityExplorer
|
||||
ExplorerCore.Init(this);
|
||||
}
|
||||
|
||||
public void SetupCursorPatches()
|
||||
private void CheckExplorerFolder()
|
||||
{
|
||||
try
|
||||
if (s_explorerFolder == null)
|
||||
{
|
||||
this.HarmonyInstance.PatchAll();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
s_explorerFolder =
|
||||
Path.Combine(
|
||||
Path.GetDirectoryName(
|
||||
Uri.UnescapeDataString(new Uri(Assembly.GetExecutingAssembly().CodeBase).AbsolutePath)),
|
||||
"UnityExplorer");
|
||||
|
||||
[HarmonyPatch(typeof(EventSystem), "current", MethodType.Setter)]
|
||||
public class PATCH_EventSystem_current
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix_EventSystem_set_current(ref EventSystem value)
|
||||
{
|
||||
CursorUnlocker.Prefix_EventSystem_set_current(ref value);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(Cursor), "lockState", MethodType.Setter)]
|
||||
public class PATCH_Cursor_lockState
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix_set_lockState(ref CursorLockMode value)
|
||||
{
|
||||
CursorUnlocker.Prefix_set_lockState(ref value);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(Cursor), "visible", MethodType.Setter)]
|
||||
public class PATCH_Cursor_visible
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix_set_visible(ref bool value)
|
||||
{
|
||||
CursorUnlocker.Prefix_set_visible(ref value);
|
||||
if (!Directory.Exists(s_explorerFolder))
|
||||
Directory.CreateDirectory(s_explorerFolder);
|
||||
}
|
||||
}
|
||||
}
|
@ -56,13 +56,7 @@ namespace UnityExplorer.ObjectExplorer
|
||||
else if (m_context == SearchContext.Class)
|
||||
currentResults = SearchProvider.ClassSearch(nameInputField.Text);
|
||||
else
|
||||
{
|
||||
string compType = "";
|
||||
if (m_context == SearchContext.UnityObject)
|
||||
compType = this.desiredTypeInput;
|
||||
|
||||
currentResults = SearchProvider.UnityObjectSearch(nameInputField.Text, compType, m_context, m_childFilter, m_sceneFilter);
|
||||
}
|
||||
currentResults = SearchProvider.UnityObjectSearch(nameInputField.Text, desiredTypeInput, m_context, m_childFilter, m_sceneFilter);
|
||||
|
||||
dataHandler.RefreshData();
|
||||
resultsScrollPool.Refresh(true);
|
||||
|
@ -114,7 +114,7 @@ namespace UnityExplorer.ObjectExplorer
|
||||
refreshRow.SetActive(!scene.IsValid());
|
||||
}
|
||||
|
||||
private void SceneHandler_OnLoadedScenesChanged(ReadOnlyCollection<Scene> loadedScenes)
|
||||
private void SceneHandler_OnLoadedScenesChanged(List<Scene> loadedScenes)
|
||||
{
|
||||
PopulateSceneDropdown();
|
||||
}
|
||||
@ -126,6 +126,9 @@ namespace UnityExplorer.ObjectExplorer
|
||||
|
||||
foreach (var scene in SceneHandler.LoadedScenes)
|
||||
{
|
||||
if (sceneToDropdownOption.ContainsKey(scene))
|
||||
continue;
|
||||
|
||||
string name = scene.name?.Trim();
|
||||
|
||||
if (!scene.IsValid())
|
||||
|
@ -29,27 +29,23 @@ namespace UnityExplorer.ObjectExplorer
|
||||
/// <summary>
|
||||
/// The GameObjects in the currently inspected scene.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<GameObject> CurrentRootObjects => new ReadOnlyCollection<GameObject>(rootObjects);
|
||||
private static GameObject[] rootObjects = new GameObject[0];
|
||||
public static GameObject[] CurrentRootObjects { get; private set; } = new GameObject[0];
|
||||
|
||||
/// <summary>
|
||||
/// All currently loaded Scenes.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<Scene> LoadedScenes => new ReadOnlyCollection<Scene>(allLoadedScenes);
|
||||
private static readonly List<Scene> allLoadedScenes = new List<Scene>();
|
||||
public static List<Scene> LoadedScenes { get; private set; } = new List<Scene>();
|
||||
private static HashSet<Scene> previousLoadedScenes;
|
||||
|
||||
/// <summary>
|
||||
/// The names of all scenes in the build settings, if they could be retrieved.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<string> AllSceneNames => new ReadOnlyCollection<string>(allScenesInBuild);
|
||||
private static readonly List<string> allScenesInBuild = new List<string>();
|
||||
public static readonly List<string> AllSceneNames = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not we successfuly retrieved the names of the scenes in the build settings.
|
||||
/// </summary>
|
||||
public static bool WasAbleToGetScenesInBuild => gotAllScenesInBuild;
|
||||
private static bool gotAllScenesInBuild = true;
|
||||
public static bool WasAbleToGetScenesInBuild { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the currently inspected Scene changes. The argument is the new scene.
|
||||
@ -59,7 +55,7 @@ namespace UnityExplorer.ObjectExplorer
|
||||
/// <summary>
|
||||
/// Invoked whenever the list of currently loaded Scenes changes. The argument contains all loaded scenes after the change.
|
||||
/// </summary>
|
||||
public static event Action<ReadOnlyCollection<Scene>> OnLoadedScenesChanged;
|
||||
public static event Action<List<Scene>> OnLoadedScenesChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Equivalent to <see cref="SceneManager.sceneCount"/> + 2, to include 'DontDestroyOnLoad' and the 'None' scene.
|
||||
@ -99,12 +95,12 @@ namespace UnityExplorer.ObjectExplorer
|
||||
for (int i = 0; i < sceneCount; i++)
|
||||
{
|
||||
var scenePath = (string)method.Invoke(null, new object[] { i });
|
||||
allScenesInBuild.Add(scenePath);
|
||||
AllSceneNames.Add(scenePath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
gotAllScenesInBuild = false;
|
||||
WasAbleToGetScenesInBuild = false;
|
||||
ExplorerCore.LogWarning($"Unable to generate list of all Scenes in the build: {ex}");
|
||||
}
|
||||
}
|
||||
@ -115,7 +111,7 @@ namespace UnityExplorer.ObjectExplorer
|
||||
int confirmedCount = 2;
|
||||
bool inspectedExists = SelectedScene == DontDestroyScene || (SelectedScene.HasValue && SelectedScene.Value == default);
|
||||
|
||||
allLoadedScenes.Clear();
|
||||
LoadedScenes.Clear();
|
||||
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
@ -131,30 +127,26 @@ namespace UnityExplorer.ObjectExplorer
|
||||
if (!inspectedExists && scene == SelectedScene)
|
||||
inspectedExists = true;
|
||||
|
||||
allLoadedScenes.Add(scene);
|
||||
LoadedScenes.Add(scene);
|
||||
}
|
||||
|
||||
bool anyChange = confirmedCount != allLoadedScenes.Count;
|
||||
bool anyChange = confirmedCount != LoadedScenes.Count;
|
||||
|
||||
allLoadedScenes.Add(DontDestroyScene);
|
||||
allLoadedScenes.Add(default);
|
||||
previousLoadedScenes = new HashSet<Scene>(allLoadedScenes);
|
||||
LoadedScenes.Add(DontDestroyScene);
|
||||
LoadedScenes.Add(default);
|
||||
previousLoadedScenes = new HashSet<Scene>(LoadedScenes);
|
||||
|
||||
// Default to first scene if none selected or previous selection no longer exists.
|
||||
if (!inspectedExists)
|
||||
{
|
||||
SelectedScene = allLoadedScenes.First();
|
||||
}
|
||||
SelectedScene = LoadedScenes.First();
|
||||
|
||||
// Notify on the list changing at all
|
||||
if (anyChange)
|
||||
{
|
||||
OnLoadedScenesChanged?.Invoke(LoadedScenes);
|
||||
}
|
||||
|
||||
// Finally, update the root objects list.
|
||||
if (SelectedScene != null && ((Scene)SelectedScene).IsValid())
|
||||
rootObjects = RuntimeProvider.Instance.GetRootGameObjects((Scene)SelectedScene);
|
||||
CurrentRootObjects = RuntimeProvider.Instance.GetRootGameObjects((Scene)SelectedScene);
|
||||
else
|
||||
{
|
||||
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GameObject));
|
||||
@ -165,7 +157,7 @@ namespace UnityExplorer.ObjectExplorer
|
||||
if (go.transform.parent == null && !go.scene.IsValid())
|
||||
objects.Add(go);
|
||||
}
|
||||
rootObjects = objects.ToArray();
|
||||
CurrentRootObjects = objects.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
BIN
src/Resources/legacy.5.6.bundle
Normal file
BIN
src/Resources/legacy.5.6.bundle
Normal file
Binary file not shown.
BIN
src/Resources/legacy.bundle
Normal file
BIN
src/Resources/legacy.bundle
Normal file
Binary file not shown.
BIN
src/Resources/modern.bundle
Normal file
BIN
src/Resources/modern.bundle
Normal file
Binary file not shown.
@ -209,6 +209,10 @@ namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
ExplorerCore.LogWarning("Invalid or corrupt panel save data! Restoring to default.");
|
||||
SetTransformDefaults();
|
||||
UIManager.Initializing = false;
|
||||
DoSaveToConfigElement();
|
||||
ConfigManager.InternalHandler.SaveConfig();
|
||||
UIManager.Initializing = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,7 +339,7 @@ namespace UnityExplorer.UI.Panels
|
||||
if (!rect)
|
||||
throw new ArgumentNullException("rect");
|
||||
|
||||
return string.Format(ParseUtility.en_US, "{0},{1},{2},{3}", new object[]
|
||||
return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", new object[]
|
||||
{
|
||||
rect.anchorMin.x,
|
||||
rect.anchorMin.y,
|
||||
@ -349,16 +353,20 @@ namespace UnityExplorer.UI.Panels
|
||||
if (string.IsNullOrEmpty(stringAnchors))
|
||||
throw new ArgumentNullException("stringAnchors");
|
||||
|
||||
if (stringAnchors.Contains(" "))
|
||||
// outdated save data, not worth recovering just reset it.
|
||||
throw new Exception("invalid save data, resetting.");
|
||||
|
||||
var split = stringAnchors.Split(',');
|
||||
|
||||
if (split.Length != 4)
|
||||
throw new Exception($"stringAnchors split is unexpected length: {split.Length}");
|
||||
|
||||
Vector4 anchors;
|
||||
anchors.x = float.Parse(split[0], ParseUtility.en_US);
|
||||
anchors.y = float.Parse(split[1], ParseUtility.en_US);
|
||||
anchors.z = float.Parse(split[2], ParseUtility.en_US);
|
||||
anchors.w = float.Parse(split[3], ParseUtility.en_US);
|
||||
anchors.x = float.Parse(split[0], CultureInfo.InvariantCulture);
|
||||
anchors.y = float.Parse(split[1], CultureInfo.InvariantCulture);
|
||||
anchors.z = float.Parse(split[2], CultureInfo.InvariantCulture);
|
||||
anchors.w = float.Parse(split[3], CultureInfo.InvariantCulture);
|
||||
|
||||
panel.anchorMin = new Vector2(anchors.x, anchors.y);
|
||||
panel.anchorMax = new Vector2(anchors.z, anchors.w);
|
||||
@ -369,7 +377,7 @@ namespace UnityExplorer.UI.Panels
|
||||
if (!rect)
|
||||
throw new ArgumentNullException("rect");
|
||||
|
||||
return string.Format(ParseUtility.en_US, "{0},{1}", new object[]
|
||||
return string.Format(CultureInfo.InvariantCulture, "{0},{1}", new object[]
|
||||
{
|
||||
rect.localPosition.x, rect.localPosition.y
|
||||
});
|
||||
@ -377,14 +385,21 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
internal static void SetPositionFromString(this RectTransform rect, string stringPosition)
|
||||
{
|
||||
if (string.IsNullOrEmpty(stringPosition))
|
||||
throw new ArgumentNullException(stringPosition);
|
||||
|
||||
if (stringPosition.Contains(" "))
|
||||
// outdated save data, not worth recovering just reset it.
|
||||
throw new Exception("invalid save data, resetting.");
|
||||
|
||||
var split = stringPosition.Split(',');
|
||||
|
||||
if (split.Length != 2)
|
||||
throw new Exception($"stringPosition split is unexpected length: {split.Length}");
|
||||
|
||||
Vector3 vector = rect.localPosition;
|
||||
vector.x = float.Parse(split[0], ParseUtility.en_US);
|
||||
vector.y = float.Parse(split[1], ParseUtility.en_US);
|
||||
vector.x = float.Parse(split[0], CultureInfo.InvariantCulture);
|
||||
vector.y = float.Parse(split[1], CultureInfo.InvariantCulture);
|
||||
rect.localPosition = vector;
|
||||
}
|
||||
}
|
||||
|
@ -16,12 +16,6 @@ namespace UnityExplorer.UI
|
||||
internal static Vector2 _largeElementSize = new Vector2(100, 30);
|
||||
internal static Vector2 _smallElementSize = new Vector2(25, 25);
|
||||
internal static Color _defaultTextColor = Color.white;
|
||||
internal static Font _defaultFont;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_defaultFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||||
}
|
||||
|
||||
public static GameObject CreateUIObject(string name, GameObject parent, Vector2 size = default)
|
||||
{
|
||||
@ -48,7 +42,7 @@ namespace UnityExplorer.UI
|
||||
internal static void SetDefaultTextValues(Text text)
|
||||
{
|
||||
text.color = _defaultTextColor;
|
||||
text.font = _defaultFont;
|
||||
text.font = UIManager.DefaultFont;
|
||||
text.fontSize = 14;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace UnityExplorer.UI
|
||||
Bottom
|
||||
}
|
||||
|
||||
public static bool Initializing { get; private set; } = true;
|
||||
public static bool Initializing { get; internal set; } = true;
|
||||
|
||||
private static readonly Dictionary<Panels, UIPanel> UIPanels = new Dictionary<Panels, UIPanel>();
|
||||
|
||||
@ -52,6 +52,7 @@ namespace UnityExplorer.UI
|
||||
internal static GameObject PanelHolder { get; private set; }
|
||||
|
||||
internal static Font ConsoleFont { get; private set; }
|
||||
internal static Font DefaultFont { get; private set; }
|
||||
internal static Shader BackupShader { get; private set; }
|
||||
|
||||
public static RectTransform NavBarRect;
|
||||
@ -92,8 +93,6 @@ namespace UnityExplorer.UI
|
||||
{
|
||||
LoadBundle();
|
||||
|
||||
UIFactory.Init();
|
||||
|
||||
CreateRootCanvas();
|
||||
|
||||
// Global UI Pool Holder
|
||||
@ -121,6 +120,12 @@ namespace UnityExplorer.UI
|
||||
lastScreenWidth = Screen.width;
|
||||
lastScreenHeight = Screen.height;
|
||||
|
||||
// Failsafe fix
|
||||
foreach (var dropdown in CanvasRoot.GetComponentsInChildren<Dropdown>(true))
|
||||
dropdown.RefreshShownValue();
|
||||
timeInput.Text = string.Empty;
|
||||
timeInput.Text = Time.timeScale.ToString();
|
||||
|
||||
Initializing = false;
|
||||
}
|
||||
|
||||
@ -404,28 +409,57 @@ namespace UnityExplorer.UI
|
||||
closeBtn.OnClick += OnCloseButtonClicked;
|
||||
}
|
||||
|
||||
#region UI AssetBundle
|
||||
// UI AssetBundle
|
||||
|
||||
private static void LoadBundle()
|
||||
{
|
||||
AssetBundle bundle = null;
|
||||
AssetBundle bundle;
|
||||
try
|
||||
{
|
||||
bundle = LoadBundle("modern");
|
||||
if (bundle == null)
|
||||
bundle = LoadBundle("legacy");
|
||||
// Get the Major and Minor of the Unity version
|
||||
var split = Application.unityVersion.Split('.');
|
||||
int major = int.Parse(split[0]);
|
||||
int minor = int.Parse(split[1]);
|
||||
|
||||
// Use appropriate AssetBundle for Unity version
|
||||
// >= 2017
|
||||
if (major >= 2017)
|
||||
bundle = LoadBundle("modern");
|
||||
// 5.6.0 to <2017
|
||||
else if (major == 5 && minor >= 6)
|
||||
bundle = LoadBundle("legacy.5.6");
|
||||
// < 5.6.0
|
||||
else
|
||||
bundle = LoadBundle("legacy");
|
||||
}
|
||||
catch
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception parsing Unity version, falling back to old AssetBundle load method...");
|
||||
bundle = LoadBundle("modern") ?? LoadBundle("legacy.5.6") ?? LoadBundle("legacy");
|
||||
}
|
||||
|
||||
AssetBundle LoadBundle(string id)
|
||||
{
|
||||
ExplorerCore.Log($"Loading {id} bundle for Unity {Application.unityVersion}");
|
||||
|
||||
return AssetBundle.LoadFromMemory(ReadFully(typeof(ExplorerCore)
|
||||
.Assembly
|
||||
.GetManifestResourceStream($"UnityExplorer.Resources.{id}.bundle")));
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (bundle == null)
|
||||
{
|
||||
ExplorerCore.LogWarning("Could not load the ExplorerUI Bundle!");
|
||||
ConsoleFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
|
||||
DefaultFont = ConsoleFont;
|
||||
return;
|
||||
}
|
||||
|
||||
BackupShader = bundle.LoadAsset<Shader>("DefaultUI");
|
||||
// Bundle loaded
|
||||
ConsoleFont = bundle.LoadAsset<Font>("CONSOLA");
|
||||
DefaultFont = bundle.LoadAsset<Font>("arial");
|
||||
|
||||
BackupShader = bundle.LoadAsset<Shader>("DefaultUI");
|
||||
// Fix for games which don't ship with 'UI/Default' shader.
|
||||
if (Graphic.defaultGraphicMaterial.shader?.name != "UI/Default")
|
||||
{
|
||||
@ -435,15 +469,6 @@ namespace UnityExplorer.UI
|
||||
else
|
||||
BackupShader = Graphic.defaultGraphicMaterial.shader;
|
||||
|
||||
ConsoleFont = bundle.LoadAsset<Font>("CONSOLA");
|
||||
}
|
||||
|
||||
private static AssetBundle LoadBundle(string id)
|
||||
{
|
||||
var stream = typeof(ExplorerCore).Assembly
|
||||
.GetManifestResourceStream($"UnityExplorer.Resources.explorerui.{id}.bundle");
|
||||
|
||||
return AssetBundle.LoadFromMemory(ReadFully(stream));
|
||||
}
|
||||
|
||||
private static byte[] ReadFully(Stream input)
|
||||
@ -457,7 +482,5 @@ namespace UnityExplorer.UI
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -93,24 +93,6 @@
|
||||
<IsCpp>true</IsCpp>
|
||||
<IsStandalone>true</IsStandalone>
|
||||
</PropertyGroup>
|
||||
<!-- ML 0.3.0 CPP -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_MLLegacy_Cpp|AnyCPU'">
|
||||
<OutputPath>..\Release\UnityExplorer.MelonLoader_Legacy.Il2Cpp\</OutputPath>
|
||||
<DefineConstants>CPP,ML,ML_LEGACY</DefineConstants>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<AssemblyName>UnityExplorer.MLLEGACY.IL2CPP</AssemblyName>
|
||||
<IsCpp>true</IsCpp>
|
||||
<IsMelonLoaderLegacy>true</IsMelonLoaderLegacy>
|
||||
</PropertyGroup>
|
||||
<!-- ML 0.3.0 Mono -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_MLLegacy_Mono|AnyCPU'">
|
||||
<OutputPath>..\Release\UnityExplorer.MelonLoader_Legacy.Mono\</OutputPath>
|
||||
<DefineConstants>MONO,ML,ML_LEGACY</DefineConstants>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<AssemblyName>UnityExplorer.MLLEGACY.Mono</AssemblyName>
|
||||
<IsCpp>false</IsCpp>
|
||||
<IsMelonLoaderLegacy>true</IsMelonLoaderLegacy>
|
||||
</PropertyGroup>
|
||||
<!-- Global refs, Mono and Il2Cpp -->
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@ -135,17 +117,10 @@
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<!-- MelonLoader Legacy refs -->
|
||||
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>..\lib\MelonLoader_Legacy\MelonLoader.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<!-- BepInEx universal refs -->
|
||||
<ItemGroup Condition="'$(IsBepInEx)'=='true'">
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>packages\HarmonyX.2.4.2\lib\net35\0Harmony.dll</HintPath>
|
||||
<HintPath>packages\HarmonyX.2.5.2\lib\net35\0Harmony.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
@ -181,7 +156,7 @@
|
||||
<!-- Standalone refs -->
|
||||
<ItemGroup Condition="'$(IsStandalone)'=='true'">
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>packages\HarmonyX.2.4.2\lib\net35\0Harmony.dll</HintPath>
|
||||
<HintPath>packages\HarmonyX.2.5.2\lib\net35\0Harmony.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
@ -243,6 +218,7 @@
|
||||
<Compile Include="Core\Config\InternalConfigHandler.cs" />
|
||||
<Compile Include="CacheObject\CacheConfigEntry.cs" />
|
||||
<Compile Include="CacheObject\Views\CacheConfigCell.cs" />
|
||||
<Compile Include="Core\Reflection\Patches.cs" />
|
||||
<Compile Include="CSConsole\CSAutoCompleter.cs" />
|
||||
<Compile Include="CSConsole\LexerBuilder.cs" />
|
||||
<Compile Include="CSConsole\Lexers\CommentLexer.cs" />
|
||||
@ -323,13 +299,13 @@
|
||||
<Compile Include="Core\Tests\TestClass.cs" />
|
||||
<Compile Include="Core\Utility\UnityHelpers.cs" />
|
||||
<Compile Include="ExplorerCore.cs" />
|
||||
<Compile Include="Loader\BIE\BepInExConfigHandler.cs" />
|
||||
<Compile Include="Loader\BIE\ExplorerBepInPlugin.cs" />
|
||||
<Compile Include="Loader\BepInEx\BepInExConfigHandler.cs" />
|
||||
<Compile Include="Loader\BepInEx\ExplorerBepInPlugin.cs" />
|
||||
<Compile Include="Loader\IExplorerLoader.cs" />
|
||||
<Compile Include="Loader\ML\ExplorerMelonMod.cs" />
|
||||
<Compile Include="Loader\ML\MelonLoaderConfigHandler.cs" />
|
||||
<Compile Include="Loader\STANDALONE\ExplorerStandalone.cs" />
|
||||
<Compile Include="Loader\STANDALONE\StandaloneConfigHandler.cs" />
|
||||
<Compile Include="Loader\MelonLoader\ExplorerMelonMod.cs" />
|
||||
<Compile Include="Loader\MelonLoader\MelonLoaderConfigHandler.cs" />
|
||||
<Compile Include="Loader\Standalone\ExplorerStandalone.cs" />
|
||||
<Compile Include="Loader\Standalone\StandaloneConfigHandler.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="UI\Models\UIBehaviourModel.cs" />
|
||||
<Compile Include="UI\Models\UIModel.cs" />
|
||||
|
@ -16,8 +16,6 @@ Global
|
||||
Release_BIE6_Mono|Any CPU = Release_BIE6_Mono|Any CPU
|
||||
Release_ML_Cpp|Any CPU = Release_ML_Cpp|Any CPU
|
||||
Release_ML_Mono|Any CPU = Release_ML_Mono|Any CPU
|
||||
Release_MLLegacy_Cpp|Any CPU = Release_MLLegacy_Cpp|Any CPU
|
||||
Release_MLLegacy_Mono|Any CPU = Release_MLLegacy_Mono|Any CPU
|
||||
Release_STANDALONE_Cpp|Any CPU = Release_STANDALONE_Cpp|Any CPU
|
||||
Release_STANDALONE_Mono|Any CPU = Release_STANDALONE_Mono|Any CPU
|
||||
EndGlobalSection
|
||||
@ -32,10 +30,6 @@ Global
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_ML_Cpp|Any CPU.Build.0 = Release|Any CPU
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_ML_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_ML_Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_MLLegacy_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_MLLegacy_Cpp|Any CPU.Build.0 = Release|Any CPU
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_MLLegacy_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_MLLegacy_Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release|Any CPU
|
||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@ -50,10 +44,6 @@ Global
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_ML_Cpp|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_ML_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_ML_Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_MLLegacy_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_MLLegacy_Cpp|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_MLLegacy_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_MLLegacy_Mono|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release|Any CPU
|
||||
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@ -68,10 +58,6 @@ Global
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Cpp|Any CPU.Build.0 = Release_ML_Cpp|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Mono|Any CPU.ActiveCfg = Release_ML_Mono|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Mono|Any CPU.Build.0 = Release_ML_Mono|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_MLLegacy_Cpp|Any CPU.ActiveCfg = Release_MLLegacy_Cpp|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_MLLegacy_Cpp|Any CPU.Build.0 = Release_MLLegacy_Cpp|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_MLLegacy_Mono|Any CPU.ActiveCfg = Release_MLLegacy_Mono|Any CPU
|
||||
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_MLLegacy_Mono|Any CPU.Build.0 = Release_MLLegacy_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
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="HarmonyX" version="2.4.2" targetFramework="net35" />
|
||||
<package id="HarmonyX" version="2.5.2" targetFramework="net35" />
|
||||
<package id="ILRepack.Lib.MSBuild.Task" version="2.0.18.2" targetFramework="net35" />
|
||||
<package id="ini-parser" version="2.5.2" targetFramework="net35" />
|
||||
<package id="Mono.Cecil" version="0.10.4" targetFramework="net35" />
|
||||
|
Reference in New Issue
Block a user