Compare commits

...

62 Commits
4.1.5 ... 4.2.0

Author SHA1 Message Date
5c9dcb1d43 Bump HarmonyX to 2.5.2 2021-07-28 19:14:37 +10:00
602770d980 Cleanup 2021-07-28 19:01:43 +10:00
f26371f95f Go back to previous panel transform saving, no need to change 2021-07-28 18:27:10 +10:00
a673c39f4a Include arial in legacy bundles 2021-07-28 18:26:53 +10:00
40583cae3d Include arial in legacy bundles, cleanup 2021-07-28 06:41:02 +10:00
20018a9ba9 Use invariant decimal separator for NumberFormatString 2021-07-28 06:40:05 +10:00
dabf92a1a5 Use CurrentCulture, and use whitespace instead of comma as separator 2021-07-27 22:17:26 +10:00
b7e275f02c Cleanup 2021-07-27 22:12:48 +10:00
f393e0d706 Include Arial font, don't rely on built-in resource
TODO add font to legacy bundles
2021-07-27 18:14:44 +10:00
ab8acc9e84 Change directory case 2021-07-21 20:53:03 +10:00
66c30ee70e Cleanup 2021-07-21 20:48:21 +10:00
ddd271c00d Cleanup 2021-07-21 20:12:34 +10:00
30fe9e4dde Cleanup 2021-07-21 18:37:01 +10:00
fa3a436037 Cleanup 2021-07-21 18:29:01 +10:00
ca27d2b20f Update CursorUnlocker.cs 2021-07-21 05:18:22 +10:00
4315e0c547 Merge branch 'master' of https://github.com/sinai-dev/UnityExplorer 2021-07-21 04:23:55 +10:00
3e19e74329 Update readme -noci 2021-07-21 04:17:41 +10:00
5a3ffebadc Remove legacy build 2021-07-21 04:16:53 +10:00
6e6b6239d8 Do patching in CursorUnlocker, add patch for SetSelectedGameObject 2021-07-21 04:14:34 +10:00
03c8e5a8bd Add Harmony instance to ExplorerCore, bump version 2021-07-21 04:14:12 +10:00
44f7209843 Remove ML 0.3 builds 2021-07-21 04:13:54 +10:00
734e45cf9f Remove patching in mod loader classes 2021-07-21 04:13:42 +10:00
97838e0b3a Update Unhollower 2021-07-21 04:13:15 +10:00
304b47f898 Bump version 2021-07-19 21:43:40 +10:00
3d1fcbcd9f Fix duplicate Scene hashcodes breaking PopulateSceneDropdown 2021-07-19 21:43:36 +10:00
36fc17aa43 Get rid of pointless ReadOnlyCollection properties 2021-07-19 21:43:16 +10:00
adfa29e63c Bump version 2021-07-15 05:20:31 +10:00
3ffdcea73b Force all devices to always be supported by InputSystem 2021-07-15 05:20:26 +10:00
dfd55260a8 Fallback to null check loading if unityVersion throws an exception 2021-07-15 05:19:48 +10:00
29c78dc5a6 Manually get Major and Minor instead of using Version class 2021-07-11 23:22:33 +10:00
bf59d9d6cd Handle cases where Unity doesn't include 'f' suffix on version
Not sure if this ever happens but just in case
2021-07-11 18:19:09 +10:00
bb0c59534a Bump version 2021-07-11 18:11:18 +10:00
802bb722bc Use Application.unityVersion to load appropriate AssetBundle
And fix issue with Dropdowns and Time input label not refreshing properly on launch
2021-07-11 18:11:14 +10:00
9ca992b0d7 Fix incorrect config description example 2021-07-07 23:27:43 +10:00
5f3b3a6870 cleanup -noci 2021-07-07 23:21:40 +10:00
f5bce439cb Favor public GetEnumerator over private. Use GetActualType. Improve logging. 2021-07-06 16:42:20 +10:00
e2b2c9038a Add 'other' issue template -noci 2021-07-05 19:05:04 +10:00
fbefccd6b7 Update issue template -noci 2021-07-02 23:32:02 +10:00
271c91f0d0 Update README.md 2021-07-02 20:03:41 +10:00
eb221bd868 Bump version 2021-07-02 18:45:09 +10:00
5b516eb4cc Add assembly name to class search result labels 2021-07-02 18:45:03 +10:00
601567f9d2 Remove arbitrary static restriction on class search 2021-07-02 17:53:12 +10:00
7ff508b874 [IL2CPP] Support private interface implementations on IDictionary and IEnumerable 2021-07-02 17:45:18 +10:00
09a7cd35cf Remove known issues from readme -noci 2021-07-02 17:35:34 +10:00
db4a338d26 Update issue template -noci 2021-07-02 17:33:41 +10:00
c08e02057c Create enhancement.yaml 2021-07-02 17:31:36 +10:00
362fcdc51a Update bug_report.yaml 2021-07-02 17:22:24 +10:00
73bd172e4d Update bug_report.yaml 2021-07-02 17:16:09 +10:00
454d3bd0b4 Add bug report issue template 2021-07-02 17:10:26 +10:00
f815a13d9a Namespace cleanup, move some categories out of UI namespace 2021-06-30 07:49:58 +10:00
65c4d49274 Update readme 2021-06-26 18:08:21 +10:00
d99137526e Fix InspectUnderMouse breaking ScrollPool in rare cases 2021-06-22 20:39:46 +10:00
92447b55cd Update README.md 2021-06-22 19:48:41 +10:00
87d5d5a2de Bump version 2021-06-22 19:46:14 +10:00
08cff3386b Fix issues with Il2Cpp nullables 2021-06-22 19:46:09 +10:00
6033200579 Don't use WaitForEndOfFrame in SrollPool init coroutine 2021-06-22 19:45:57 +10:00
94ec1c4908 Update line numbers on panel resize 2021-06-21 19:50:11 +10:00
7a400e762c Cleanup 2021-06-21 19:49:44 +10:00
67f9f744bb Handle Unity 2021+ InputField.onEndEdit change 2021-06-21 19:26:05 +10:00
7a59f9a2a1 Update info about startup script -noci 2021-06-20 19:10:44 +10:00
9b42eef1b9 Line numbers and startup script 2021-06-20 19:06:52 +10:00
830000b019 Bump version 2021-06-20 19:06:33 +10:00
101 changed files with 1092 additions and 1168 deletions

60
.github/ISSUE_TEMPLATE/bug_report.yaml vendored Normal file
View File

@ -0,0 +1,60 @@
name: Bug Report
description: File a bug or crash report
title: "[Bug]: "
labels: [bug]
body:
- type: markdown
attributes:
value: |
Thanks for submitting a bug report, please fill out as much detail as possible.
- type: checkboxes
id: latestversion
attributes:
label: Are you on the latest version of UnityExplorer?
description: If not, you must update first.
options:
- label: Yes, I'm on the latest version of UnityExplorer.
required: true
- type: dropdown
id: version
attributes:
label: Which release are you using?
description: Please select your environment for UnityExplorer.
options:
- BepInEx IL2CPP
- BepInEx 6.X Mono
- BepInEx 5.X Mono
- MelonLoader IL2CPP
- MelonLoader Mono
- Standalone IL2CPP
- Standalone Mono
validations:
required: true
- type: textarea
id: game
attributes:
label: Which game did this occur on?
description: Please tell us the name of the game. If it's a personal or private project, just let us know the Unity version.
validations:
required: true
- type: textarea
id: what-happened
attributes:
label: Describe the issue.
description: What happened? Should something else have happened instead? Please provide steps to reproduce the issue if possible.
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: logs
attributes:
label: Relevant log output
description: |
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: false

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1 @@
blank_issues_enabled: false

18
.github/ISSUE_TEMPLATE/enhancement.yaml vendored Normal file
View File

@ -0,0 +1,18 @@
name: New feature or enhancement
description: Suggest or discuss a feature or enhancement for UnityExplorer
title: "[Enhancement]: "
labels: [enhancement]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to discuss UnityExplorer, please provide as much detail as possible.
- type: textarea
id: description
attributes:
label: Describe the new feature or enhancement
description: |
Please go into as much detail as necessary in describing the new feature or enhancement.
If providing examples or suggestions for the required C# code, please use syntax-highlighted code blocks.
validations:
required: true

13
.github/ISSUE_TEMPLATE/other.yaml vendored Normal file
View 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

View File

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

View File

@ -6,10 +6,7 @@
🔍 An in-game UI for exploring, debugging and modifying Unity games.
</p>
<p align="center">
✔️ Supports most Unity versions from 5.2 to 2020+ (IL2CPP and Mono).
</p>
<p align="center">
☕ Enjoy this tool? Consider supporting me on <a href="https://ko-fi.com/sinaidev">ko-fi</a>!
✔️ Supports most Unity versions from 5.2 to 2021+ (IL2CPP and Mono).
</p>
<p align="center">
⚡ UnityExplorer is on <a href="https://thunderstore.io/package/sinai-dev/UnityExplorer/">Thunderstore</a>! (and as <a href="https://gtfo.thunderstore.io/package/sinai-dev/UnityExplorer_IL2CPP/">IL2CPP</a>)
@ -35,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.
@ -53,11 +49,6 @@ The standalone release can be used with any injector or loader of your choice, b
3. Create an instance of Unity Explorer with `UnityExplorer.ExplorerStandalone.CreateInstance();`
4. Optionally subscribe to the `ExplorerStandalone.OnLog` event to handle logging if you wish
# Known issues
* Any `MissingMethodException` or `NotSupportedException`: please report the issue and provide a copy of your mod loader log and/or Unity log.
* In IL2CPP, some IEnumerable and IDictionary types may fail enumeration. Waiting for the Unhollower rewrite to address this any further.
* The C# Console's completions have some minor issues such as not suggestion global classes which have no namespace, and erronously suggesting classes from using directives when they shouldn't be suggested. These are issues with mcs itself which I am looking into.
# Features
<p align="center">
@ -91,6 +82,7 @@ The inspector is used to see detailed information on objects of any type and man
### C# Console
* The C# Console uses the `Mono.CSharp.Evaluator` to define temporary classes or run immediate REPL code.
* You can execute a script automatically on startup by naming it `startup.cs` and placing it in the `UnityExplorer\Scripts\` folder (this folder will be created where you placed the DLL file).
* See the "Help" dropdown in the C# console menu for more detailed information.
### Mouse-Inspect

Binary file not shown.

View File

@ -3,10 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.UI.CSConsole.Lexers;
using UnityExplorer.CSConsole.Lexers;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets.AutoComplete;
namespace UnityExplorer.UI.CSConsole
namespace UnityExplorer.CSConsole
{
public class CSAutoCompleter : ISuggestionProvider
{

View File

@ -10,11 +10,12 @@ using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Core.Input;
using UnityExplorer.UI.CSConsole;
using UnityExplorer.CSConsole;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets.AutoComplete;
namespace UnityExplorer.UI.CSConsole
namespace UnityExplorer.CSConsole
{
public static class ConsoleController
{
@ -36,6 +37,8 @@ namespace UnityExplorer.UI.CSConsole
public static bool EnableAutoIndent { get; private set; } = true;
public static bool EnableSuggestions { get; private set; } = true;
internal static string ScriptsFolder => Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Scripts");
internal static readonly string[] DefaultUsing = new string[]
{
"System",
@ -51,6 +54,7 @@ namespace UnityExplorer.UI.CSConsole
public static void Init()
{
// Make sure console is supported on this platform
try
{
ResetConsole(false);
@ -63,19 +67,41 @@ namespace UnityExplorer.UI.CSConsole
return;
}
// Setup console
Lexer = new LexerBuilder();
Completer = new CSAutoCompleter();
SetupHelpInteraction();
Panel.OnInputChanged += OnInputChanged;
Panel.InputScroll.OnScroll += OnInputScrolled;
Panel.InputScroller.OnScroll += OnInputScrolled;
Panel.OnCompileClicked += Evaluate;
Panel.OnResetClicked += ResetConsole;
Panel.OnHelpDropdownChanged += HelpSelected;
Panel.OnAutoIndentToggled += OnToggleAutoIndent;
Panel.OnCtrlRToggled += OnToggleCtrlRShortcut;
Panel.OnSuggestionsToggled += OnToggleSuggestions;
Panel.OnPanelResized += OnInputScrolled;
// Run startup script
try
{
if (!Directory.Exists(ScriptsFolder))
Directory.CreateDirectory(ScriptsFolder);
var startupPath = Path.Combine(ScriptsFolder, "startup.cs");
if (File.Exists(startupPath))
{
ExplorerCore.Log($"Executing startup script from '{startupPath}'...");
var text = File.ReadAllText(startupPath);
Input.Text = text;
Evaluate();
}
}
catch (Exception ex)
{
ExplorerCore.LogWarning($"Exception executing startup script: {ex}");
}
}
@ -317,7 +343,7 @@ namespace UnityExplorer.UI.CSConsole
var charBot = charTop - CSCONSOLE_LINEHEIGHT;
var viewportMin = Input.Rect.rect.height - Input.Rect.anchoredPosition.y - (Input.Rect.rect.height * 0.5f);
var viewportMax = viewportMin - Panel.InputScroll.ViewportRect.rect.height;
var viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
float diff = 0f;
if (charTop > viewportMin)
@ -337,7 +363,7 @@ namespace UnityExplorer.UI.CSConsole
{
settingCaretCoroutine = true;
Input.Component.readOnly = true;
RuntimeProvider.Instance.StartCoroutine(SetAutocompleteCaretCoro(caretPosition));
RuntimeProvider.Instance.StartCoroutine(SetCaretCoroutine(caretPosition));
}
internal static PropertyInfo SelectionGuardProperty => selectionGuardPropInfo ?? GetSelectionGuardPropInfo();
@ -352,7 +378,7 @@ namespace UnityExplorer.UI.CSConsole
private static PropertyInfo selectionGuardPropInfo;
private static IEnumerator SetAutocompleteCaretCoro(int caretPosition)
private static IEnumerator SetCaretCoroutine(int caretPosition)
{
var color = Input.Component.selectionColor;
color.a = 0f;
@ -376,7 +402,6 @@ namespace UnityExplorer.UI.CSConsole
settingCaretCoroutine = false;
}
#region Lexer Highlighting
/// <summary>
@ -384,43 +409,83 @@ namespace UnityExplorer.UI.CSConsole
/// </summary>
private static bool HighlightVisibleInput()
{
int startIdx = 0;
int endIdx = Input.Text.Length - 1;
int topLine = 0;
// Calculate visible text if necessary
if (Input.Rect.rect.height > Panel.InputScroll.ViewportRect.rect.height)
if (string.IsNullOrEmpty(Input.Text))
{
topLine = -1;
int bottomLine = -1;
// the top and bottom position of the viewport in relation to the text height
// they need the half-height adjustment to normalize against the 'line.topY' value.
var viewportMin = Input.Rect.rect.height - Input.Rect.anchoredPosition.y - (Input.Rect.rect.height * 0.5f);
var viewportMax = viewportMin - Panel.InputScroll.ViewportRect.rect.height;
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
{
var line = Input.TextGenerator.lines[i];
// if not set the top line yet, and top of line is below the viewport top
if (topLine == -1 && line.topY <= viewportMin)
topLine = i;
// if bottom of line is below the viewport bottom
if ((line.topY - line.height) >= viewportMax)
bottomLine = i;
}
topLine = Math.Max(0, topLine - 1);
bottomLine = Math.Min(Input.TextGenerator.lineCount - 1, bottomLine + 1);
startIdx = Input.TextGenerator.lines[topLine].startCharIdx;
endIdx = (bottomLine >= Input.TextGenerator.lineCount - 1)
? Input.Text.Length - 1
: (Input.TextGenerator.lines[bottomLine + 1].startCharIdx - 1);
Panel.HighlightText.text = "";
Panel.LineNumberText.text = "1";
return false;
}
// Calculate the visible lines
int topLine = -1;
int bottomLine = -1;
// the top and bottom position of the viewport in relation to the text height
// they need the half-height adjustment to normalize against the 'line.topY' value.
var viewportMin = Input.Rect.rect.height - Input.Rect.anchoredPosition.y - (Input.Rect.rect.height * 0.5f);
var viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
{
var line = Input.TextGenerator.lines[i];
// if not set the top line yet, and top of line is below the viewport top
if (topLine == -1 && line.topY <= viewportMin)
topLine = i;
// if bottom of line is below the viewport bottom
if ((line.topY - line.height) >= viewportMax)
bottomLine = i;
}
topLine = Math.Max(0, topLine - 1);
bottomLine = Math.Min(Input.TextGenerator.lineCount - 1, bottomLine + 1);
int startIdx = Input.TextGenerator.lines[topLine].startCharIdx;
int endIdx = (bottomLine >= Input.TextGenerator.lineCount - 1)
? Input.Text.Length - 1
: (Input.TextGenerator.lines[bottomLine + 1].startCharIdx - 1);
// Highlight the visible text with the LexerBuilder
Panel.HighlightText.text = Lexer.BuildHighlightedString(Input.Text, startIdx, endIdx, topLine, LastCaretPosition, out bool ret);
// Set the line numbers
// determine true starting line number (not the same as the cached TextGenerator line numbers)
int realStartLine = 0;
for (int i = 0; i < startIdx; i++)
{
if (LexerBuilder.IsNewLine(Input.Text[i]))
realStartLine++;
}
realStartLine++;
char lastPrev = '\n';
var sb = new StringBuilder();
// append leading new lines for spacing (no point rendering line numbers we cant see)
for (int i = 0; i < topLine; i++)
sb.Append('\n');
// append the displayed line numbers
for (int i = topLine; i <= bottomLine; i++)
{
if (i > 0)
lastPrev = Input.Text[Input.TextGenerator.lines[i].startCharIdx - 1];
// previous line ended with a newline character, this is an actual new line.
if (LexerBuilder.IsNewLine(lastPrev))
{
sb.Append(realStartLine.ToString());
realStartLine++;
}
sb.Append('\n');
}
Panel.LineNumberText.text = sb.ToString();
return ret;
}
@ -555,7 +620,9 @@ If the game was built with Unity's stubbed netstandard 2.0 runtime, you can fix
internal const string STARTUP_TEXT = @"<color=#5d8556>// Welcome to the UnityExplorer C# Console!
// It is recommended to use the Log panel (or a console log window) while using this tool.
// Use the Help dropdown to see detailed examples of how to use the console.</color>";
// Use the Help dropdown to see detailed examples of how to use the console.
// To execute a script automatically on startup, put the script at 'UnityExplorer\Scripts\startup.cs'</color>";
internal const string HELP_USINGS = @"// You can add a using directive to any namespace, but you must compile for it to take effect.
// It will remain in effect until you Reset the console.

View File

@ -5,16 +5,17 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CSConsole.Lexers;
using UnityExplorer.CSConsole.Lexers;
namespace UnityExplorer.UI.CSConsole
namespace UnityExplorer.CSConsole
{
public struct MatchInfo
{
public int startIndex;
public int endIndex;
public string htmlColorTag;
public bool isStringOrComment;
public bool matchToEndOfLine;
public string htmlColorTag;
}
public class LexerBuilder
@ -112,12 +113,24 @@ namespace UnityExplorer.UI.CSConsole
sb.Append(input[i]);
sb.Append(SignatureHighlighter.CLOSE_COLOR);
// check caretIdx to determine inStringOrComment state
if (caretIdx >= match.startIndex && (caretIdx <= match.endIndex || (caretIdx >= input.Length && match.endIndex >= input.Length - 1)))
caretInStringOrComment = match.isStringOrComment;
// update the last unhighlighted start index
lastUnhighlighted = match.endIndex + 1;
int matchEndIdx = match.endIndex;
if (match.matchToEndOfLine)
{
while (input.Length - 1 >= 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)))
caretInStringOrComment = match.isStringOrComment;
}
// Append trailing unhighlighted input

View File

@ -2,7 +2,7 @@
using System.Linq;
using UnityEngine;
namespace UnityExplorer.UI.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public class CommentLexer : Lexer
{

View File

@ -2,7 +2,7 @@
using System.Text;
using UnityEngine;
namespace UnityExplorer.UI.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public class KeywordLexer : Lexer
{

View File

@ -2,7 +2,7 @@
using System.Linq;
using UnityEngine;
namespace UnityExplorer.UI.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public abstract class Lexer
{

View File

@ -1,6 +1,6 @@
using UnityEngine;
namespace UnityExplorer.UI.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public class NumberLexer : Lexer
{

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using UnityEngine;
namespace UnityExplorer.UI.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public class StringLexer : Lexer
{

View File

@ -3,7 +3,7 @@ using System.Linq;
using System.Text;
using UnityEngine;
namespace UnityExplorer.UI.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public class SymbolLexer : Lexer
{

View File

@ -7,7 +7,7 @@ using System.Text;
// Thanks to ManlyMarco for this
namespace UnityExplorer.UI.CSConsole
namespace UnityExplorer.CSConsole
{
public class ScriptEvaluator : Evaluator, IDisposable
{

View File

@ -7,13 +7,7 @@ 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.UI.CSConsole
namespace UnityExplorer.CSConsole
{
public class ScriptInteraction : InteractiveBase
{
@ -76,4 +70,4 @@ namespace UnityExplorer.UI.CSConsole
}
}
}
}

View File

@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.CacheObject.Views;
namespace UnityExplorer.UI.CacheObject
namespace UnityExplorer.CacheObject
{
public class CacheConfigEntry : CacheObjectBase
{

View File

@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.Inspectors;
namespace UnityExplorer.UI.CacheObject
namespace UnityExplorer.CacheObject
{
public class CacheField : CacheMember
{

View File

@ -2,10 +2,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.Views;
namespace UnityExplorer.UI.CacheObject
namespace UnityExplorer.CacheObject
{
public class CacheKeyValuePair : CacheObjectBase
{

View File

@ -2,10 +2,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.Views;
namespace UnityExplorer.UI.CacheObject
namespace UnityExplorer.CacheObject
{
public class CacheListEntry : CacheObjectBase
{

View File

@ -5,11 +5,12 @@ using System.Reflection;
using System.Text;
using UnityEngine;
using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Inspectors;
using UnityExplorer.UI.Models;
using UnityExplorer.UI;
namespace UnityExplorer.UI.CacheObject
namespace UnityExplorer.CacheObject
{
public abstract class CacheMember : CacheObjectBase
{

View File

@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.Inspectors;
namespace UnityExplorer.UI.CacheObject
namespace UnityExplorer.CacheObject
{
public class CacheMethod : CacheMember
{

View File

@ -7,11 +7,12 @@ using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.UI.Models;
using UnityExplorer.UI;
namespace UnityExplorer.UI.CacheObject
namespace UnityExplorer.CacheObject
{
public enum ValueState
{

View File

@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.Inspectors;
namespace UnityExplorer.UI.CacheObject
namespace UnityExplorer.CacheObject
{
public class CacheProperty : CacheMember
{

View File

@ -3,10 +3,10 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
namespace UnityExplorer.UI.CacheObject
namespace UnityExplorer.CacheObject
{
public interface ICacheObjectController
{

View File

@ -4,9 +4,10 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
namespace UnityExplorer.UI.CacheObject.IValues
namespace UnityExplorer.CacheObject.IValues
{
public class InteractiveColor : InteractiveValue
{

View File

@ -5,13 +5,14 @@ using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Inspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.CacheObject.IValues
namespace UnityExplorer.CacheObject.IValues
{
public class InteractiveDictionary : InteractiveValue, ICellPoolDataSource<CacheKeyValuePairCell>, ICacheObjectController
{

View File

@ -5,9 +5,10 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
namespace UnityExplorer.UI.CacheObject.IValues
namespace UnityExplorer.CacheObject.IValues
{
public class InteractiveEnum : InteractiveValue
{

View File

@ -5,13 +5,14 @@ using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Inspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.CacheObject.IValues
namespace UnityExplorer.CacheObject.IValues
{
public class InteractiveList : InteractiveValue, ICellPoolDataSource<CacheListEntryCell>, ICacheObjectController
{

View File

@ -6,10 +6,11 @@ using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.CacheObject;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI;
namespace UnityExplorer.UI.CacheObject.IValues
namespace UnityExplorer.CacheObject.IValues
{
public class InteractiveString : InteractiveValue
{

View File

@ -4,10 +4,11 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
using UnityExplorer.UI.Models;
namespace UnityExplorer.UI.CacheObject.IValues
namespace UnityExplorer.CacheObject.IValues
{
public abstract class InteractiveValue : IPooledObject
{

View File

@ -5,9 +5,10 @@ using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
namespace UnityExplorer.UI.CacheObject.IValues
namespace UnityExplorer.CacheObject.IValues
{
public class InteractiveValueStruct : InteractiveValue
{

View File

@ -4,8 +4,9 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
namespace UnityExplorer.UI.CacheObject.Views
namespace UnityExplorer.CacheObject.Views
{
public class ConfigEntryCell : CacheObjectCell
{

View File

@ -4,11 +4,12 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.Inspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.CacheObject.Views
namespace UnityExplorer.CacheObject.Views
{
public class CacheKeyValuePairCell : CacheObjectCell
{

View File

@ -4,9 +4,9 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.CacheObject.IValues;
namespace UnityExplorer.UI.CacheObject.Views
namespace UnityExplorer.CacheObject.Views
{
public class CacheListEntryCell : CacheObjectCell
{

View File

@ -4,9 +4,10 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.CacheObject.Views
namespace UnityExplorer.CacheObject.Views
{
public class CacheMemberCell : CacheObjectCell
{

View File

@ -4,11 +4,12 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.Inspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.CacheObject.Views
namespace UnityExplorer.CacheObject.Views
{
public abstract class CacheObjectCell : ICell
{

View File

@ -5,10 +5,11 @@ using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Models;
using UnityExplorer.UI.Widgets.AutoComplete;
namespace UnityExplorer.UI.CacheObject.Views
namespace UnityExplorer.CacheObject.Views
{
public class EvaluateWidget : IPooledObject
{

View File

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

View File

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

View File

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

View File

@ -132,7 +132,6 @@ namespace UnityExplorer
return null;
var type = obj.GetType();
try
{
if (IsString(obj))
@ -216,7 +215,7 @@ namespace UnityExplorer
// from other structs to il2cpp object
else if (typeof(Il2CppSystem.Object).IsAssignableFrom(castTo))
{
return BoxIl2CppObject(obj);
return BoxIl2CppObject(obj).TryCast(castTo);
}
else
return obj;
@ -295,7 +294,27 @@ namespace UnityExplorer
try
{
if (toType.IsEnum)
{
// Check for nullable enums
var type = cppObj.GetType();
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Il2CppSystem.Nullable<>))
{
var nullable = cppObj.TryCast(type);
var nullableHasValueProperty = type.GetProperty("HasValue");
if ((bool)nullableHasValueProperty.GetValue(nullable, null))
{
// nullable has a value.
var nullableValueProperty = type.GetProperty("Value");
return Enum.Parse(toType, nullableValueProperty.GetValue(nullable, null).ToString());
}
// nullable and no current value.
return cppObj;
}
return Enum.Parse(toType, cppObj.ToString());
}
// Not enum, unbox with Il2CppObjectBase.Unbox
var name = toType.AssemblyQualifiedName;
@ -780,21 +799,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))
{
getEnumeratorMethods.Add(key, 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);
}
}
@ -803,7 +825,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;
@ -857,7 +879,7 @@ namespace UnityExplorer
try
{
var type = dictionary.GetType();
var type = dictionary.GetActualType();
if (typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(type))
{
@ -867,20 +889,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))
{
getEnumeratorMethods.Add(cacheKey, 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);
}
}
@ -891,16 +916,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);

View File

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

View File

@ -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)]

View File

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

View File

@ -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>();
@ -117,22 +118,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();
}

View File

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

View File

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

View File

@ -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()

View File

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

View File

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

View File

@ -6,7 +6,7 @@ using System.Reflection;
using System.Text;
using UnityEngine;
using UnityExplorer.UI;
using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.CacheObject.IValues;
#if CPP
using UnhollowerRuntimeLib;
using UnhollowerBaseLib;
@ -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[i] = (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
}
}

View File

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

View File

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

View File

@ -2,9 +2,11 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Object = UnityEngine.Object;
// Project-wide namespace for accessibility
@ -107,5 +109,16 @@ namespace UnityExplorer
return color;
}
private static PropertyInfo onEndEdit;
public static UnityEvent<string> GetOnEndEdit(this InputField _this)
{
if (onEndEdit == null)
onEndEdit = typeof(InputField).GetProperty("onEndEdit")
?? throw new Exception("Could not get InputField.onEndEdit property!");
return onEndEdit.GetValue(_this, null).TryCast<UnityEvent<string>>();
}
}
}

View File

@ -11,8 +11,8 @@ using UnityExplorer.Core.Input;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Tests;
using UnityExplorer.UI;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.ObjectExplorer;
using UnityExplorer.Inspectors;
using UnityExplorer.ObjectExplorer;
using UnityExplorer.UI.Panels;
namespace UnityExplorer
@ -20,13 +20,15 @@ namespace UnityExplorer
public static class ExplorerCore
{
public const string NAME = "UnityExplorer";
public const string VERSION = "4.1.5";
public const string VERSION = "4.2.0";
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();

View File

@ -6,12 +6,13 @@ using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Input;
using UnityExplorer.UI;
using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete;
namespace UnityExplorer.UI.Inspectors
namespace UnityExplorer.Inspectors
{
public class GameObjectInspector : InspectorBase
{

View File

@ -4,9 +4,10 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Inspectors
namespace UnityExplorer.Inspectors
{
public class ComponentCell : ButtonCell
{

View File

@ -5,7 +5,7 @@ using System.Text;
using UnityEngine;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Inspectors
namespace UnityExplorer.Inspectors
{
public class ComponentList : ButtonListHandler<Component, ComponentCell>
{

View File

@ -5,8 +5,9 @@ using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Input;
using UnityExplorer.UI;
namespace UnityExplorer.UI.Inspectors
namespace UnityExplorer.Inspectors
{
public class GameObjectControls
{
@ -234,7 +235,7 @@ namespace UnityExplorer.UI.Inspectors
private void OnExploreButtonClicked()
{
var panel = UIManager.GetPanel<Panels.ObjectExplorerPanel>(UIManager.Panels.ObjectExplorer);
var panel = UIManager.GetPanel<UI.Panels.ObjectExplorerPanel>(UIManager.Panels.ObjectExplorer);
panel.SceneExplorer.JumpToTransform(this.Parent.GOTarget.transform);
}
@ -468,7 +469,7 @@ namespace UnityExplorer.UI.Inspectors
//UIFactory.SetLayoutElement(pathApplyBtn.Component.gameObject, minHeight: 25, minWidth: 120);
//pathApplyBtn.OnClick += () => { OnPathEndEdit(PathInput.Text); };
PathInput.Component.onEndEdit.AddListener((string val) => { OnPathEndEdit(val); });
PathInput.Component.GetOnEndEdit().AddListener((string val) => { OnPathEndEdit(val); });
// Title and update row
@ -484,7 +485,7 @@ namespace UnityExplorer.UI.Inspectors
NameInput = UIFactory.CreateInputField(titleRow, "NameInput", "untitled");
UIFactory.SetLayoutElement(NameInput.Component.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999);
NameInput.Component.textComponent.fontSize = 15;
NameInput.Component.onEndEdit.AddListener((string val) => { OnNameEndEdit(val); });
NameInput.Component.GetOnEndEdit().AddListener((string val) => { OnNameEndEdit(val); });
// second row (toggles, instanceID, tag, buttons)
@ -521,7 +522,7 @@ namespace UnityExplorer.UI.Inspectors
TagInput = UIFactory.CreateInputField(secondRow, "TagInput", "none");
UIFactory.SetLayoutElement(TagInput.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
TagInput.Component.textComponent.color = Color.white;
TagInput.Component.onEndEdit.AddListener((string val) => { OnTagEndEdit(val); });
TagInput.Component.GetOnEndEdit().AddListener((string val) => { OnTagEndEdit(val); });
// Instantiate
var instantiateBtn = UIFactory.CreateButton(secondRow, "InstantiateBtn", "Instantiate", new Color(0.2f, 0.2f, 0.2f));
@ -644,7 +645,7 @@ namespace UnityExplorer.UI.Inspectors
var inputField = UIFactory.CreateInputField(rowObj, "InputField", "...");
UIFactory.SetLayoutElement(inputField.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
inputField.Component.onEndEdit.AddListener((string value) => { OnTransformInputEndEdit(type, value); });
inputField.Component.GetOnEndEdit().AddListener((string value) => { OnTransformInputEndEdit(type, value); });
var control = new TransformControl(type, inputField);

View File

@ -11,7 +11,7 @@ using UnityExplorer.Core.Runtime;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
namespace UnityExplorer.UI.Inspectors
namespace UnityExplorer.Inspectors
{
public enum MouseInspectMode
{

View File

@ -4,10 +4,11 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels;
namespace UnityExplorer.UI.Inspectors
namespace UnityExplorer.Inspectors
{
public abstract class InspectorBase : IPooledObject
{

View File

@ -5,8 +5,8 @@ using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.CacheObject;
using UnityExplorer.Inspectors;
using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels;

View File

@ -4,10 +4,11 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Models;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Inspectors
namespace UnityExplorer.Inspectors
{
public class InspectorTab : IPooledObject
{

View File

@ -10,12 +10,13 @@ using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI;
namespace UnityExplorer.UI.Inspectors
namespace UnityExplorer.Inspectors
{
public class ReflectionInspector : InspectorBase, ICellPoolDataSource<CacheMemberCell>, ICacheObjectController
{

View File

@ -51,8 +51,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 +61,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

View File

@ -15,7 +15,5 @@ namespace UnityExplorer
Action<object> OnLogMessage { get; }
Action<object> OnLogWarning { get; }
Action<object> OnLogError { get; }
void SetupCursorPatches();
}
}

View File

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

View File

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

View File

@ -0,0 +1,43 @@
#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 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

View File

@ -0,0 +1,77 @@
#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();
}
}
}
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();
}
}
}
#endif

View File

@ -21,8 +21,7 @@ namespace UnityExplorer
/// Call this to initialize UnityExplorer without adding a log listener.
/// </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);
/// <summary>
/// Call this to initialize UnityExplorer and add a listener for UnityExplorer's log messages.
@ -34,7 +33,8 @@ namespace UnityExplorer
if (Instance != null)
return Instance;
OnLog += logListener;
if (logListener != null)
OnLog += logListener;
var instance = new ExplorerStandalone();
instance.Init();
@ -48,9 +48,6 @@ 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 ConfigHandler ConfigHandler => _configHandler;
private StandaloneConfigHandler _configHandler;
@ -58,19 +55,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 +73,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);
}
}
}

View File

@ -4,12 +4,13 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete;
namespace UnityExplorer.UI.ObjectExplorer
namespace UnityExplorer.ObjectExplorer
{
public class ObjectSearch : UIModel
{
@ -52,8 +53,8 @@ namespace UnityExplorer.UI.ObjectExplorer
if (m_context == SearchContext.Singleton)
currentResults = SearchProvider.SingletonSearch(nameInputField.Text);
else if (m_context == SearchContext.StaticClass)
currentResults = SearchProvider.StaticClassSearch(nameInputField.Text);
else if (m_context == SearchContext.Class)
currentResults = SearchProvider.ClassSearch(nameInputField.Text);
else
{
string compType = "";
@ -129,8 +130,11 @@ namespace UnityExplorer.UI.ObjectExplorer
if (!cachedCellTexts.ContainsKey(index))
{
string text;
if (m_context == SearchContext.StaticClass)
text = SignatureHighlighter.Parse(currentResults[index] as Type, true);
if (m_context == SearchContext.Class)
{
var type = currentResults[index] as Type;
text = $"{SignatureHighlighter.Parse(type, true)} <color=grey><i>({type.Assembly.GetName().Name})</i></color>";
}
else
text = ToStringUtility.ToStringWithType(currentResults[index], currentResults[index]?.GetActualType());
@ -142,7 +146,7 @@ namespace UnityExplorer.UI.ObjectExplorer
private void OnCellClicked(int dataIndex)
{
if (m_context == SearchContext.StaticClass)
if (m_context == SearchContext.Class)
InspectorManager.Inspect(currentResults[dataIndex] as Type);
else
InspectorManager.Inspect(currentResults[dataIndex]);

View File

@ -8,11 +8,12 @@ using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.UI;
using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.ObjectExplorer
namespace UnityExplorer.ObjectExplorer
{
public class SceneExplorer : UIModel
{
@ -113,7 +114,7 @@ namespace UnityExplorer.UI.ObjectExplorer
refreshRow.SetActive(!scene.IsValid());
}
private void SceneHandler_OnLoadedScenesChanged(ReadOnlyCollection<Scene> loadedScenes)
private void SceneHandler_OnLoadedScenesChanged(List<Scene> loadedScenes)
{
PopulateSceneDropdown();
}
@ -125,6 +126,9 @@ namespace UnityExplorer.UI.ObjectExplorer
foreach (var scene in SceneHandler.LoadedScenes)
{
if (sceneToDropdownOption.ContainsKey(scene))
continue;
string name = scene.name?.Trim();
if (!scene.IsValid())

View File

@ -6,7 +6,7 @@ using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace UnityExplorer.UI.ObjectExplorer
namespace UnityExplorer.ObjectExplorer
{
public static class SceneHandler
{
@ -29,14 +29,12 @@ namespace UnityExplorer.UI.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>
@ -59,7 +57,7 @@ namespace UnityExplorer.UI.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.
@ -115,7 +113,7 @@ namespace UnityExplorer.UI.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 +129,26 @@ namespace UnityExplorer.UI.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 +159,7 @@ namespace UnityExplorer.UI.ObjectExplorer
if (go.transform.parent == null && !go.scene.IsValid())
objects.Add(go);
}
rootObjects = objects.ToArray();
CurrentRootObjects = objects.ToArray();
}
}
}

View File

@ -8,14 +8,13 @@ using UnityEngine.SceneManagement;
using UnityExplorer.Core;
using UnityExplorer.Core.Runtime;
namespace UnityExplorer.UI.ObjectExplorer
namespace UnityExplorer.ObjectExplorer
{
public enum SearchContext
{
UnityObject,
// GameObject,
Singleton,
StaticClass
Class
}
public enum ChildFilter
@ -134,7 +133,7 @@ namespace UnityExplorer.UI.ObjectExplorer
return results;
}
internal static List<object> StaticClassSearch(string input)
internal static List<object> ClassSearch(string input)
{
var list = new List<object>();
@ -144,11 +143,10 @@ namespace UnityExplorer.UI.ObjectExplorer
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in asm.TryGetTypes().Where(it => it.IsSealed && it.IsAbstract))
foreach (var type in asm.TryGetTypes())
{
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ContainsIgnoreCase(nameFilter))
continue;
list.Add(type);
}
}

Binary file not shown.

BIN
src/Resources/legacy.bundle Normal file

Binary file not shown.

BIN
src/Resources/modern.bundle Normal file

Binary file not shown.

View File

@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -6,7 +7,7 @@ using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.CSConsole;
using UnityExplorer.CSConsole;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Panels
@ -18,10 +19,11 @@ namespace UnityExplorer.UI.Panels
public override int MinWidth => 750;
public override int MinHeight => 300;
public InputFieldScroller InputScroll { get; private set; }
public InputFieldRef Input => InputScroll.InputField;
public InputFieldScroller InputScroller { get; private set; }
public InputFieldRef Input => InputScroller.InputField;
public Text InputText { get; private set; }
public Text HighlightText { get; private set; }
public Text LineNumberText { get; private set; }
public Dropdown HelpDropdown { get; private set; }
@ -33,6 +35,7 @@ namespace UnityExplorer.UI.Panels
public Action<bool> OnCtrlRToggled;
public Action<bool> OnSuggestionsToggled;
public Action<bool> OnAutoIndentToggled;
public Action OnPanelResized;
private void InvokeOnValueChanged(string value)
{
@ -60,6 +63,11 @@ namespace UnityExplorer.UI.Panels
// UI Construction
public override void OnFinishResize(RectTransform panel)
{
OnPanelResized?.Invoke();
}
protected internal override void DoSetDefaultPosAndAnchors()
{
Rect.localPosition = Vector2.zero;
@ -121,19 +129,53 @@ namespace UnityExplorer.UI.Panels
// Console Input
var inputArea = UIFactory.CreateUIObject("InputGroup", content);
UIFactory.SetLayoutElement(inputArea, flexibleWidth: 9999, flexibleHeight: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(inputArea, false, true, true, true);
inputArea.AddComponent<Image>().color = Color.white;
inputArea.AddComponent<Mask>().showMaskGraphic = false;
// line numbers
var linesHolder = UIFactory.CreateUIObject("LinesHolder", inputArea);
var linesRect = linesHolder.GetComponent<RectTransform>();
linesRect.pivot = new Vector2(0, 1);
linesRect.anchorMin = new Vector2(0, 0);
linesRect.anchorMax = new Vector2(0, 1);
linesRect.sizeDelta = new Vector2(0, 305000);
linesRect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 0, 50);
linesHolder.AddComponent<Image>().color = new Color(0.05f, 0.05f, 0.05f);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(linesHolder, true, true, true, true);
LineNumberText = UIFactory.CreateLabel(linesHolder, "LineNumbers", "1", TextAnchor.UpperCenter, Color.grey, fontSize: 16);
LineNumberText.font = UIManager.ConsoleFont;
// input field
int fontSize = 16;
var inputObj = UIFactory.CreateScrollInputField(this.content, "ConsoleInput", ConsoleController.STARTUP_TEXT, out var inputScroller, fontSize);
InputScroll = inputScroller;
var inputObj = UIFactory.CreateScrollInputField(inputArea, "ConsoleInput", ConsoleController.STARTUP_TEXT,
out var inputScroller, fontSize);
InputScroller = inputScroller;
ConsoleController.defaultInputFieldAlpha = Input.Component.selectionColor.a;
Input.OnValueChanged += InvokeOnValueChanged;
// move line number text with input field
linesRect.transform.SetParent(inputObj.transform.Find("Viewport"), false);
inputScroller.Slider.Scrollbar.onValueChanged.AddListener((float val) => { SetLinesPosition(); });
inputScroller.Slider.Slider.onValueChanged.AddListener((float val) => { SetLinesPosition(); });
void SetLinesPosition()
{
linesRect.anchoredPosition = new Vector2(linesRect.anchoredPosition.x, inputScroller.ContentRect.anchoredPosition.y);
//SetInputLayout();
}
InputText = Input.Component.textComponent;
InputText.supportRichText = false;
Input.PlaceholderText.fontSize = fontSize;
InputText.color = Color.clear;
Input.Component.customCaretColor = true;
Input.Component.caretColor = Color.white;
Input.PlaceholderText.fontSize = fontSize;
// Lexer highlight text overlay
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", InputText.gameObject);
@ -154,7 +196,19 @@ namespace UnityExplorer.UI.Panels
Input.PlaceholderText.font = UIManager.ConsoleFont;
HighlightText.font = UIManager.ConsoleFont;
RuntimeProvider.Instance.StartCoroutine(DelayedLayoutSetup());
}
private IEnumerator DelayedLayoutSetup()
{
yield return null;
SetInputLayout();
}
public void SetInputLayout()
{
Input.Rect.offsetMin = new Vector2(52, Input.Rect.offsetMin.y);
Input.Rect.offsetMax = new Vector2(2, Input.Rect.offsetMax.y);
}
}
}

View File

@ -6,7 +6,7 @@ using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.Inspectors;
namespace UnityExplorer.UI.Panels
{

View File

@ -11,7 +11,7 @@ using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.Models;
using UnityExplorer.UI.ObjectExplorer;
using UnityExplorer.ObjectExplorer;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Panels

View File

@ -5,8 +5,8 @@ using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Panels

View File

@ -23,6 +23,7 @@ namespace UnityExplorer.UI.Panels
{
s_resizeCursorObj.SetActive(false);
wasAnyDragging = false;
Resizing = false;
foreach (var instance in Instances)
{

View File

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

View File

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

View File

@ -8,8 +8,8 @@ using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Core.Input;
using UnityExplorer.UI.CSConsole;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.CSConsole;
using UnityExplorer.Inspectors;
using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
@ -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;
}
@ -378,7 +383,7 @@ namespace UnityExplorer.UI
timeInput = UIFactory.CreateInputField(navbarPanel, "TimeInput", "timeScale");
UIFactory.SetLayoutElement(timeInput.Component.gameObject, minHeight: 25, minWidth: 40);
timeInput.Text = Time.timeScale.ToString("F2");
timeInput.Component.onEndEdit.AddListener(OnTimeInputEndEdit);
timeInput.Component.GetOnEndEdit().AddListener(OnTimeInputEndEdit);
pauseBtn = UIFactory.CreateButton(navbarPanel, "PauseButton", "||", new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(pauseBtn.Component.gameObject, minHeight: 25, minWidth: 25);
@ -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
}
}

View File

@ -80,12 +80,12 @@ namespace UnityExplorer.UI.Widgets
if (ContentRect.rect.height < desiredHeight)
{
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
ContentRect.sizeDelta = new Vector2(ContentRect.sizeDelta.x, desiredHeight);
this.Slider.UpdateSliderHandle();
}
else if (ContentRect.rect.height > desiredHeight)
{
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
ContentRect.sizeDelta = new Vector2(ContentRect.sizeDelta.x, desiredHeight);
this.Slider.UpdateSliderHandle();
}
}

View File

@ -193,12 +193,11 @@ namespace UnityExplorer.UI.Widgets
RuntimeProvider.Instance.StartCoroutine(InitCoroutine(onHeightChangedListener));
}
private WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
private IEnumerator InitCoroutine(Action onHeightChangedListener)
{
ScrollRect.content.anchoredPosition = Vector2.zero;
yield return waitForEndOfFrame ?? (waitForEndOfFrame = new WaitForEndOfFrame());
yield return null;
yield return null;
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.Inspectors;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Widgets

View File

@ -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,20 +117,13 @@
<Private>False</Private>
</Reference>
</ItemGroup>
<!-- MelonLoader Legacy refs -->
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
<Reference Include="MelonLoader">
<HintPath>..\lib\MelonLoader_Legacy\MelonLoader.dll</HintPath>
<!-- BepInEx universal refs -->
<ItemGroup Condition="'$(IsBepInEx)'=='true'">
<Reference Include="0Harmony">
<HintPath>packages\HarmonyX.2.5.2\lib\net35\0Harmony.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>
<Private>False</Private>
</Reference>
</ItemGroup>
<!-- BepInEx 5 Mono refs -->
<ItemGroup Condition="'$(IsBepInEx)|$(IsCpp)|$(Configuration)'=='true|false|Release_BIE5_Mono'">
<Reference Include="BepInEx">
@ -180,10 +155,10 @@
</ItemGroup>
<!-- Standalone refs -->
<ItemGroup Condition="'$(IsStandalone)'=='true'">
<Reference Include="0Harmony">
<HintPath>packages\HarmonyX.2.4.2\lib\net35\0Harmony.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="0Harmony">
<HintPath>packages\HarmonyX.2.5.2\lib\net35\0Harmony.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<!-- Mono refs -->
<ItemGroup Condition="'$(IsCpp)'=='false'">
@ -241,54 +216,54 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Core\Config\InternalConfigHandler.cs" />
<Compile Include="UI\CacheObject\CacheConfigEntry.cs" />
<Compile Include="UI\CacheObject\Views\CacheConfigCell.cs" />
<Compile Include="UI\CSConsole\CSAutoCompleter.cs" />
<Compile Include="UI\CSConsole\LexerBuilder.cs" />
<Compile Include="UI\CSConsole\Lexers\CommentLexer.cs" />
<Compile Include="UI\CSConsole\Lexers\KeywordLexer.cs" />
<Compile Include="UI\CSConsole\Lexers\Lexer.cs" />
<Compile Include="UI\CSConsole\Lexers\NumberLexer.cs" />
<Compile Include="UI\CSConsole\Lexers\StringLexer.cs" />
<Compile Include="UI\CSConsole\Lexers\SymbolLexer.cs" />
<Compile Include="UI\CSConsole\ScriptEvaluator.cs" />
<Compile Include="UI\CSConsole\ScriptInteraction.cs" />
<Compile Include="CacheObject\CacheConfigEntry.cs" />
<Compile Include="CacheObject\Views\CacheConfigCell.cs" />
<Compile Include="CSConsole\CSAutoCompleter.cs" />
<Compile Include="CSConsole\LexerBuilder.cs" />
<Compile Include="CSConsole\Lexers\CommentLexer.cs" />
<Compile Include="CSConsole\Lexers\KeywordLexer.cs" />
<Compile Include="CSConsole\Lexers\Lexer.cs" />
<Compile Include="CSConsole\Lexers\NumberLexer.cs" />
<Compile Include="CSConsole\Lexers\StringLexer.cs" />
<Compile Include="CSConsole\Lexers\SymbolLexer.cs" />
<Compile Include="CSConsole\ScriptEvaluator.cs" />
<Compile Include="CSConsole\ScriptInteraction.cs" />
<Compile Include="Core\ExplorerBehaviour.cs" />
<Compile Include="Core\Reflection\Extensions.cs" />
<Compile Include="Core\Reflection\Il2CppReflection.cs" />
<Compile Include="Core\Utility\ArgumentUtility.cs" />
<Compile Include="Core\Utility\MiscUtility.cs" />
<Compile Include="Core\Utility\ParseUtility.cs" />
<Compile Include="UI\Inspectors\GameObjectWidgets\ComponentCell.cs" />
<Compile Include="UI\Inspectors\GameObjectWidgets\ComponentList.cs" />
<Compile Include="UI\Inspectors\GameObjectWidgets\GameObjectControls.cs" />
<Compile Include="UI\Inspectors\InspectUnderMouse.cs" />
<Compile Include="UI\CSConsole\ConsoleController.cs" />
<Compile Include="UI\CacheObject\CacheField.cs" />
<Compile Include="UI\CacheObject\CacheKeyValuePair.cs" />
<Compile Include="UI\CacheObject\CacheListEntry.cs" />
<Compile Include="UI\CacheObject\CacheMember.cs" />
<Compile Include="UI\CacheObject\CacheMethod.cs" />
<Compile Include="UI\CacheObject\CacheObjectBase.cs" />
<Compile Include="UI\CacheObject\CacheProperty.cs" />
<Compile Include="UI\CacheObject\Views\CacheKeyValuePairCell.cs" />
<Compile Include="UI\CacheObject\Views\CacheListEntryCell.cs" />
<Compile Include="UI\CacheObject\Views\CacheMemberCell.cs" />
<Compile Include="UI\CacheObject\Views\CacheObjectCell.cs" />
<Compile Include="UI\CacheObject\Views\EvaluateWidget.cs" />
<Compile Include="UI\Inspectors\GameObjectInspector.cs" />
<Compile Include="UI\CacheObject\ICacheObjectController.cs" />
<Compile Include="UI\Inspectors\InspectorManager.cs" />
<Compile Include="UI\Inspectors\InspectorTab.cs" />
<Compile Include="UI\Inspectors\InspectorBase.cs" />
<Compile Include="UI\CacheObject\IValues\InteractiveColor.cs" />
<Compile Include="UI\CacheObject\IValues\InteractiveDictionary.cs" />
<Compile Include="UI\CacheObject\IValues\InteractiveEnum.cs" />
<Compile Include="UI\CacheObject\IValues\InteractiveList.cs" />
<Compile Include="UI\CacheObject\IValues\InteractiveString.cs" />
<Compile Include="UI\CacheObject\IValues\InteractiveValue.cs" />
<Compile Include="UI\Inspectors\ReflectionInspector.cs" />
<Compile Include="UI\CacheObject\IValues\InteractiveValueStruct.cs" />
<Compile Include="Inspectors\GameObjectWidgets\ComponentCell.cs" />
<Compile Include="Inspectors\GameObjectWidgets\ComponentList.cs" />
<Compile Include="Inspectors\GameObjectWidgets\GameObjectControls.cs" />
<Compile Include="Inspectors\InspectUnderMouse.cs" />
<Compile Include="CSConsole\ConsoleController.cs" />
<Compile Include="CacheObject\CacheField.cs" />
<Compile Include="CacheObject\CacheKeyValuePair.cs" />
<Compile Include="CacheObject\CacheListEntry.cs" />
<Compile Include="CacheObject\CacheMember.cs" />
<Compile Include="CacheObject\CacheMethod.cs" />
<Compile Include="CacheObject\CacheObjectBase.cs" />
<Compile Include="CacheObject\CacheProperty.cs" />
<Compile Include="CacheObject\Views\CacheKeyValuePairCell.cs" />
<Compile Include="CacheObject\Views\CacheListEntryCell.cs" />
<Compile Include="CacheObject\Views\CacheMemberCell.cs" />
<Compile Include="CacheObject\Views\CacheObjectCell.cs" />
<Compile Include="CacheObject\Views\EvaluateWidget.cs" />
<Compile Include="Inspectors\GameObjectInspector.cs" />
<Compile Include="CacheObject\ICacheObjectController.cs" />
<Compile Include="Inspectors\InspectorManager.cs" />
<Compile Include="Inspectors\InspectorTab.cs" />
<Compile Include="Inspectors\InspectorBase.cs" />
<Compile Include="CacheObject\IValues\InteractiveColor.cs" />
<Compile Include="CacheObject\IValues\InteractiveDictionary.cs" />
<Compile Include="CacheObject\IValues\InteractiveEnum.cs" />
<Compile Include="CacheObject\IValues\InteractiveList.cs" />
<Compile Include="CacheObject\IValues\InteractiveString.cs" />
<Compile Include="CacheObject\IValues\InteractiveValue.cs" />
<Compile Include="Inspectors\ReflectionInspector.cs" />
<Compile Include="CacheObject\IValues\InteractiveValueStruct.cs" />
<Compile Include="UI\Models\InputFieldRef.cs" />
<Compile Include="UI\Pool.cs" />
<Compile Include="UI\Panels\LogPanel.cs" />
@ -318,18 +293,18 @@
<Compile Include="Core\Runtime\RuntimeContext.cs" />
<Compile Include="Core\Runtime\RuntimeProvider.cs" />
<Compile Include="Core\Runtime\TextureUtilProvider.cs" />
<Compile Include="UI\ObjectExplorer\SceneHandler.cs" />
<Compile Include="UI\ObjectExplorer\SearchProvider.cs" />
<Compile Include="ObjectExplorer\SceneHandler.cs" />
<Compile Include="ObjectExplorer\SearchProvider.cs" />
<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" />
@ -344,8 +319,8 @@
<Compile Include="UI\Widgets\AutoComplete\AutoCompleteModal.cs" />
<Compile Include="UI\Widgets\AutoComplete\TypeCompleter.cs" />
<Compile Include="UI\Models\ButtonRef.cs" />
<Compile Include="UI\ObjectExplorer\ObjectSearch.cs" />
<Compile Include="UI\ObjectExplorer\SceneExplorer.cs" />
<Compile Include="ObjectExplorer\ObjectSearch.cs" />
<Compile Include="ObjectExplorer\SceneExplorer.cs" />
<Compile Include="UI\Widgets\ScrollPool\DataHeightCache.cs" />
<Compile Include="UI\Widgets\ScrollPool\ICell.cs" />
<Compile Include="UI\Widgets\ScrollPool\ICellPoolDataSource.cs" />

View File

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

Some files were not shown because too many files have changed in this diff Show More