mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-22 16:42:38 +08:00
Compare commits
154 Commits
Author | SHA1 | Date | |
---|---|---|---|
5c9dcb1d43 | |||
602770d980 | |||
f26371f95f | |||
a673c39f4a | |||
40583cae3d | |||
20018a9ba9 | |||
dabf92a1a5 | |||
b7e275f02c | |||
f393e0d706 | |||
ab8acc9e84 | |||
66c30ee70e | |||
ddd271c00d | |||
30fe9e4dde | |||
fa3a436037 | |||
ca27d2b20f | |||
4315e0c547 | |||
3e19e74329 | |||
5a3ffebadc | |||
6e6b6239d8 | |||
03c8e5a8bd | |||
44f7209843 | |||
734e45cf9f | |||
97838e0b3a | |||
304b47f898 | |||
3d1fcbcd9f | |||
36fc17aa43 | |||
adfa29e63c | |||
3ffdcea73b | |||
dfd55260a8 | |||
29c78dc5a6 | |||
bf59d9d6cd | |||
bb0c59534a | |||
802bb722bc | |||
9ca992b0d7 | |||
5f3b3a6870 | |||
f5bce439cb | |||
e2b2c9038a | |||
fbefccd6b7 | |||
271c91f0d0 | |||
eb221bd868 | |||
5b516eb4cc | |||
601567f9d2 | |||
7ff508b874 | |||
09a7cd35cf | |||
db4a338d26 | |||
c08e02057c | |||
362fcdc51a | |||
73bd172e4d | |||
454d3bd0b4 | |||
f815a13d9a | |||
65c4d49274 | |||
d99137526e | |||
92447b55cd | |||
87d5d5a2de | |||
08cff3386b | |||
6033200579 | |||
94ec1c4908 | |||
7a400e762c | |||
67f9f744bb | |||
7a59f9a2a1 | |||
9b42eef1b9 | |||
830000b019 | |||
34910ab273 | |||
86b036095e | |||
b57e5be2e6 | |||
2d8ae45814 | |||
66dc262a68 | |||
4342901206 | |||
58b7c72a5c | |||
623dc7b7be | |||
e6f4939cc9 | |||
7a539ba78b | |||
0d10f94eb5 | |||
91671bf243 | |||
a72877befb | |||
16335c1bc4 | |||
8fab9e6268 | |||
fdd9039cca | |||
dcca980635 | |||
bfcab8248e | |||
97c20144f1 | |||
aaab10a0a0 | |||
b42a8dbe6a | |||
d7008db22e | |||
8c1913fe80 | |||
8d8c9ac7c9 | |||
f35beeaf58 | |||
d150ff3455 | |||
c4fa0d6bcd | |||
a5f56cf5a3 | |||
8c822b2ee9 | |||
4681b7e192 | |||
97093733d8 | |||
615f77979f | |||
ba3cf970d9 | |||
b2fb571b18 | |||
67ce6f946a | |||
1b82ccb49f | |||
480eb5afd5 | |||
88ea2a09c9 | |||
a678aa4d78 | |||
eaf478e314 | |||
d391968b32 | |||
70349ad7c7 | |||
78f2d1070f | |||
51307563ab | |||
185d1aaa0f | |||
3d6e8fcbf8 | |||
1daf4fade4 | |||
d92fb3f83f | |||
fe24b68fe2 | |||
6bf92b9a96 | |||
9f1cab019d | |||
a131404ac7 | |||
773900d749 | |||
342fc6bdb8 | |||
e85ea6ac3a | |||
af889e64cb | |||
0274022ce4 | |||
211576e0f8 | |||
3e42d7479f | |||
df4dea20c1 | |||
ece0c43067 | |||
6311c8d09a | |||
04739d0be8 | |||
a46acba265 | |||
5515b2eae4 | |||
9992029e28 | |||
14105785f0 | |||
365269b0dd | |||
0b973393d1 | |||
701d4431ae | |||
bfa73bcb55 | |||
b0bbeb3cf8 | |||
1a26623080 | |||
041f2938f7 | |||
9e7bb1a625 | |||
36f23b7cdc | |||
b51b743df4 | |||
805aff07cc | |||
bcdaf3b97e | |||
cb8e947fdf | |||
c8899be3ae | |||
cd5c69c965 | |||
5427312f18 | |||
eb7e80d910 | |||
a54888ae3a | |||
4f0553d293 | |||
9f0f7f9b57 | |||
383c6f19e8 | |||
428fab28f9 | |||
760b2981ad | |||
eee7d6bcc4 | |||
e270f205a1 |
60
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
60
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal 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
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
18
.github/ISSUE_TEMPLATE/enhancement.yaml
vendored
Normal file
18
.github/ISSUE_TEMPLATE/enhancement.yaml
vendored
Normal 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
13
.github/ISSUE_TEMPLATE/other.yaml
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
name: Other
|
||||||
|
description: Something else?
|
||||||
|
title: "[Other]: "
|
||||||
|
labels: [Other]
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Describe the issue
|
||||||
|
description: |
|
||||||
|
Please describe the issue in as much detail as possible.
|
||||||
|
validations:
|
||||||
|
required: true
|
97
.github/workflows/dotnet.yml
vendored
Normal file
97
.github/workflows/dotnet.yml
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
name: Build UnityExplorer
|
||||||
|
|
||||||
|
# Controls when the action will run.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: windows-latest
|
||||||
|
if: "!contains(github.event.head_commit.message, '-noci')"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Checkout latest with submodules
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
# Setup tools
|
||||||
|
- name: Setup msbuild
|
||||||
|
uses: microsoft/setup-msbuild@v1
|
||||||
|
|
||||||
|
- name: Setup nuget
|
||||||
|
uses: nuget/setup-nuget@v1
|
||||||
|
with:
|
||||||
|
nuget-api-key: ${{ secrets.NuGetAPIKey }}
|
||||||
|
nuget-version: '5.x'
|
||||||
|
|
||||||
|
# Build Il2CppAssemblyUnhollower
|
||||||
|
- run: msbuild lib\Il2CppAssemblyUnhollower\UnhollowerBaseLib\UnhollowerBaseLib.csproj -t:Restore -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release
|
||||||
|
|
||||||
|
# Build mcs
|
||||||
|
- run: nuget restore lib\mcs-unity\mcs.sln
|
||||||
|
- run: msbuild lib\mcs-unity\mcs\mcs.csproj -t:Restore -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release
|
||||||
|
|
||||||
|
# Build UnityExplorer releases, and upload artifacts
|
||||||
|
|
||||||
|
- run: nuget restore src\UnityExplorer.sln
|
||||||
|
|
||||||
|
# BepInEx Il2Cpp
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_BIE_Cpp
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.BepInEx.Il2Cpp
|
||||||
|
path: ./Release/UnityExplorer.BepInEx.Il2Cpp/*
|
||||||
|
|
||||||
|
# BepInEx 5 Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_BIE5_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.BepInEx5.Mono
|
||||||
|
path: ./Release/UnityExplorer.BepInEx5.Mono/*
|
||||||
|
|
||||||
|
# BepInEx 6 Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_BIE6_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.BepInEx6.Mono
|
||||||
|
path: ./Release/UnityExplorer.BepInEx6.Mono/*
|
||||||
|
|
||||||
|
# MelonLoader Il2Cpp
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_ML_Cpp
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.MelonLoader.Il2Cpp
|
||||||
|
path: ./Release/UnityExplorer.MelonLoader.Il2Cpp/*
|
||||||
|
|
||||||
|
# MelonLoader Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_ML_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.MelonLoader.Mono
|
||||||
|
path: ./Release/UnityExplorer.MelonLoader.Mono/*
|
||||||
|
|
||||||
|
# Standalone Il2Cpp
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_STANDALONE_Cpp
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.Standalone.Il2Cpp
|
||||||
|
path: ./Release/UnityExplorer.Standalone.Il2Cpp/*
|
||||||
|
|
||||||
|
# Standalone Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_STANDALONE_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.Standalone.Mono
|
||||||
|
path: ./Release/UnityExplorer.Standalone.Mono/*
|
||||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,9 +1,6 @@
|
|||||||
[submodule "lib/Il2CppAssemblyUnhollower"]
|
[submodule "lib/Il2CppAssemblyUnhollower"]
|
||||||
path = lib/Il2CppAssemblyUnhollower
|
path = lib/Il2CppAssemblyUnhollower
|
||||||
url = https://github.com/knah/Il2CppAssemblyUnhollower
|
url = https://github.com/knah/Il2CppAssemblyUnhollower
|
||||||
[submodule "lib/HarmonyX"]
|
|
||||||
path = lib/HarmonyX
|
|
||||||
url = https://github.com/BepInEx/HarmonyX
|
|
||||||
[submodule "lib/mcs-unity"]
|
[submodule "lib/mcs-unity"]
|
||||||
path = lib/mcs-unity
|
path = lib/mcs-unity
|
||||||
url = https://github.com/sinai-dev/mcs-unity
|
url = https://github.com/sinai-dev/mcs-unity
|
||||||
|
105
README.md
105
README.md
@ -3,44 +3,44 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
An in-game explorer and a suite of debugging tools for <a href="https://docs.unity3d.com/Manual/IL2CPP.html">IL2CPP</a> and <b>Mono</b> Unity games, to aid with modding development.
|
🔍 An in-game UI for exploring, debugging and modifying Unity games.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Supports most Unity games from versions 5.2 to 2020+.
|
✔️ 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>)
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Releases [](../../releases/latest) [](../../releases) [](../../releases/latest)
|
# Releases [](../../releases)
|
||||||
|
|
||||||
| Mod Loader | IL2CPP | Mono |
|
[](../../releases/latest) [](https://github.com/sinai-dev/UnityExplorer/actions) [](../../releases/latest)
|
||||||
| ----------- | ------ | ---- |
|
|
||||||
| [BepInEx](https://github.com/BepInEx/BepInEx) 6.X | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx6.Mono.zip) |
|
|
||||||
| [BepInEx](https://github.com/BepInEx/BepInEx) 5.X | ✖️ n/a | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx5.Mono.zip) |
|
|
||||||
| [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3.1 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Mono.zip) |
|
|
||||||
| Standalone | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Mono.zip) |
|
|
||||||
|
|
||||||
### Known issues
|
## BepInEx
|
||||||
* Any `MissingMethodException` or `NotSupportedException`: please report the issue and provide a copy of your mod loader log and/or Unity log.
|
|
||||||
* The C# console may unexpectedly produce a GC Mark Overflow crash when calling certain outside methods. Not clear yet what is causing this, but it's being looked into.
|
|
||||||
* In IL2CPP, some IEnumerable and IDictionary types may fail enumeration. Waiting for the Unhollower rewrite to address this any further.
|
|
||||||
* In IL2CPP, the C# console might not suggest deobfuscated (or obfuscated) names. Being looked into.
|
|
||||||
|
|
||||||
## How to install
|
| Release | IL2CPP | Mono |
|
||||||
|
| ------- | ------ | ---- |
|
||||||
|
| BIE 6.X | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx6.Mono.zip) |
|
||||||
|
| BIE 5.X | ✖️ n/a | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx5.Mono.zip) |
|
||||||
|
|
||||||
### BepInEx
|
1. Take the `UnityExplorer.BIE.[version].dll` file and put it in `BepInEx\plugins\`
|
||||||
|
2. In IL2CPP, you will need to download the [Unity libs](https://github.com/LavaGang/Unity-Runtime-Libraries) for the game's Unity version, create a folder `BepInEx\unity-libs\`, then extract the Unity libs into this folder.
|
||||||
|
|
||||||
1. Install [BepInEx](https://github.com/BepInEx/BepInEx) for your game. IL2CPP currently requires a [Bleeding Edge](https://builds.bepis.io/projects/bepinex_be) release.
|
<i>Note: BepInEx 6 is obtainable via [BepisBuilds](https://builds.bepis.io/projects/bepinex_be)</i>
|
||||||
2. Download the UnityExplorer release for BepInEx IL2CPP or Mono above.
|
|
||||||
3. Take the `UnityExplorer.BIE.___.dll` file and put it in `[GameFolder]\BepInEx\plugins\`
|
|
||||||
4. In IL2CPP, you will need to download the [Unity libs](https://github.com/LavaGang/Unity-Runtime-Libraries) for the game's Unity version and put them in the `BepInEx\unity-libs\` folder.
|
|
||||||
|
|
||||||
### MelonLoader
|
## MelonLoader
|
||||||
|
|
||||||
1. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3.1+ for your game. This version can currently be obtained from [here](https://github.com/LavaGang/MelonLoader/actions).
|
| Release | IL2CPP | Mono |
|
||||||
2. Download the UnityExplorer release for MelonLoader IL2CPP or Mono above.
|
| ------- | ------ | ---- |
|
||||||
3. Take the `UnityExplorer.ML.___.dll` file and put it in the `[GameFolder]\Mods\` folder.
|
| 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) |
|
||||||
|
|
||||||
### Standalone
|
1. Take the `UnityExplorer.ML.[version].dll` file and put it in the `Mods\` folder created by MelonLoader.
|
||||||
|
|
||||||
|
## Standalone
|
||||||
|
|
||||||
|
| IL2CPP | Mono |
|
||||||
|
| ------ | ---- |
|
||||||
|
| ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Mono.zip) |
|
||||||
|
|
||||||
The standalone release can be used with any injector or loader of your choice, but it requires you to load the dependencies manually: HarmonyX, and the IL2CPP version also requires that you set up an [Il2CppAssemblyUnhollower runtime](https://github.com/knah/Il2CppAssemblyUnhollower#required-external-setup).
|
The standalone release can be used with any injector or loader of your choice, but it requires you to load the dependencies manually: HarmonyX, and the IL2CPP version also requires that you set up an [Il2CppAssemblyUnhollower runtime](https://github.com/knah/Il2CppAssemblyUnhollower#required-external-setup).
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ 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();`
|
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
|
4. Optionally subscribe to the `ExplorerStandalone.OnLog` event to handle logging if you wish
|
||||||
|
|
||||||
## Features
|
# Features
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://raw.githubusercontent.com/sinai-dev/UnityExplorer/master/img/preview.png">
|
<a href="https://raw.githubusercontent.com/sinai-dev/UnityExplorer/master/img/preview.png">
|
||||||
@ -59,48 +59,61 @@ The standalone release can be used with any injector or loader of your choice, b
|
|||||||
|
|
||||||
### Object Explorer
|
### Object Explorer
|
||||||
|
|
||||||
* Use the <b>Scene Explorer</b> tab to traverse the active scenes, as well as the DontDestroyOnLoad scene and the HideAndDontSave "scene" (assets and hidden objects).
|
* Use the <b>Scene Explorer</b> tab to traverse the active scenes, as well as the DontDestroyOnLoad and HideAndDontSave objects.
|
||||||
|
* The "HideAndDontSave" scene contains objects with that flag, as well as Assets and Resources which are not in any scene but behave the same way.
|
||||||
|
* You can use the Scene Loader to easily load any of the scenes in the build (may not work for Unity 5.X games)
|
||||||
* Use the <b>Object Search</b> tab to search for Unity objects (including GameObjects, Components, etc), C# Singletons or Static Classes.
|
* Use the <b>Object Search</b> tab to search for Unity objects (including GameObjects, Components, etc), C# Singletons or Static Classes.
|
||||||
|
* Use the UnityObject search to look for any objects which derive from `UnityEngine.Object`, with optional filters
|
||||||
|
* The singleton search will look for any classes with a typical "Instance" field, and check it for a current value. This may cause unexpected behaviour in some IL2CPP games as we cannot distinguish between true properties and field-properties, so some property accessors will be invoked.
|
||||||
|
|
||||||
### Inspector
|
### Inspector
|
||||||
|
|
||||||
The inspector is used to see detailed information on GameObjects (GameObject Inspector), C# objects (Reflection Inspector) and C# classes (Static Inspector).
|
The inspector is used to see detailed information on objects of any type and manipulate their values, as well as to inspect C# Classes with static reflection.
|
||||||
|
|
||||||
For the GameObject Inspector, you can edit any of the input fields in the inspector (excluding readonly fields) and press <b>Enter</b> to apply your changes. You can also do this to the GameObject path as a way to change the GameObject's parent. Press the <b>Escape</b> key to cancel your edits.
|
* The <b>GameObject Inspector</b> (tab prefix `[G]`) is used to inspect a `GameObject`, and to see and manipulate its Transform and Components.
|
||||||
|
* You can edit any of the input fields in the inspector (excluding readonly fields) and press <b>Enter</b> to apply your changes. You can also do this to the GameObject path as a way to change the GameObject's parent. Press the <b>Escape</b> key to cancel your edits.
|
||||||
In the Reflection Inspectors, automatic updating is not enabled by default, and you must press Apply for any changes you make to take effect.
|
* <i>note: When inspecting a GameObject with a Canvas, the transform controls may be overridden by the RectTransform anchors.</i>
|
||||||
|
* The <b>Reflection Inspectors</b> (tab prefix `[R]` and `[S]`) are used for everything else
|
||||||
|
* Automatic updating is not enabled by default, and you must press Apply for any changes you make to take effect.
|
||||||
|
* Press the `▼` button to expand certain values such as strings, enums, lists, dictionaries, some structs, etc
|
||||||
|
* Use the filters at the top to quickly find the members you are looking for
|
||||||
|
* For `Texture2D` objects, there is a `View Texture` button at the top of the inspector which lets you view it and save it as a PNG file. Currently there are no other similar helpers yet, but I may add more at some point for Mesh, Sprite, Material, etc
|
||||||
|
|
||||||
### C# Console
|
### C# Console
|
||||||
|
|
||||||
The C# Console uses the `Mono.CSharp.Evaluator` to define temporary classes or run immediate REPL code.
|
* 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.
|
* See the "Help" dropdown in the C# console menu for more detailed information.
|
||||||
|
|
||||||
### Mouse-Inspect
|
### Mouse-Inspect
|
||||||
|
|
||||||
The "Mouse Inspect" dropdown on the main UnityExplorer navbar allows you to inspect objects under the mouse.
|
* The "Mouse Inspect" dropdown on the main UnityExplorer navbar allows you to inspect objects under the mouse.
|
||||||
|
|
||||||
* <b>World</b>: uses Physics.Raycast to look for Colliders
|
* <b>World</b>: uses Physics.Raycast to look for Colliders
|
||||||
* <b>UI</b>: uses GraphicRaycasters to find UI objects
|
* <b>UI</b>: uses GraphicRaycasters to find UI objects
|
||||||
|
|
||||||
### Settings
|
### Settings
|
||||||
|
|
||||||
You can change the settings via the "Options" page of the main menu, or directly from the config file.
|
* You can change the settings via the "Options" tab of the menu, or directly from the config file.
|
||||||
|
|
||||||
Depending on the release you are using, the config file will be found at:
|
|
||||||
* BepInEx: `BepInEx\config\com.sinai.unityexplorer.cfg`
|
* BepInEx: `BepInEx\config\com.sinai.unityexplorer.cfg`
|
||||||
* MelonLoader: `UserData\MelonPreferences.cfg`
|
* MelonLoader: `UserData\MelonPreferences.cfg`
|
||||||
* Standalone `{DLL_location}\UnityExplorer\config.ini`
|
* Standalone `{DLL_location}\UnityExplorer\config.ini`
|
||||||
|
|
||||||
## Building
|
# Building
|
||||||
|
|
||||||
|
If you fork the repository on GitHub you can build using the [dotnet workflow](https://github.com/sinai-dev/UnityExplorer/blob/master/.github/workflows/dotnet.yml):
|
||||||
|
|
||||||
|
0. Click on the Actions tab and enable workflows in your repository
|
||||||
|
1. Click on the "Build UnityExplorer" workflow, then click "Run Workflow" and run it manually, or make a new commit to trigger the workflow.
|
||||||
|
2. Take the artifact from the completed run.
|
||||||
|
|
||||||
|
For Visual Studio:
|
||||||
|
|
||||||
0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
|
0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
|
||||||
1. Open the `src\UnityExplorer.sln` project in Visual Studio.
|
1. Open the `src\UnityExplorer.sln` project.
|
||||||
2. Select `Solution 'UnityExplorer' (1 of 1 project)` in the Solution Explorer panel, and set the <b>Active config</b> property to the version you want to build, then build it. Alternatively, use "Batch Build" and select all releases.
|
2. Build `mcs` (Release/AnyCPU, you may need to run `nuget restore mcs.sln`), and if using IL2CPP then build `Il2CppAssemblyUnhollower` (Release/AnyCPU) as well.
|
||||||
3. The DLLs are built to the `Release\` folder in the root of the repository.
|
3. Build the UnityExplorer release(s) you want to use, either by selecting the config as the Active Config, or batch-building.
|
||||||
4. If ILRepack complains about an error, just change the Active config to a different release and then back again. This sometimes happens for the first time you build the project.
|
|
||||||
|
|
||||||
## Acknowledgments
|
# Acknowledgments
|
||||||
|
|
||||||
* [ManlyMarco](https://github.com/ManlyMarco) for [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor) \[[license](THIRDPARTY_LICENSES.md#runtimeunityeditor-license)\], the ScriptEvaluator from RUE's REPL console was used as the base for UnityExplorer's C# console.
|
* [ManlyMarco](https://github.com/ManlyMarco) for [Runtime Unity Editor](https://github.com/ManlyMarco/RuntimeUnityEditor) \[[license](THIRDPARTY_LICENSES.md#runtimeunityeditor-license)\], the ScriptEvaluator from RUE's REPL console was used as the base for UnityExplorer's C# console.
|
||||||
* [denikson](https://github.com/denikson) (aka Horse) for [mcs-unity](https://github.com/denikson/mcs-unity) \[no license\], used as the `Mono.CSharp` reference for the C# Console.
|
* [denikson](https://github.com/denikson) (aka Horse) for [mcs-unity](https://github.com/denikson/mcs-unity) \[no license\], used as the `Mono.CSharp` reference for the C# Console.
|
||||||
|
Binary file not shown.
Submodule lib/HarmonyX deleted from 64462b3e31
Submodule lib/Il2CppAssemblyUnhollower updated: 0911fdaca6...0099c25069
@ -3,10 +3,11 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityExplorer.UI.CSConsole.Lexers;
|
using UnityExplorer.CSConsole.Lexers;
|
||||||
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole
|
namespace UnityExplorer.CSConsole
|
||||||
{
|
{
|
||||||
public class CSAutoCompleter : ISuggestionProvider
|
public class CSAutoCompleter : ISuggestionProvider
|
||||||
{
|
{
|
||||||
@ -22,7 +23,6 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
AutoCompleteModal.Instance.ReleaseOwnership(this);
|
AutoCompleteModal.Instance.ReleaseOwnership(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delimiters for completions, notably does not include '.'
|
|
||||||
private readonly HashSet<char> delimiters = new HashSet<char>
|
private readonly HashSet<char> delimiters = new HashSet<char>
|
||||||
{
|
{
|
||||||
'{', '}', ',', ';', '<', '>', '(', ')', '[', ']', '=', '|', '&', '?'
|
'{', '}', ',', ';', '<', '>', '(', ')', '[', ']', '=', '|', '&', '?'
|
||||||
@ -41,7 +41,7 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
suggestions.Clear();
|
suggestions.Clear();
|
||||||
|
|
||||||
int caret = Math.Max(0, Math.Min(InputField.Text.Length - 1, InputField.Component.caretPosition - 1));
|
int caret = Math.Max(0, Math.Min(InputField.Text.Length - 1, InputField.Component.caretPosition - 1));
|
||||||
int start = caret;
|
int startIdx = caret;
|
||||||
|
|
||||||
// If the character at the caret index is whitespace or delimiter,
|
// If the character at the caret index is whitespace or delimiter,
|
||||||
// or if the next character (if it exists) is not whitespace,
|
// or if the next character (if it exists) is not whitespace,
|
||||||
@ -55,17 +55,17 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the current composition string (from caret back to last delimiter)
|
// get the current composition string (from caret back to last delimiter)
|
||||||
while (start > 0)
|
while (startIdx > 0)
|
||||||
{
|
{
|
||||||
start--;
|
startIdx--;
|
||||||
char c = InputField.Text[start];
|
char c = InputField.Text[startIdx];
|
||||||
if (delimiters.Contains(c))
|
if (delimiters.Contains(c) || char.IsWhiteSpace(c))
|
||||||
{
|
{
|
||||||
start++;
|
startIdx++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
string input = InputField.Text.Substring(start, caret - start + 1);
|
string input = InputField.Text.Substring(startIdx, caret - startIdx + 1);
|
||||||
|
|
||||||
// Get MCS completions
|
// Get MCS completions
|
||||||
|
|
@ -1,18 +1,21 @@
|
|||||||
using System;
|
using Mono.CSharp;
|
||||||
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CSConsole;
|
|
||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
|
using UnityExplorer.CSConsole;
|
||||||
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole
|
namespace UnityExplorer.CSConsole
|
||||||
{
|
{
|
||||||
public static class ConsoleController
|
public static class ConsoleController
|
||||||
{
|
{
|
||||||
@ -34,6 +37,8 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
public static bool EnableAutoIndent { get; private set; } = true;
|
public static bool EnableAutoIndent { get; private set; } = true;
|
||||||
public static bool EnableSuggestions { 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[]
|
internal static readonly string[] DefaultUsing = new string[]
|
||||||
{
|
{
|
||||||
"System",
|
"System",
|
||||||
@ -49,6 +54,7 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
|
// Make sure console is supported on this platform
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ResetConsole(false);
|
ResetConsole(false);
|
||||||
@ -61,19 +67,41 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup console
|
||||||
Lexer = new LexerBuilder();
|
Lexer = new LexerBuilder();
|
||||||
Completer = new CSAutoCompleter();
|
Completer = new CSAutoCompleter();
|
||||||
|
|
||||||
SetupHelpInteraction();
|
SetupHelpInteraction();
|
||||||
|
|
||||||
Panel.OnInputChanged += OnInputChanged;
|
Panel.OnInputChanged += OnInputChanged;
|
||||||
Panel.InputScroll.OnScroll += OnInputScrolled;
|
Panel.InputScroller.OnScroll += OnInputScrolled;
|
||||||
Panel.OnCompileClicked += Evaluate;
|
Panel.OnCompileClicked += Evaluate;
|
||||||
Panel.OnResetClicked += ResetConsole;
|
Panel.OnResetClicked += ResetConsole;
|
||||||
Panel.OnHelpDropdownChanged += HelpSelected;
|
Panel.OnHelpDropdownChanged += HelpSelected;
|
||||||
Panel.OnAutoIndentToggled += OnToggleAutoIndent;
|
Panel.OnAutoIndentToggled += OnToggleAutoIndent;
|
||||||
Panel.OnCtrlRToggled += OnToggleCtrlRShortcut;
|
Panel.OnCtrlRToggled += OnToggleCtrlRShortcut;
|
||||||
Panel.OnSuggestionsToggled += OnToggleSuggestions;
|
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}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -149,15 +177,16 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Try to "Compile" the code (tries to interpret it as REPL)
|
// Compile the code. If it returned a CompiledMethod, it is REPL.
|
||||||
var evaluation = Evaluator.Compile(input);
|
CompiledMethod repl = Evaluator.Compile(input);
|
||||||
if (evaluation != null)
|
|
||||||
|
if (repl != null)
|
||||||
{
|
{
|
||||||
// Valid REPL, we have a delegate to the evaluation.
|
// Valid REPL, we have a delegate to the evaluation.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
object ret = null;
|
object ret = null;
|
||||||
evaluation.Invoke(ref ret);
|
repl.Invoke(ref ret);
|
||||||
var result = ret?.ToString();
|
var result = ret?.ToString();
|
||||||
if (!string.IsNullOrEmpty(result))
|
if (!string.IsNullOrEmpty(result))
|
||||||
ExplorerCore.Log($"Invoked REPL, result: {ret}");
|
ExplorerCore.Log($"Invoked REPL, result: {ret}");
|
||||||
@ -171,9 +200,7 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The input was not recognized as an evaluation. Compile the code.
|
// The compiled code was not REPL, so it was a using directive or it defined classes.
|
||||||
|
|
||||||
Evaluator.Run(input);
|
|
||||||
|
|
||||||
string output = ScriptEvaluator._textWriter.ToString();
|
string output = ScriptEvaluator._textWriter.ToString();
|
||||||
var outputSplit = output.Split('\n');
|
var outputSplit = output.Split('\n');
|
||||||
@ -230,23 +257,32 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
previousInput = value;
|
previousInput = value;
|
||||||
|
|
||||||
if (EnableSuggestions && AutoCompleteModal.CheckEnter(Completer))
|
if (EnableSuggestions && AutoCompleteModal.CheckEnter(Completer))
|
||||||
{
|
|
||||||
OnAutocompleteEnter();
|
OnAutocompleteEnter();
|
||||||
}
|
|
||||||
else if (!settingCaretCoroutine)
|
|
||||||
{
|
|
||||||
if (EnableSuggestions)
|
|
||||||
Completer.CheckAutocompletes();
|
|
||||||
|
|
||||||
|
if (!settingCaretCoroutine)
|
||||||
|
{
|
||||||
if (EnableAutoIndent)
|
if (EnableAutoIndent)
|
||||||
DoAutoIndent();
|
DoAutoIndent();
|
||||||
}
|
}
|
||||||
|
|
||||||
HighlightVisibleInput();
|
var inStringOrComment = HighlightVisibleInput();
|
||||||
|
|
||||||
|
if (!settingCaretCoroutine)
|
||||||
|
{
|
||||||
|
if (EnableSuggestions)
|
||||||
|
{
|
||||||
|
if (inStringOrComment)
|
||||||
|
AutoCompleteModal.Instance.ReleaseOwnership(Completer);
|
||||||
|
else
|
||||||
|
Completer.CheckAutocompletes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpdateCaret(out _);
|
UpdateCaret(out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static float timeOfLastCtrlR;
|
||||||
|
|
||||||
public static void Update()
|
public static void Update()
|
||||||
{
|
{
|
||||||
if (SRENotSupported)
|
if (SRENotSupported)
|
||||||
@ -254,22 +290,24 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
|
|
||||||
UpdateCaret(out bool caretMoved);
|
UpdateCaret(out bool caretMoved);
|
||||||
|
|
||||||
if (!settingCaretCoroutine && EnableSuggestions && AutoCompleteModal.CheckEscape(Completer))
|
if (!settingCaretCoroutine && EnableSuggestions)
|
||||||
|
{
|
||||||
|
if (AutoCompleteModal.CheckEscape(Completer))
|
||||||
{
|
{
|
||||||
OnAutocompleteEscaped();
|
OnAutocompleteEscaped();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!settingCaretCoroutine && EnableSuggestions && caretMoved)
|
if (caretMoved)
|
||||||
{
|
|
||||||
AutoCompleteModal.Instance.ReleaseOwnership(Completer);
|
AutoCompleteModal.Instance.ReleaseOwnership(Completer);
|
||||||
//Completer.CheckAutocompletes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EnableCtrlRShortcut
|
if (EnableCtrlRShortcut
|
||||||
&& (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
|
&& (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
|
||||||
&& InputManager.GetKeyDown(KeyCode.R))
|
&& InputManager.GetKeyDown(KeyCode.R)
|
||||||
|
&& timeOfLastCtrlR.OccuredEarlierThanDefault())
|
||||||
{
|
{
|
||||||
|
timeOfLastCtrlR = Time.realtimeSinceStartup;
|
||||||
Evaluate(Panel.Input.Text);
|
Evaluate(Panel.Input.Text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,7 +343,7 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
var charBot = charTop - CSCONSOLE_LINEHEIGHT;
|
var charBot = charTop - CSCONSOLE_LINEHEIGHT;
|
||||||
|
|
||||||
var viewportMin = Input.Rect.rect.height - Input.Rect.anchoredPosition.y - (Input.Rect.rect.height * 0.5f);
|
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;
|
float diff = 0f;
|
||||||
if (charTop > viewportMin)
|
if (charTop > viewportMin)
|
||||||
@ -325,18 +363,31 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
{
|
{
|
||||||
settingCaretCoroutine = true;
|
settingCaretCoroutine = true;
|
||||||
Input.Component.readOnly = true;
|
Input.Component.readOnly = true;
|
||||||
RuntimeProvider.Instance.StartCoroutine(SetAutocompleteCaretCoro(caretPosition));
|
RuntimeProvider.Instance.StartCoroutine(SetCaretCoroutine(caretPosition));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerator SetAutocompleteCaretCoro(int caretPosition)
|
internal static PropertyInfo SelectionGuardProperty => selectionGuardPropInfo ?? GetSelectionGuardPropInfo();
|
||||||
|
|
||||||
|
private static PropertyInfo GetSelectionGuardPropInfo()
|
||||||
|
{
|
||||||
|
selectionGuardPropInfo = typeof(EventSystem).GetProperty("m_SelectionGuard");
|
||||||
|
if (selectionGuardPropInfo == null)
|
||||||
|
selectionGuardPropInfo = typeof(EventSystem).GetProperty("m_selectionGuard");
|
||||||
|
return selectionGuardPropInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PropertyInfo selectionGuardPropInfo;
|
||||||
|
|
||||||
|
private static IEnumerator SetCaretCoroutine(int caretPosition)
|
||||||
{
|
{
|
||||||
var color = Input.Component.selectionColor;
|
var color = Input.Component.selectionColor;
|
||||||
color.a = 0f;
|
color.a = 0f;
|
||||||
Input.Component.selectionColor = color;
|
Input.Component.selectionColor = color;
|
||||||
EventSystem.current.SetSelectedGameObject(null, null);
|
try { EventSystem.current.SetSelectedGameObject(null, null); } catch { }
|
||||||
yield return null;
|
yield return null;
|
||||||
|
|
||||||
EventSystem.current.SetSelectedGameObject(Input.UIRoot, null);
|
try { SelectionGuardProperty.SetValue(EventSystem.current, false, null); } catch { }
|
||||||
|
try { EventSystem.current.SetSelectedGameObject(Input.UIRoot, null); } catch { }
|
||||||
Input.Component.Select();
|
Input.Component.Select();
|
||||||
yield return null;
|
yield return null;
|
||||||
|
|
||||||
@ -351,25 +402,29 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
settingCaretCoroutine = false;
|
settingCaretCoroutine = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region Lexer Highlighting
|
#region Lexer Highlighting
|
||||||
|
|
||||||
private static void HighlightVisibleInput()
|
/// <summary>
|
||||||
|
/// Returns true if caret is inside string or comment, false otherwise
|
||||||
|
/// </summary>
|
||||||
|
private static bool HighlightVisibleInput()
|
||||||
{
|
{
|
||||||
int startIdx = 0;
|
if (string.IsNullOrEmpty(Input.Text))
|
||||||
int endIdx = Input.Text.Length - 1;
|
{
|
||||||
int topLine = 0;
|
Panel.HighlightText.text = "";
|
||||||
|
Panel.LineNumberText.text = "1";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate visible text if necessary
|
// Calculate the visible lines
|
||||||
if (Input.Rect.rect.height > Panel.InputScroll.ViewportRect.rect.height)
|
|
||||||
{
|
int topLine = -1;
|
||||||
topLine = -1;
|
|
||||||
int bottomLine = -1;
|
int bottomLine = -1;
|
||||||
|
|
||||||
// the top and bottom position of the viewport in relation to the text height
|
// 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.
|
// 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 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;
|
||||||
|
|
||||||
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
|
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
|
||||||
{
|
{
|
||||||
@ -385,14 +440,53 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
topLine = Math.Max(0, topLine - 1);
|
topLine = Math.Max(0, topLine - 1);
|
||||||
bottomLine = Math.Min(Input.TextGenerator.lineCount - 1, bottomLine + 1);
|
bottomLine = Math.Min(Input.TextGenerator.lineCount - 1, bottomLine + 1);
|
||||||
|
|
||||||
startIdx = Input.TextGenerator.lines[topLine].startCharIdx;
|
int startIdx = Input.TextGenerator.lines[topLine].startCharIdx;
|
||||||
endIdx = (bottomLine >= Input.TextGenerator.lineCount - 1)
|
int endIdx = (bottomLine >= Input.TextGenerator.lineCount - 1)
|
||||||
? Input.Text.Length - 1
|
? Input.Text.Length - 1
|
||||||
: (Input.TextGenerator.lines[bottomLine + 1].startCharIdx - 1);
|
: (Input.TextGenerator.lines[bottomLine + 1].startCharIdx - 1);
|
||||||
}
|
|
||||||
|
|
||||||
// Highlight the visible text with the LexerBuilder
|
// Highlight the visible text with the LexerBuilder
|
||||||
Panel.HighlightText.text = Lexer.BuildHighlightedString(Input.Text, startIdx, endIdx, topLine);
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -526,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!
|
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.
|
// 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.
|
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.
|
// It will remain in effect until you Reset the console.
|
@ -5,14 +5,16 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CSConsole.Lexers;
|
using UnityExplorer.CSConsole.Lexers;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole
|
namespace UnityExplorer.CSConsole
|
||||||
{
|
{
|
||||||
public struct MatchInfo
|
public struct MatchInfo
|
||||||
{
|
{
|
||||||
public int startIndex;
|
public int startIndex;
|
||||||
public int endIndex;
|
public int endIndex;
|
||||||
|
public bool isStringOrComment;
|
||||||
|
public bool matchToEndOfLine;
|
||||||
public string htmlColorTag;
|
public string htmlColorTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +84,10 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
/// <param name="endIdx">The last character you want to highlight</param>
|
/// <param name="endIdx">The last character you want to highlight</param>
|
||||||
/// <param name="leadingLines">The amount of leading empty lines you want before the first character in the return string.</param>
|
/// <param name="leadingLines">The amount of leading empty lines you want before the first character in the return string.</param>
|
||||||
/// <returns>A string which contains the amount of leading lines specified, as well as the rich-text highlighted section.</returns>
|
/// <returns>A string which contains the amount of leading lines specified, as well as the rich-text highlighted section.</returns>
|
||||||
public string BuildHighlightedString(string input, int startIdx, int endIdx, int leadingLines)
|
public string BuildHighlightedString(string input, int startIdx, int endIdx, int leadingLines, int caretIdx, out bool caretInStringOrComment)
|
||||||
{
|
{
|
||||||
|
caretInStringOrComment = false;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(input) || endIdx <= startIdx)
|
if (string.IsNullOrEmpty(input) || endIdx <= startIdx)
|
||||||
return input;
|
return input;
|
||||||
|
|
||||||
@ -105,14 +109,28 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
|
|
||||||
// append the highlighted match
|
// append the highlighted match
|
||||||
sb.Append(match.htmlColorTag);
|
sb.Append(match.htmlColorTag);
|
||||||
|
|
||||||
for (int i = match.startIndex; i <= match.endIndex && i <= currentEndIdx; i++)
|
for (int i = match.startIndex; i <= match.endIndex && i <= currentEndIdx; i++)
|
||||||
sb.Append(input[i]);
|
sb.Append(input[i]);
|
||||||
|
|
||||||
sb.Append(SignatureHighlighter.CLOSE_COLOR);
|
sb.Append(SignatureHighlighter.CLOSE_COLOR);
|
||||||
|
|
||||||
// update the last unhighlighted start index
|
// update the last unhighlighted start index
|
||||||
lastUnhighlighted = match.endIndex + 1;
|
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
|
// Append trailing unhighlighted input
|
||||||
@ -150,6 +168,7 @@ namespace UnityExplorer.UI.CSConsole
|
|||||||
startIndex = startIndex,
|
startIndex = startIndex,
|
||||||
endIndex = CommittedIndex,
|
endIndex = CommittedIndex,
|
||||||
htmlColorTag = lexer.ColorTag,
|
htmlColorTag = lexer.ColorTag,
|
||||||
|
isStringOrComment = lexer is StringLexer || lexer is CommentLexer,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
@ -2,7 +2,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
namespace UnityExplorer.CSConsole.Lexers
|
||||||
{
|
{
|
||||||
public class CommentLexer : Lexer
|
public class CommentLexer : Lexer
|
||||||
{
|
{
|
@ -2,7 +2,7 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
namespace UnityExplorer.CSConsole.Lexers
|
||||||
{
|
{
|
||||||
public class KeywordLexer : Lexer
|
public class KeywordLexer : Lexer
|
||||||
{
|
{
|
||||||
@ -41,6 +41,10 @@ namespace UnityExplorer.UI.CSConsole.Lexers
|
|||||||
while (!lexer.EndOfInput && char.IsLetter(lexer.PeekNext()))
|
while (!lexer.EndOfInput && char.IsLetter(lexer.PeekNext()))
|
||||||
sb.Append(lexer.Current);
|
sb.Append(lexer.Current);
|
||||||
|
|
||||||
|
// next must be whitespace or delimiter
|
||||||
|
if (!lexer.EndOfInput && !(char.IsWhiteSpace(lexer.Current) || lexer.IsDelimiter(lexer.Current)))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (keywords.Contains(sb.ToString()))
|
if (keywords.Contains(sb.ToString()))
|
||||||
{
|
{
|
||||||
if (!lexer.EndOfInput)
|
if (!lexer.EndOfInput)
|
@ -1,8 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
namespace UnityExplorer.CSConsole.Lexers
|
||||||
{
|
{
|
||||||
public abstract class Lexer
|
public abstract class Lexer
|
||||||
{
|
{
|
@ -1,6 +1,6 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
namespace UnityExplorer.CSConsole.Lexers
|
||||||
{
|
{
|
||||||
public class NumberLexer : Lexer
|
public class NumberLexer : Lexer
|
||||||
{
|
{
|
@ -1,7 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
namespace UnityExplorer.CSConsole.Lexers
|
||||||
{
|
{
|
||||||
public class StringLexer : Lexer
|
public class StringLexer : Lexer
|
||||||
{
|
{
|
@ -3,7 +3,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
namespace UnityExplorer.CSConsole.Lexers
|
||||||
{
|
{
|
||||||
public class SymbolLexer : Lexer
|
public class SymbolLexer : Lexer
|
||||||
{
|
{
|
||||||
@ -11,7 +11,7 @@ namespace UnityExplorer.UI.CSConsole.Lexers
|
|||||||
protected override Color HighlightColor => new Color(0.6f, 0.6f, 0.6f);
|
protected override Color HighlightColor => new Color(0.6f, 0.6f, 0.6f);
|
||||||
|
|
||||||
// all symbols are delimiters
|
// all symbols are delimiters
|
||||||
public override IEnumerable<char> Delimiters => symbols;
|
public override IEnumerable<char> Delimiters => symbols.Where(it => it != '.'); // '.' is not a delimiter, only a separator.
|
||||||
|
|
||||||
public static bool IsSymbol(char c) => symbols.Contains(c);
|
public static bool IsSymbol(char c) => symbols.Contains(c);
|
||||||
|
|
@ -1,13 +1,13 @@
|
|||||||
using System;
|
using Mono.CSharp;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Mono.CSharp;
|
|
||||||
|
|
||||||
// Thanks to ManlyMarco for this
|
// Thanks to ManlyMarco for this
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole
|
namespace UnityExplorer.CSConsole
|
||||||
{
|
{
|
||||||
public class ScriptEvaluator : Evaluator, IDisposable
|
public class ScriptEvaluator : Evaluator, IDisposable
|
||||||
{
|
{
|
@ -1,19 +1,13 @@
|
|||||||
using System;
|
using Mono.CSharp;
|
||||||
using Mono.CSharp;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using UnityEngine;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityExplorer.Core.Runtime;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityExplorer.Core.Runtime;
|
||||||
|
|
||||||
/*
|
namespace UnityExplorer.CSConsole
|
||||||
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
|
|
||||||
{
|
{
|
||||||
public class ScriptInteraction : InteractiveBase
|
public class ScriptInteraction : InteractiveBase
|
||||||
{
|
{
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.UI.CacheObject.Views;
|
using UnityExplorer.CacheObject.Views;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject
|
namespace UnityExplorer.CacheObject
|
||||||
{
|
{
|
||||||
public class CacheConfigEntry : CacheObjectBase
|
public class CacheConfigEntry : CacheObjectBase
|
||||||
{
|
{
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject
|
namespace UnityExplorer.CacheObject
|
||||||
{
|
{
|
||||||
public class CacheField : CacheMember
|
public class CacheField : CacheMember
|
||||||
{
|
{
|
@ -2,11 +2,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityExplorer.UI.CacheObject.Views;
|
using UnityExplorer.CacheObject.IValues;
|
||||||
using UnityExplorer.UI.IValues;
|
using UnityExplorer.CacheObject.Views;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject
|
namespace UnityExplorer.CacheObject
|
||||||
{
|
{
|
||||||
public class CacheKeyValuePair : CacheObjectBase
|
public class CacheKeyValuePair : CacheObjectBase
|
||||||
{
|
{
|
@ -2,10 +2,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityExplorer.UI.CacheObject.Views;
|
using UnityExplorer.CacheObject.IValues;
|
||||||
using UnityExplorer.UI.IValues;
|
using UnityExplorer.CacheObject.Views;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject
|
namespace UnityExplorer.CacheObject
|
||||||
{
|
{
|
||||||
public class CacheListEntry : CacheObjectBase
|
public class CacheListEntry : CacheObjectBase
|
||||||
{
|
{
|
@ -5,12 +5,12 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityExplorer.Core.Runtime;
|
using UnityExplorer.Core.Runtime;
|
||||||
using UnityExplorer.UI.CacheObject.Views;
|
using UnityExplorer.CacheObject.Views;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Utility;
|
using UnityExplorer.UI;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject
|
namespace UnityExplorer.CacheObject
|
||||||
{
|
{
|
||||||
public abstract class CacheMember : CacheObjectBase
|
public abstract class CacheMember : CacheObjectBase
|
||||||
{
|
{
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject
|
namespace UnityExplorer.CacheObject
|
||||||
{
|
{
|
||||||
public class CacheMethod : CacheMember
|
public class CacheMethod : CacheMember
|
||||||
{
|
{
|
@ -7,12 +7,12 @@ using System.Text;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core.Runtime;
|
using UnityExplorer.Core.Runtime;
|
||||||
using UnityExplorer.UI.CacheObject.Views;
|
using UnityExplorer.CacheObject.IValues;
|
||||||
using UnityExplorer.UI.IValues;
|
using UnityExplorer.CacheObject.Views;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Utility;
|
using UnityExplorer.UI;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject
|
namespace UnityExplorer.CacheObject
|
||||||
{
|
{
|
||||||
public enum ValueState
|
public enum ValueState
|
||||||
{
|
{
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject
|
namespace UnityExplorer.CacheObject
|
||||||
{
|
{
|
||||||
public class CacheProperty : CacheMember
|
public class CacheProperty : CacheMember
|
||||||
{
|
{
|
||||||
@ -28,10 +28,11 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
object ret;
|
||||||
if (HasArguments)
|
if (HasArguments)
|
||||||
return PropertyInfo.GetValue(DeclaringInstance, this.Evaluator.TryParseArguments());
|
ret = PropertyInfo.GetValue(DeclaringInstance, this.Evaluator.TryParseArguments());
|
||||||
|
else
|
||||||
var ret = PropertyInfo.GetValue(DeclaringInstance, null);
|
ret = PropertyInfo.GetValue(DeclaringInstance, null);
|
||||||
HadException = false;
|
HadException = false;
|
||||||
LastException = null;
|
LastException = null;
|
||||||
return ret;
|
return ret;
|
@ -3,10 +3,10 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
using UnityExplorer.UI.CacheObject.Views;
|
using UnityExplorer.CacheObject.Views;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject
|
namespace UnityExplorer.CacheObject
|
||||||
{
|
{
|
||||||
public interface ICacheObjectController
|
public interface ICacheObjectController
|
||||||
{
|
{
|
@ -4,9 +4,10 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.IValues
|
namespace UnityExplorer.CacheObject.IValues
|
||||||
{
|
{
|
||||||
public class InteractiveColor : InteractiveValue
|
public class InteractiveColor : InteractiveValue
|
||||||
{
|
{
|
@ -5,14 +5,14 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
using UnityExplorer.UI.CacheObject.Views;
|
using UnityExplorer.CacheObject.Views;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.IValues
|
namespace UnityExplorer.CacheObject.IValues
|
||||||
{
|
{
|
||||||
public class InteractiveDictionary : InteractiveValue, ICellPoolDataSource<CacheKeyValuePairCell>, ICacheObjectController
|
public class InteractiveDictionary : InteractiveValue, ICellPoolDataSource<CacheKeyValuePairCell>, ICacheObjectController
|
||||||
{
|
{
|
@ -5,9 +5,10 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.IValues
|
namespace UnityExplorer.CacheObject.IValues
|
||||||
{
|
{
|
||||||
public class InteractiveEnum : InteractiveValue
|
public class InteractiveEnum : InteractiveValue
|
||||||
{
|
{
|
@ -5,14 +5,14 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
using UnityExplorer.UI.CacheObject.Views;
|
using UnityExplorer.CacheObject.Views;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.IValues
|
namespace UnityExplorer.CacheObject.IValues
|
||||||
{
|
{
|
||||||
public class InteractiveList : InteractiveValue, ICellPoolDataSource<CacheListEntryCell>, ICacheObjectController
|
public class InteractiveList : InteractiveValue, ICellPoolDataSource<CacheListEntryCell>, ICacheObjectController
|
||||||
{
|
{
|
@ -6,10 +6,11 @@ using System.Text;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.IValues
|
namespace UnityExplorer.CacheObject.IValues
|
||||||
{
|
{
|
||||||
public class InteractiveString : InteractiveValue
|
public class InteractiveString : InteractiveValue
|
||||||
{
|
{
|
@ -4,10 +4,11 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
using UnityExplorer.UI;
|
||||||
|
using UnityExplorer.UI.Models;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.IValues
|
namespace UnityExplorer.CacheObject.IValues
|
||||||
{
|
{
|
||||||
public abstract class InteractiveValue : IPooledObject
|
public abstract class InteractiveValue : IPooledObject
|
||||||
{
|
{
|
@ -5,10 +5,10 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
using UnityExplorer.UI.Utility;
|
using UnityExplorer.UI;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.IValues
|
namespace UnityExplorer.CacheObject.IValues
|
||||||
{
|
{
|
||||||
public class InteractiveValueStruct : InteractiveValue
|
public class InteractiveValueStruct : InteractiveValue
|
||||||
{
|
{
|
@ -4,8 +4,9 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject.Views
|
namespace UnityExplorer.CacheObject.Views
|
||||||
{
|
{
|
||||||
public class ConfigEntryCell : CacheObjectCell
|
public class ConfigEntryCell : CacheObjectCell
|
||||||
{
|
{
|
@ -4,11 +4,12 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.CacheObject.IValues;
|
||||||
using UnityExplorer.UI.IValues;
|
using UnityExplorer.Inspectors;
|
||||||
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject.Views
|
namespace UnityExplorer.CacheObject.Views
|
||||||
{
|
{
|
||||||
public class CacheKeyValuePairCell : CacheObjectCell
|
public class CacheKeyValuePairCell : CacheObjectCell
|
||||||
{
|
{
|
@ -4,9 +4,9 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.IValues;
|
using UnityExplorer.CacheObject.IValues;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject.Views
|
namespace UnityExplorer.CacheObject.Views
|
||||||
{
|
{
|
||||||
public class CacheListEntryCell : CacheObjectCell
|
public class CacheListEntryCell : CacheObjectCell
|
||||||
{
|
{
|
@ -4,9 +4,10 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject.Views
|
namespace UnityExplorer.CacheObject.Views
|
||||||
{
|
{
|
||||||
public class CacheMemberCell : CacheObjectCell
|
public class CacheMemberCell : CacheObjectCell
|
||||||
{
|
{
|
@ -4,13 +4,12 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.CacheObject.IValues;
|
||||||
using UnityExplorer.UI.IValues;
|
using UnityExplorer.Inspectors;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject.Views
|
namespace UnityExplorer.CacheObject.Views
|
||||||
{
|
{
|
||||||
public abstract class CacheObjectCell : ICell
|
public abstract class CacheObjectCell : ICell
|
||||||
{
|
{
|
@ -5,11 +5,11 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Utility;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CacheObject.Views
|
namespace UnityExplorer.CacheObject.Views
|
||||||
{
|
{
|
||||||
public class EvaluateWidget : IPooledObject
|
public class EvaluateWidget : IPooledObject
|
||||||
{
|
{
|
@ -21,6 +21,7 @@ namespace UnityExplorer.Core.Config
|
|||||||
public static ConfigElement<bool> Force_Unlock_Mouse;
|
public static ConfigElement<bool> Force_Unlock_Mouse;
|
||||||
public static ConfigElement<KeyCode> Force_Unlock_Toggle;
|
public static ConfigElement<KeyCode> Force_Unlock_Toggle;
|
||||||
public static ConfigElement<bool> Aggressive_Mouse_Unlock;
|
public static ConfigElement<bool> Aggressive_Mouse_Unlock;
|
||||||
|
public static ConfigElement<bool> Disable_EventSystem_Override;
|
||||||
public static ConfigElement<string> Default_Output_Path;
|
public static ConfigElement<string> Default_Output_Path;
|
||||||
public static ConfigElement<bool> Log_Unity_Debug;
|
public static ConfigElement<bool> Log_Unity_Debug;
|
||||||
public static ConfigElement<bool> Hide_On_Startup;
|
public static ConfigElement<bool> Hide_On_Startup;
|
||||||
@ -93,7 +94,11 @@ namespace UnityExplorer.Core.Config
|
|||||||
KeyCode.None);
|
KeyCode.None);
|
||||||
|
|
||||||
Aggressive_Mouse_Unlock = new ConfigElement<bool>("Aggressive Mouse Unlock",
|
Aggressive_Mouse_Unlock = new ConfigElement<bool>("Aggressive Mouse Unlock",
|
||||||
"Use WaitForEndOfFrame to aggressively force the Mouse to be unlocked (requires game restart).",
|
"Use WaitForEndOfFrame to aggressively force the Mouse to be unlocked.\n<b>Requires restart to take effect.</b>",
|
||||||
|
false);
|
||||||
|
|
||||||
|
Disable_EventSystem_Override = new ConfigElement<bool>("Disable EventSystem override",
|
||||||
|
"If enabled, UnityExplorer will not override the EventSystem from the game.\n<b>May require restart to take effect.</b>",
|
||||||
false);
|
false);
|
||||||
|
|
||||||
Log_Unity_Debug = new ConfigElement<bool>("Log Unity Debug",
|
Log_Unity_Debug = new ConfigElement<bool>("Log Unity Debug",
|
||||||
@ -108,10 +113,11 @@ namespace UnityExplorer.Core.Config
|
|||||||
"The delay on startup before the UI is created.",
|
"The delay on startup before the UI is created.",
|
||||||
1f);
|
1f);
|
||||||
|
|
||||||
Reflection_Signature_Blacklist = new ConfigElement<string>("Reflection Signature Blacklist",
|
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." +
|
"Use this to blacklist certain member signatures if they are known to cause a crash or other issues.\r\n" +
|
||||||
"\r\nSeperate signatures with a semicolon ';'.",
|
"Seperate signatures with a semicolon ';'.\r\n" +
|
||||||
"DEFAULT");
|
"For example, to blacklist Camera.main, you would add 'UnityEngine.Camera.main;'",
|
||||||
|
"");
|
||||||
|
|
||||||
// Internal configs (panel save data)
|
// Internal configs (panel save data)
|
||||||
|
|
||||||
|
@ -87,9 +87,6 @@ namespace UnityExplorer.Core.Config
|
|||||||
foreach (var entry in ConfigManager.InternalConfigs)
|
foreach (var entry in ConfigManager.InternalConfigs)
|
||||||
sec.AddKey(entry.Key, entry.Value.BoxedValue.ToString());
|
sec.AddKey(entry.Key, entry.Value.BoxedValue.ToString());
|
||||||
|
|
||||||
if (!Directory.Exists(ExplorerCore.Loader.ConfigFolder))
|
|
||||||
Directory.CreateDirectory(ExplorerCore.Loader.ConfigFolder);
|
|
||||||
|
|
||||||
File.WriteAllText(INI_PATH, data.ToString());
|
File.WriteAllText(INI_PATH, data.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,17 +32,33 @@ namespace UnityExplorer
|
|||||||
public ExplorerBehaviour(IntPtr ptr) : base(ptr) { }
|
public ExplorerBehaviour(IntPtr ptr) : base(ptr) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private static bool onPostRenderFailed;
|
||||||
|
|
||||||
internal void Awake()
|
internal void Awake()
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
#if CPP
|
#if CPP
|
||||||
Camera.onPostRender = Camera.onPostRender == null
|
Camera.onPostRender = Camera.onPostRender == null
|
||||||
? new Action<Camera>(OnPostRender)
|
? new Action<Camera>(OnPostRender)
|
||||||
: Il2CppSystem.Delegate.Combine(Camera.onPostRender, (Camera.CameraCallback)new Action<Camera>(OnPostRender)).Cast<Camera.CameraCallback>();
|
: Il2CppSystem.Delegate.Combine(Camera.onPostRender,
|
||||||
|
(Camera.CameraCallback)new Action<Camera>(OnPostRender)).Cast<Camera.CameraCallback>();
|
||||||
|
|
||||||
|
if (Camera.onPostRender == null || Camera.onPostRender.delegates == null)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning("Failed to add Camera.onPostRender listener, falling back to LateUpdate instead!");
|
||||||
|
onPostRenderFailed = true;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
Camera.onPostRender += OnPostRender;
|
Camera.onPostRender += OnPostRender;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception adding onPostRender listener: {ex.ReflectionExToString()}\r\nFalling back to LateUpdate!");
|
||||||
|
onPostRenderFailed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal void Update()
|
internal void Update()
|
||||||
{
|
{
|
||||||
@ -54,7 +70,13 @@ namespace UnityExplorer
|
|||||||
ExplorerCore.FixedUpdate();
|
ExplorerCore.FixedUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void OnPostRender(Camera camera)
|
internal void LateUpdate()
|
||||||
|
{
|
||||||
|
if (onPostRenderFailed)
|
||||||
|
OnPostRender(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnPostRender(Camera _)
|
||||||
{
|
{
|
||||||
ExplorerCore.OnPostRender();
|
ExplorerCore.OnPostRender();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
using System;
|
using HarmonyLib;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityExplorer.Core.Input;
|
|
||||||
using BF = System.Reflection.BindingFlags;
|
|
||||||
using UnityExplorer.Core.Config;
|
|
||||||
using UnityExplorer.Core;
|
using UnityExplorer.Core;
|
||||||
|
using UnityExplorer.Core.Config;
|
||||||
|
using UnityExplorer.Core.Input;
|
||||||
using UnityExplorer.UI;
|
using UnityExplorer.UI;
|
||||||
using System.Collections;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
namespace UnityExplorer.Core.Input
|
namespace UnityExplorer.Core.Input
|
||||||
{
|
{
|
||||||
@ -37,12 +36,15 @@ namespace UnityExplorer.Core.Input
|
|||||||
lastVisibleState = Cursor.visible;
|
lastVisibleState = Cursor.visible;
|
||||||
|
|
||||||
SetupPatches();
|
SetupPatches();
|
||||||
|
|
||||||
UpdateCursorControl();
|
UpdateCursorControl();
|
||||||
|
|
||||||
|
// Hook up config values
|
||||||
|
|
||||||
|
// Force Unlock Mouse
|
||||||
Unlock = ConfigManager.Force_Unlock_Mouse.Value;
|
Unlock = ConfigManager.Force_Unlock_Mouse.Value;
|
||||||
ConfigManager.Force_Unlock_Mouse.OnValueChanged += (bool val) => { Unlock = val; };
|
ConfigManager.Force_Unlock_Mouse.OnValueChanged += (bool val) => { Unlock = val; };
|
||||||
|
|
||||||
|
// Aggressive Mouse Unlock
|
||||||
if (ConfigManager.Aggressive_Mouse_Unlock.Value)
|
if (ConfigManager.Aggressive_Mouse_Unlock.Value)
|
||||||
SetupAggressiveUnlock();
|
SetupAggressiveUnlock();
|
||||||
}
|
}
|
||||||
@ -59,13 +61,13 @@ namespace UnityExplorer.Core.Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame();
|
private static WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame();
|
||||||
|
|
||||||
private static IEnumerator AggressiveUnlockCoroutine()
|
private static IEnumerator AggressiveUnlockCoroutine()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
yield return _waitForEndOfFrame;
|
yield return _waitForEndOfFrame ?? (_waitForEndOfFrame = new WaitForEndOfFrame());
|
||||||
|
|
||||||
if (UIManager.ShowMenu)
|
if (UIManager.ShowMenu)
|
||||||
UpdateCursorControl();
|
UpdateCursorControl();
|
||||||
@ -83,7 +85,7 @@ namespace UnityExplorer.Core.Input
|
|||||||
Cursor.lockState = CursorLockMode.None;
|
Cursor.lockState = CursorLockMode.None;
|
||||||
Cursor.visible = true;
|
Cursor.visible = true;
|
||||||
|
|
||||||
if (UIManager.EventSys)
|
if (!ConfigManager.Disable_EventSystem_Override.Value && UIManager.EventSys)
|
||||||
SetEventSystem();
|
SetEventSystem();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -91,7 +93,7 @@ namespace UnityExplorer.Core.Input
|
|||||||
Cursor.lockState = lastLockMode;
|
Cursor.lockState = lastLockMode;
|
||||||
Cursor.visible = lastVisibleState;
|
Cursor.visible = lastVisibleState;
|
||||||
|
|
||||||
if (UIManager.EventSys)
|
if (!ConfigManager.Disable_EventSystem_Override.Value && UIManager.EventSys)
|
||||||
ReleaseEventSystem();
|
ReleaseEventSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,42 +148,114 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
// Patches
|
// Patches
|
||||||
|
|
||||||
private static void SetupPatches()
|
public static void SetupPatches()
|
||||||
{
|
{
|
||||||
try
|
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 e)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
ExplorerCore.Log($"Exception setting up Cursor patches: {e.GetType()}, {e.Message}");
|
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.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)
|
public static void Prefix_EventSystem_set_current(ref EventSystem value)
|
||||||
{
|
{
|
||||||
if (!UIManager.EventSys)
|
if (!settingEventSystem && value)
|
||||||
{
|
|
||||||
if (value)
|
|
||||||
{
|
{
|
||||||
lastEventSystem = value;
|
lastEventSystem = value;
|
||||||
lastInputModule = value.currentInputModule;
|
lastInputModule = value.currentInputModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!UIManager.EventSys)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!settingEventSystem && value != UIManager.EventSys)
|
if (!settingEventSystem && ShouldActuallyUnlock && !ConfigManager.Disable_EventSystem_Override.Value)
|
||||||
{
|
|
||||||
lastEventSystem = value;
|
|
||||||
lastInputModule = value?.currentInputModule;
|
|
||||||
|
|
||||||
if (ShouldActuallyUnlock)
|
|
||||||
{
|
{
|
||||||
value = UIManager.EventSys;
|
value = UIManager.EventSys;
|
||||||
value.enabled = true;
|
value.enabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true.
|
// Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true.
|
||||||
// Also keep track of when anything else tries to set Cursor state, this will be the
|
// Also keep track of when anything else tries to set Cursor state, this will be the
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using UnityEngine;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
|
|
||||||
namespace UnityExplorer.Core.Input
|
namespace UnityExplorer.Core.Input
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityExplorer.UI;
|
using UnityExplorer.UI;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace UnityExplorer.Core.Input
|
namespace UnityExplorer.Core.Input
|
||||||
{
|
{
|
||||||
@ -12,6 +12,8 @@ namespace UnityExplorer.Core.Input
|
|||||||
{
|
{
|
||||||
public InputSystem()
|
public InputSystem()
|
||||||
{
|
{
|
||||||
|
SetupSupportedDevices();
|
||||||
|
|
||||||
m_kbCurrentProp = TKeyboard.GetProperty("current");
|
m_kbCurrentProp = TKeyboard.GetProperty("current");
|
||||||
m_kbIndexer = TKeyboard.GetProperty("Item", new Type[] { TKey });
|
m_kbIndexer = TKeyboard.GetProperty("Item", new Type[] { TKey });
|
||||||
|
|
||||||
@ -32,6 +34,36 @@ namespace UnityExplorer.Core.Input
|
|||||||
.GetMethod("ReadValue");
|
.GetMethod("ReadValue");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
#region reflection cache
|
||||||
|
|
||||||
public static Type TKeyboard => m_tKeyboard ?? (m_tKeyboard = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.Keyboard"));
|
public static Type TKeyboard => m_tKeyboard ?? (m_tKeyboard = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.Keyboard"));
|
||||||
@ -138,6 +170,8 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
public bool GetMouseButtonDown(int btn)
|
public bool GetMouseButtonDown(int btn)
|
||||||
{
|
{
|
||||||
|
if (CurrentMouse == null)
|
||||||
|
return false;
|
||||||
switch (btn)
|
switch (btn)
|
||||||
{
|
{
|
||||||
case 0: return (bool)m_btnWasPressedProp.GetValue(LeftMouseButton, null);
|
case 0: return (bool)m_btnWasPressedProp.GetValue(LeftMouseButton, null);
|
||||||
@ -149,6 +183,8 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
public bool GetMouseButton(int btn)
|
public bool GetMouseButton(int btn)
|
||||||
{
|
{
|
||||||
|
if (CurrentMouse == null)
|
||||||
|
return false;
|
||||||
switch (btn)
|
switch (btn)
|
||||||
{
|
{
|
||||||
case 0: return (bool)m_btnIsPressedProp.GetValue(LeftMouseButton, null);
|
case 0: return (bool)m_btnIsPressedProp.GetValue(LeftMouseButton, null);
|
||||||
|
@ -99,8 +99,10 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
public static Exception GetInnerMostException(this Exception e)
|
public static Exception GetInnerMostException(this Exception e)
|
||||||
{
|
{
|
||||||
while (e.InnerException != null)
|
while (e != null)
|
||||||
{
|
{
|
||||||
|
if (e.InnerException == null)
|
||||||
|
break;
|
||||||
#if CPP
|
#if CPP
|
||||||
if (e.InnerException is System.Runtime.CompilerServices.RuntimeWrappedException)
|
if (e.InnerException is System.Runtime.CompilerServices.RuntimeWrappedException)
|
||||||
break;
|
break;
|
||||||
|
@ -16,6 +16,7 @@ using CppType = Il2CppSystem.Type;
|
|||||||
using BF = System.Reflection.BindingFlags;
|
using BF = System.Reflection.BindingFlags;
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnhollowerBaseLib.Attributes;
|
using UnhollowerBaseLib.Attributes;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityExplorer
|
namespace UnityExplorer
|
||||||
{
|
{
|
||||||
@ -25,10 +26,15 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
float start = Time.realtimeSinceStartup;
|
||||||
TryLoadGameModules();
|
TryLoadGameModules();
|
||||||
|
ExplorerCore.Log($"Loaded Unhollowed modules in {Time.realtimeSinceStartup - start} seconds");
|
||||||
|
|
||||||
|
start = Time.realtimeSinceStartup;
|
||||||
BuildDeobfuscationCache();
|
BuildDeobfuscationCache();
|
||||||
OnTypeLoaded += TryCacheDeobfuscatedType;
|
OnTypeLoaded += TryCacheDeobfuscatedType;
|
||||||
|
ExplorerCore.Log($"Setup IL2CPP reflection in {Time.realtimeSinceStartup - start} seconds, " +
|
||||||
|
$"deobfuscated types count: {DeobfuscatedTypes.Count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IL2CPP Extern and pointers
|
#region IL2CPP Extern and pointers
|
||||||
@ -44,15 +50,15 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
|
public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
|
||||||
{
|
{
|
||||||
if (cppClassPointers.TryGetValue(type.AssemblyQualifiedName, out il2cppPtr))
|
if (!cppClassPointers.TryGetValue(type.AssemblyQualifiedName, out il2cppPtr))
|
||||||
return il2cppPtr != IntPtr.Zero;
|
{
|
||||||
|
|
||||||
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
|
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
|
||||||
.MakeGenericType(new Type[] { type })
|
.MakeGenericType(new Type[] { type })
|
||||||
.GetField("NativeClassPtr", BF.Public | BF.Static)
|
.GetField("NativeClassPtr", BF.Public | BF.Static)
|
||||||
.GetValue(null);
|
.GetValue(null);
|
||||||
|
|
||||||
cppClassPointers.Add(type.AssemblyQualifiedName, il2cppPtr);
|
cppClassPointers.Add(type.AssemblyQualifiedName, il2cppPtr);
|
||||||
|
}
|
||||||
|
|
||||||
return il2cppPtr != IntPtr.Zero;
|
return il2cppPtr != IntPtr.Zero;
|
||||||
}
|
}
|
||||||
@ -72,9 +78,6 @@ namespace UnityExplorer
|
|||||||
foreach (var type in asm.TryGetTypes())
|
foreach (var type in asm.TryGetTypes())
|
||||||
TryCacheDeobfuscatedType(type);
|
TryCacheDeobfuscatedType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DeobfuscatedTypes.Count > 0)
|
|
||||||
ExplorerCore.Log($"Built IL2CPP deobfuscation cache, initial count: {DeobfuscatedTypes.Count}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TryCacheDeobfuscatedType(Type type)
|
private static void TryCacheDeobfuscatedType(Type type)
|
||||||
@ -129,7 +132,6 @@ namespace UnityExplorer
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var type = obj.GetType();
|
var type = obj.GetType();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (IsString(obj))
|
if (IsString(obj))
|
||||||
@ -213,7 +215,7 @@ namespace UnityExplorer
|
|||||||
// from other structs to il2cpp object
|
// from other structs to il2cpp object
|
||||||
else if (typeof(Il2CppSystem.Object).IsAssignableFrom(castTo))
|
else if (typeof(Il2CppSystem.Object).IsAssignableFrom(castTo))
|
||||||
{
|
{
|
||||||
return BoxIl2CppObject(obj);
|
return BoxIl2CppObject(obj).TryCast(castTo);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return obj;
|
return obj;
|
||||||
@ -237,11 +239,11 @@ namespace UnityExplorer
|
|||||||
else if (castTo == typeof(string))
|
else if (castTo == typeof(string))
|
||||||
return UnboxString(obj);
|
return UnboxString(obj);
|
||||||
|
|
||||||
// Casting from il2cpp object to il2cpp object...
|
|
||||||
|
|
||||||
if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr))
|
if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr))
|
||||||
return obj;
|
return obj;
|
||||||
|
|
||||||
|
// Casting from il2cpp object to il2cpp object...
|
||||||
|
|
||||||
IntPtr castFromPtr = il2cpp_object_get_class(cppObj.Pointer);
|
IntPtr castFromPtr = il2cpp_object_get_class(cppObj.Pointer);
|
||||||
|
|
||||||
if (!il2cpp_class_is_assignable_from(castToPtr, castFromPtr))
|
if (!il2cpp_class_is_assignable_from(castToPtr, castFromPtr))
|
||||||
@ -292,7 +294,27 @@ namespace UnityExplorer
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (toType.IsEnum)
|
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());
|
return Enum.Parse(toType, cppObj.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not enum, unbox with Il2CppObjectBase.Unbox
|
||||||
|
|
||||||
var name = toType.AssemblyQualifiedName;
|
var name = toType.AssemblyQualifiedName;
|
||||||
|
|
||||||
@ -459,7 +481,7 @@ namespace UnityExplorer
|
|||||||
#if ML
|
#if ML
|
||||||
Path.Combine("MelonLoader", "Managed")
|
Path.Combine("MelonLoader", "Managed")
|
||||||
#elif BIE
|
#elif BIE
|
||||||
Path.Combine("BepInEx", "unhollowed")
|
Path.Combine(BepInEx.Paths.BepInExRootPath, "unhollowed")
|
||||||
#else
|
#else
|
||||||
Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Modules")
|
Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Modules")
|
||||||
#endif
|
#endif
|
||||||
@ -515,7 +537,7 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
#region Il2cpp reflection blacklist
|
#region Il2cpp reflection blacklist
|
||||||
|
|
||||||
public override string DefaultReflectionBlacklist => string.Join(";", defaultIl2CppBlacklist);
|
public override string[] DefaultReflectionBlacklist => defaultIl2CppBlacklist.ToArray();
|
||||||
|
|
||||||
// These methods currently cause a crash in most il2cpp games,
|
// These methods currently cause a crash in most il2cpp games,
|
||||||
// even from doing "GetParameters()" on the MemberInfo.
|
// even from doing "GetParameters()" on the MemberInfo.
|
||||||
@ -777,21 +799,24 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
// Some ugly reflection to use the il2cpp interface for the instance type
|
// Some ugly reflection to use the il2cpp interface for the instance type
|
||||||
|
|
||||||
var type = list.GetType();
|
var type = list.GetActualType();
|
||||||
var key = type.AssemblyQualifiedName;
|
var key = type.AssemblyQualifiedName;
|
||||||
|
|
||||||
if (!getEnumeratorMethods.ContainsKey(key))
|
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
|
// ensure the enumerator type is supported
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var test = getEnumeratorMethods[key].Invoke(list, null);
|
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);
|
notSupportedTypes.Add(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -800,7 +825,7 @@ namespace UnityExplorer
|
|||||||
throw new NotSupportedException($"The IEnumerable type '{type.FullName}' does not support MoveNext.");
|
throw new NotSupportedException($"The IEnumerable type '{type.FullName}' does not support MoveNext.");
|
||||||
|
|
||||||
cppEnumerator = getEnumeratorMethods[key].Invoke(list, null);
|
cppEnumerator = getEnumeratorMethods[key].Invoke(list, null);
|
||||||
var enumeratorType = cppEnumerator.GetType();
|
var enumeratorType = cppEnumerator.GetActualType();
|
||||||
|
|
||||||
var enumInfoKey = enumeratorType.AssemblyQualifiedName;
|
var enumInfoKey = enumeratorType.AssemblyQualifiedName;
|
||||||
|
|
||||||
@ -854,7 +879,7 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var type = dictionary.GetType();
|
var type = dictionary.GetActualType();
|
||||||
|
|
||||||
if (typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(type))
|
if (typeof(Il2CppSystem.Collections.Hashtable).IsAssignableFrom(type))
|
||||||
{
|
{
|
||||||
@ -864,20 +889,23 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
var keys = type.GetProperty("Keys").GetValue(dictionary, null);
|
var keys = type.GetProperty("Keys").GetValue(dictionary, null);
|
||||||
|
|
||||||
var keyCollType = keys.GetType();
|
var keyCollType = keys.GetActualType();
|
||||||
var cacheKey = keys.GetType().AssemblyQualifiedName;
|
var cacheKey = keyCollType.AssemblyQualifiedName;
|
||||||
if (!getEnumeratorMethods.ContainsKey(cacheKey))
|
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
|
// test support
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var test = getEnumeratorMethods[cacheKey].Invoke(keys, null);
|
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);
|
notSupportedTypes.Add(cacheKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -888,16 +916,16 @@ namespace UnityExplorer
|
|||||||
var keyEnumerator = getEnumeratorMethods[cacheKey].Invoke(keys, null);
|
var keyEnumerator = getEnumeratorMethods[cacheKey].Invoke(keys, null);
|
||||||
var keyInfo = new EnumeratorInfo
|
var keyInfo = new EnumeratorInfo
|
||||||
{
|
{
|
||||||
current = keyEnumerator.GetType().GetProperty("Current"),
|
current = keyEnumerator.GetActualType().GetProperty("Current"),
|
||||||
moveNext = keyEnumerator.GetType().GetMethod("MoveNext"),
|
moveNext = keyEnumerator.GetActualType().GetMethod("MoveNext"),
|
||||||
};
|
};
|
||||||
|
|
||||||
var values = type.GetProperty("Values").GetValue(dictionary, null);
|
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
|
var valueInfo = new EnumeratorInfo
|
||||||
{
|
{
|
||||||
current = valueEnumerator.GetType().GetProperty("Current"),
|
current = valueEnumerator.GetActualType().GetProperty("Current"),
|
||||||
moveNext = valueEnumerator.GetType().GetMethod("MoveNext"),
|
moveNext = valueEnumerator.GetActualType().GetMethod("MoveNext"),
|
||||||
};
|
};
|
||||||
|
|
||||||
dictEnumerator = EnumerateCppDict(keyInfo, keyEnumerator, valueInfo, valueEnumerator);
|
dictEnumerator = EnumerateCppDict(keyInfo, keyEnumerator, valueInfo, valueEnumerator);
|
||||||
|
@ -4,15 +4,14 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using BF = System.Reflection.BindingFlags;
|
|
||||||
using UnityExplorer.Core.Runtime;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
|
using UnityExplorer.Core.Runtime;
|
||||||
|
using BF = System.Reflection.BindingFlags;
|
||||||
|
|
||||||
namespace UnityExplorer
|
namespace UnityExplorer
|
||||||
{
|
{
|
||||||
|
|
||||||
public class ReflectionUtility
|
public class ReflectionUtility
|
||||||
{
|
{
|
||||||
public const BF FLAGS = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
|
public const BF FLAGS = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
|
||||||
@ -43,7 +42,7 @@ namespace UnityExplorer
|
|||||||
public static Action<Type> OnTypeLoaded;
|
public static Action<Type> OnTypeLoaded;
|
||||||
|
|
||||||
/// <summary>Key: Type.FullName</summary>
|
/// <summary>Key: Type.FullName</summary>
|
||||||
public static readonly SortedDictionary<string, Type> AllTypes = new SortedDictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
|
protected static readonly SortedDictionary<string, Type> AllTypes = new SortedDictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
public static readonly List<string> AllNamespaces = new List<string>();
|
public static readonly List<string> AllNamespaces = new List<string>();
|
||||||
private static readonly HashSet<string> uniqueNamespaces = new HashSet<string>();
|
private static readonly HashSet<string> uniqueNamespaces = new HashSet<string>();
|
||||||
@ -66,10 +65,14 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
private static void SetupTypeCache()
|
private static void SetupTypeCache()
|
||||||
{
|
{
|
||||||
|
float start = Time.realtimeSinceStartup;
|
||||||
|
|
||||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
CacheTypes(asm);
|
CacheTypes(asm);
|
||||||
|
|
||||||
AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoaded;
|
AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoaded;
|
||||||
|
|
||||||
|
ExplorerCore.Log($"Cached AppDomain assemblies in {Time.realtimeSinceStartup - start} seconds");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AssemblyLoaded(object sender, AssemblyLoadEventArgs args)
|
private static void AssemblyLoaded(object sender, AssemblyLoadEventArgs args)
|
||||||
@ -84,6 +87,7 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
foreach (var type in asm.TryGetTypes())
|
foreach (var type in asm.TryGetTypes())
|
||||||
{
|
{
|
||||||
|
// Cache namespace if there is one
|
||||||
if (!string.IsNullOrEmpty(type.Namespace) && !uniqueNamespaces.Contains(type.Namespace))
|
if (!string.IsNullOrEmpty(type.Namespace) && !uniqueNamespaces.Contains(type.Namespace))
|
||||||
{
|
{
|
||||||
uniqueNamespaces.Add(type.Namespace);
|
uniqueNamespaces.Add(type.Namespace);
|
||||||
@ -97,16 +101,16 @@ namespace UnityExplorer
|
|||||||
AllNamespaces.Insert(i, type.Namespace);
|
AllNamespaces.Insert(i, type.Namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache the type. Overwrite type if one exists with the full name
|
||||||
if (AllTypes.ContainsKey(type.FullName))
|
if (AllTypes.ContainsKey(type.FullName))
|
||||||
AllTypes[type.FullName] = type;
|
AllTypes[type.FullName] = type;
|
||||||
else
|
else
|
||||||
{
|
|
||||||
AllTypes.Add(type.FullName, type);
|
AllTypes.Add(type.FullName, type);
|
||||||
//allTypeNames.Add(type.FullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Invoke listener
|
||||||
OnTypeLoaded?.Invoke(type);
|
OnTypeLoaded?.Invoke(type);
|
||||||
|
|
||||||
|
// Check type inheritance cache, add this to any lists it should be in
|
||||||
foreach (var key in typeInheritance.Keys)
|
foreach (var key in typeInheritance.Keys)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -151,13 +155,6 @@ namespace UnityExplorer
|
|||||||
internal virtual string Internal_ProcessTypeInString(string theString, Type type)
|
internal virtual string Internal_ProcessTypeInString(string theString, Type type)
|
||||||
=> theString;
|
=> theString;
|
||||||
|
|
||||||
//// Force loading modules
|
|
||||||
//public static bool LoadModule(string moduleName)
|
|
||||||
// => Instance.Internal_LoadModule(moduleName);
|
|
||||||
//
|
|
||||||
//internal virtual bool Internal_LoadModule(string moduleName)
|
|
||||||
// => false;
|
|
||||||
|
|
||||||
// Singleton finder
|
// Singleton finder
|
||||||
|
|
||||||
public static void FindSingleton(string[] possibleNames, Type type, BindingFlags flags, List<object> instances)
|
public static void FindSingleton(string[] possibleNames, Type type, BindingFlags flags, List<object> instances)
|
||||||
@ -434,20 +431,17 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
#region Reflection Blacklist
|
#region Reflection Blacklist
|
||||||
|
|
||||||
public virtual string DefaultReflectionBlacklist => string.Empty;
|
public virtual string[] DefaultReflectionBlacklist => new string[0];
|
||||||
|
|
||||||
public static void LoadBlacklistString(string blacklist)
|
public static void LoadBlacklistString(string blacklist)
|
||||||
{
|
{
|
||||||
if (string.Equals(blacklist, "DEFAULT", StringComparison.InvariantCultureIgnoreCase))
|
try
|
||||||
{
|
{
|
||||||
blacklist = Instance.DefaultReflectionBlacklist;
|
if (string.IsNullOrEmpty(blacklist) && !Instance.DefaultReflectionBlacklist.Any())
|
||||||
ConfigManager.Reflection_Signature_Blacklist.Value = blacklist;
|
|
||||||
ConfigManager.Handler.SaveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(blacklist))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
var sigs = blacklist.Split(';');
|
var sigs = blacklist.Split(';');
|
||||||
foreach (var sig in sigs)
|
foreach (var sig in sigs)
|
||||||
{
|
{
|
||||||
@ -457,9 +451,25 @@ namespace UnityExplorer
|
|||||||
if (!currentBlacklist.Contains(s))
|
if (!currentBlacklist.Contains(s))
|
||||||
currentBlacklist.Add(s);
|
currentBlacklist.Add(s);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception parsing blacklist string: {ex.ReflectionExToString()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var sig in Instance.DefaultReflectionBlacklist)
|
||||||
|
{
|
||||||
|
if (!currentBlacklist.Contains(sig))
|
||||||
|
currentBlacklist.Add(sig);
|
||||||
|
}
|
||||||
|
|
||||||
Mono.CSharp.IL2CPP.Blacklist.SignatureBlacklist = currentBlacklist;
|
Mono.CSharp.IL2CPP.Blacklist.SignatureBlacklist = currentBlacklist;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception setting up reflection blacklist: {ex.ReflectionExToString()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsBlacklisted(MemberInfo member)
|
public static bool IsBlacklisted(MemberInfo member)
|
||||||
{
|
{
|
||||||
|
@ -32,16 +32,6 @@ namespace UnityExplorer
|
|||||||
return new AssetBundle(ptr);
|
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 ~~~~~~~~~~~~
|
// ~~~~~~~~~~~~ Instance ~~~~~~~~~~~~
|
||||||
|
|
||||||
private readonly IntPtr m_bundlePtr = IntPtr.Zero;
|
private readonly IntPtr m_bundlePtr = IntPtr.Zero;
|
||||||
@ -78,7 +68,8 @@ namespace UnityExplorer
|
|||||||
return new UnityEngine.Object(ptr).TryCast<T>();
|
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);
|
internal delegate void d_Unload(IntPtr _this, bool unloadAllLoadedObjects);
|
||||||
|
|
||||||
public void Unload(bool unloadAssets = true)
|
public void Unload(bool unloadAssets = true)
|
||||||
|
@ -7,7 +7,6 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace UnityExplorer.Core.Runtime.Il2Cpp
|
namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||||
{
|
{
|
||||||
[SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "External methods")]
|
|
||||||
public static class ICallManager
|
public static class ICallManager
|
||||||
{
|
{
|
||||||
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||||
|
@ -6,8 +6,8 @@ using System.Linq;
|
|||||||
using UnhollowerBaseLib;
|
using UnhollowerBaseLib;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
// CREDIT HerpDerpenstine
|
// Credit to HerpDerpenstine and knah
|
||||||
// https://github.com/LavaGang/MelonLoader/blob/master/MelonLoader.Support.Il2Cpp/MelonCoroutines.cs
|
// https://github.com/LavaGang/MelonLoader/blob/master/SM_Il2Cpp/Coroutines.cs
|
||||||
|
|
||||||
namespace UnityExplorer.Core.Runtime.Il2Cpp
|
namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||||
{
|
{
|
||||||
|
@ -43,9 +43,9 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
ExplorerCore.LogUnity(condition, type);
|
ExplorerCore.LogUnity(condition, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void StartCoroutine(IEnumerator routine)
|
public override void Update()
|
||||||
{
|
{
|
||||||
Il2CppCoroutine.Start(routine);
|
Il2CppCoroutine.Process();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void ProcessOnPostRender()
|
internal override void ProcessOnPostRender()
|
||||||
@ -53,9 +53,14 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
Il2CppCoroutine.ProcessWaitForEndOfFrame();
|
Il2CppCoroutine.ProcessWaitForEndOfFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
internal override void ProcessFixedUpdate()
|
||||||
{
|
{
|
||||||
Il2CppCoroutine.Process();
|
Il2CppCoroutine.ProcessWaitForFixedUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void StartCoroutine(IEnumerator routine)
|
||||||
|
{
|
||||||
|
Il2CppCoroutine.Start(routine);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override T AddComponent<T>(GameObject obj, Type type)
|
public override T AddComponent<T>(GameObject obj, Type type)
|
||||||
@ -68,6 +73,7 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
return ScriptableObject.CreateInstance(Il2CppType.From(type));
|
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)
|
public override void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List<RaycastResult> list)
|
||||||
{
|
{
|
||||||
var il2cppList = new Il2CppSystem.Collections.Generic.List<RaycastResult>();
|
var il2cppList = new Il2CppSystem.Collections.Generic.List<RaycastResult>();
|
||||||
@ -112,22 +118,17 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
if (!scene.isLoaded)
|
if (!scene.isLoaded)
|
||||||
return new GameObject[0];
|
return new GameObject[0];
|
||||||
|
|
||||||
int handle = scene.handle;
|
if (scene.handle == -1)
|
||||||
|
|
||||||
if (handle == -1)
|
|
||||||
return new GameObject[0];
|
return new GameObject[0];
|
||||||
|
|
||||||
int count = GetRootCount(handle);
|
int count = GetRootCount(scene.handle);
|
||||||
|
|
||||||
if (count < 1)
|
if (count < 1)
|
||||||
return new GameObject[0];
|
return new GameObject[0];
|
||||||
|
|
||||||
var list = new Il2CppSystem.Collections.Generic.List<GameObject>(count);
|
var list = new Il2CppSystem.Collections.Generic.List<GameObject>(count);
|
||||||
|
|
||||||
var iCall = ICallManager.GetICall<d_GetRootGameObjects>("UnityEngine.SceneManagement.Scene::GetRootGameObjectsInternal");
|
var iCall = ICallManager.GetICall<d_GetRootGameObjects>("UnityEngine.SceneManagement.Scene::GetRootGameObjectsInternal");
|
||||||
|
iCall.Invoke(scene.handle, list.Pointer);
|
||||||
iCall.Invoke(handle, list.Pointer);
|
|
||||||
|
|
||||||
return list.ToArray();
|
return list.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,19 +38,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
return new Il2CppStructArray<byte>(ptr);
|
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
|
// Sprite Sprite.Create
|
||||||
|
|
||||||
public override Sprite CreateSprite(Texture2D texture)
|
public override Sprite CreateSprite(Texture2D texture)
|
||||||
|
@ -10,6 +10,7 @@ using UnityEngine.Events;
|
|||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using UnityExplorer;
|
||||||
|
|
||||||
namespace UnityExplorer.Core.Runtime.Mono
|
namespace UnityExplorer.Core.Runtime.Mono
|
||||||
{
|
{
|
||||||
@ -18,7 +19,6 @@ namespace UnityExplorer.Core.Runtime.Mono
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
ExplorerCore.Context = RuntimeContext.Mono;
|
ExplorerCore.Context = RuntimeContext.Mono;
|
||||||
//Reflection = new MonoReflection();
|
|
||||||
TextureUtil = new MonoTextureUtil();
|
TextureUtil = new MonoTextureUtil();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,34 +28,23 @@ namespace UnityExplorer.Core.Runtime.Mono
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Application_logMessageReceived(string condition, string stackTrace, LogType type)
|
private void Application_logMessageReceived(string condition, string stackTrace, LogType type)
|
||||||
{
|
=> ExplorerCore.LogUnity(condition, type);
|
||||||
ExplorerCore.LogUnity(condition, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void StartCoroutine(IEnumerator routine)
|
public override void StartCoroutine(IEnumerator routine)
|
||||||
{
|
=> ExplorerBehaviour.Instance.StartCoroutine(routine);
|
||||||
ExplorerBehaviour.Instance.StartCoroutine(routine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override T AddComponent<T>(GameObject obj, Type type)
|
public override T AddComponent<T>(GameObject obj, Type type)
|
||||||
{
|
=> (T)obj.AddComponent(type);
|
||||||
return (T)obj.AddComponent(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override ScriptableObject CreateScriptable(Type type)
|
public override ScriptableObject CreateScriptable(Type type)
|
||||||
{
|
=> ScriptableObject.CreateInstance(type);
|
||||||
return ScriptableObject.CreateInstance(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List<RaycastResult> list)
|
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);
|
=> LayerMask.LayerToName(layer);
|
||||||
@ -63,25 +52,11 @@ namespace UnityExplorer.Core.Runtime.Mono
|
|||||||
public override UnityEngine.Object[] FindObjectsOfTypeAll(Type type)
|
public override UnityEngine.Object[] FindObjectsOfTypeAll(Type type)
|
||||||
=> Resources.FindObjectsOfTypeAll(type);
|
=> Resources.FindObjectsOfTypeAll(type);
|
||||||
|
|
||||||
//private static readonly FieldInfo fi_Scene_handle = typeof(Scene).GetField("m_Handle", ReflectionUtility.AllFlags);
|
|
||||||
|
|
||||||
//public override int GetSceneHandle(Scene scene)
|
|
||||||
//{
|
|
||||||
// return (int)fi_Scene_handle.GetValue(scene);
|
|
||||||
//}
|
|
||||||
|
|
||||||
public override GameObject[] GetRootGameObjects(Scene scene)
|
public override GameObject[] GetRootGameObjects(Scene scene)
|
||||||
{
|
=> scene.isLoaded ? scene.GetRootGameObjects() : new GameObject[0];
|
||||||
if (!scene.isLoaded)
|
|
||||||
return new GameObject[0];
|
|
||||||
|
|
||||||
return scene.GetRootGameObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetRootCount(Scene scene)
|
public override int GetRootCount(Scene scene)
|
||||||
{
|
=> scene.rootCount;
|
||||||
return scene.rootCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetColorBlock(Selectable selectable, Color? normal = null, Color? highlighted = null, Color? pressed = null,
|
public override void SetColorBlock(Selectable selectable, Color? normal = null, Color? highlighted = null, Color? pressed = null,
|
||||||
Color? disabled = null)
|
Color? disabled = null)
|
||||||
@ -104,58 +79,41 @@ namespace UnityExplorer.Core.Runtime.Mono
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void SetColorBlock(Selectable selectable, ColorBlock colors)
|
public override void SetColorBlock(Selectable selectable, ColorBlock colors)
|
||||||
{
|
=> selectable.colors = colors;
|
||||||
selectable.colors = colors;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MonoExtensions
|
public static class MonoExtensions
|
||||||
{
|
{
|
||||||
|
// Helpers to use the same style of AddListener that IL2CPP uses.
|
||||||
|
|
||||||
public static void AddListener(this UnityEvent _event, Action listener)
|
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)
|
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)
|
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)
|
public static void RemoveListener<T>(this UnityEvent<T> _event, Action<T> listener)
|
||||||
{
|
=> _event.RemoveListener(new UnityAction<T>(listener));
|
||||||
_event.RemoveListener(new UnityAction<T>(listener));
|
|
||||||
}
|
// Doesn't exist in NET 3.5
|
||||||
|
|
||||||
public static void Clear(this StringBuilder sb)
|
public static void Clear(this StringBuilder sb)
|
||||||
{
|
=> sb.Remove(0, sb.Length);
|
||||||
sb.Remove(0, sb.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PropertyInfo pi_childControlHeight;
|
// 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)
|
public static void SetChildControlHeight(this HorizontalOrVerticalLayoutGroup group, bool value)
|
||||||
{
|
=> ReflectionUtility.GetPropertyInfo(typeof(HorizontalOrVerticalLayoutGroup), "childControlHeight")
|
||||||
if (pi_childControlHeight == null)
|
?.SetValue(group, value, null);
|
||||||
pi_childControlHeight = group.GetType().GetProperty("childControlHeight");
|
|
||||||
|
|
||||||
pi_childControlHeight?.SetValue(group, value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PropertyInfo pi_childControlWidth;
|
|
||||||
|
|
||||||
public static void SetChildControlWidth(this HorizontalOrVerticalLayoutGroup group, bool value)
|
public static void SetChildControlWidth(this HorizontalOrVerticalLayoutGroup group, bool value)
|
||||||
{
|
=> ReflectionUtility.GetPropertyInfo(typeof(HorizontalOrVerticalLayoutGroup), "childControlWidth")
|
||||||
if (pi_childControlWidth == null)
|
?.SetValue(group, value, null);
|
||||||
pi_childControlWidth = group.GetType().GetProperty("childControlWidth");
|
|
||||||
|
|
||||||
pi_childControlWidth?.SetValue(group, value, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -12,41 +12,28 @@ namespace UnityExplorer.Core.Runtime.Mono
|
|||||||
public class MonoTextureUtil : TextureUtilProvider
|
public class MonoTextureUtil : TextureUtilProvider
|
||||||
{
|
{
|
||||||
public override void Blit(Texture2D tex, RenderTexture rt)
|
public override void Blit(Texture2D tex, RenderTexture rt)
|
||||||
{
|
=> Graphics.Blit(tex, rt);
|
||||||
Graphics.Blit(tex, rt);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Sprite CreateSprite(Texture2D texture)
|
public override Sprite CreateSprite(Texture2D texture)
|
||||||
{
|
=> Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
|
||||||
return Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.zero);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable)
|
//public override bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable)
|
||||||
{
|
// => tex.LoadImage(data, markNonReadable);
|
||||||
return tex.LoadImage(data, markNonReadable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Texture2D NewTexture2D(int width, int height)
|
public override Texture2D NewTexture2D(int width, int height)
|
||||||
{
|
=> new Texture2D(width, height);
|
||||||
return new Texture2D(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override byte[] EncodeToPNG(Texture2D tex)
|
public override byte[] EncodeToPNG(Texture2D tex)
|
||||||
{
|
=> EncodeToPNGSafe(tex);
|
||||||
return EncodeToPNGSafe(tex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MethodInfo EncodeToPNGMethod => m_encodeToPNGMethod ?? GetEncodeToPNGMethod();
|
private static MethodInfo EncodeToPNGMethod => m_encodeToPNGMethod ?? GetEncodeToPNGMethod();
|
||||||
private static MethodInfo m_encodeToPNGMethod;
|
private static MethodInfo m_encodeToPNGMethod;
|
||||||
|
|
||||||
public static byte[] EncodeToPNGSafe(Texture2D tex)
|
public static byte[] EncodeToPNGSafe(Texture2D tex)
|
||||||
{
|
{
|
||||||
var method = EncodeToPNGMethod;
|
return EncodeToPNGMethod.IsStatic
|
||||||
|
? (byte[])EncodeToPNGMethod.Invoke(null, new object[] { tex })
|
||||||
if (method.IsStatic)
|
: (byte[])EncodeToPNGMethod.Invoke(tex, ArgumentUtility.EmptyArgs);
|
||||||
return (byte[])method.Invoke(null, new object[] { tex });
|
|
||||||
else
|
|
||||||
return (byte[])method.Invoke(tex, ArgumentUtility.EmptyArgs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MethodInfo GetEncodeToPNGMethod()
|
private static MethodInfo GetEncodeToPNGMethod()
|
||||||
|
@ -40,8 +40,6 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
public abstract void Update();
|
public abstract void Update();
|
||||||
|
|
||||||
//public virtual bool IsReferenceEqual(object a, object b) => ReferenceEquals(a, b);
|
|
||||||
|
|
||||||
// Unity API handlers
|
// Unity API handlers
|
||||||
|
|
||||||
public abstract T AddComponent<T>(GameObject obj, Type type) where T : Component;
|
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 void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List<RaycastResult> list);
|
||||||
|
|
||||||
//public abstract int GetSceneHandle(Scene scene);
|
|
||||||
|
|
||||||
public abstract GameObject[] GetRootGameObjects(Scene scene);
|
public abstract GameObject[] GetRootGameObjects(Scene scene);
|
||||||
|
|
||||||
public abstract int GetRootCount(Scene scene);
|
public abstract int GetRootCount(Scene scene);
|
||||||
|
@ -22,7 +22,7 @@ namespace UnityExplorer.Core.Runtime
|
|||||||
|
|
||||||
public abstract void Blit(Texture2D tex, RenderTexture rt);
|
public abstract 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);
|
public abstract Sprite CreateSprite(Texture2D texture);
|
||||||
|
|
||||||
@ -43,27 +43,22 @@ namespace UnityExplorer.Core.Runtime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool LoadImage(Texture2D tex, string filePath, bool markNonReadable)
|
//public static bool LoadImage(Texture2D tex, string filePath, bool markNonReadable)
|
||||||
{
|
//{
|
||||||
if (!File.Exists(filePath))
|
// if (!File.Exists(filePath))
|
||||||
return false;
|
// return false;
|
||||||
|
//
|
||||||
return Instance.LoadImage(tex, File.ReadAllBytes(filePath), markNonReadable);
|
// return Instance.LoadImage(tex, File.ReadAllBytes(filePath), markNonReadable);
|
||||||
}
|
//}
|
||||||
|
|
||||||
public static Texture2D Copy(Texture2D orig, Rect rect)
|
public static Texture2D Copy(Texture2D orig, Rect rect)
|
||||||
{
|
{
|
||||||
Color[] pixels;
|
|
||||||
|
|
||||||
if (!IsReadable(orig))
|
if (!IsReadable(orig))
|
||||||
orig = ForceReadTexture(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);
|
Texture2D newTex = Instance.NewTexture2D((int)rect.width, (int)rect.height);
|
||||||
|
|
||||||
newTex.SetPixels(pixels);
|
newTex.SetPixels(pixels);
|
||||||
|
|
||||||
return newTex;
|
return newTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +87,7 @@ namespace UnityExplorer.Core.Runtime
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExplorerCore.Log("Exception on ForceReadTexture: " + e.ToString());
|
ExplorerCore.Log($"Exception on ForceReadTexture: {e.ToString()}");
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,13 +98,11 @@ namespace UnityExplorer.Core.Runtime
|
|||||||
Directory.CreateDirectory(dir);
|
Directory.CreateDirectory(dir);
|
||||||
|
|
||||||
byte[] data;
|
byte[] data;
|
||||||
string savepath = dir + @"\" + name + ".png";
|
string savepath = $@"{dir}\{name}.png";
|
||||||
|
|
||||||
// Make sure we can EncodeToPNG it.
|
// Make sure we can EncodeToPNG it.
|
||||||
if (tex.format != TextureFormat.ARGB32 || !IsReadable(tex))
|
if (tex.format != TextureFormat.ARGB32 || !IsReadable(tex))
|
||||||
{
|
|
||||||
tex = ForceReadTexture(tex);
|
tex = ForceReadTexture(tex);
|
||||||
}
|
|
||||||
|
|
||||||
if (isDTXnmNormal)
|
if (isDTXnmNormal)
|
||||||
{
|
{
|
||||||
@ -120,14 +113,10 @@ namespace UnityExplorer.Core.Runtime
|
|||||||
data = Instance.EncodeToPNG(tex);
|
data = Instance.EncodeToPNG(tex);
|
||||||
|
|
||||||
if (data == null || !data.Any())
|
if (data == null || !data.Any())
|
||||||
{
|
|
||||||
ExplorerCore.LogWarning("Couldn't get any data for the texture!");
|
ExplorerCore.LogWarning("Couldn't get any data for the texture!");
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
File.WriteAllBytes(savepath, data);
|
File.WriteAllBytes(savepath, data);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Converts DTXnm-format Normal Map to RGBA-format Normal Map.
|
// Converts DTXnm-format Normal Map to RGBA-format Normal Map.
|
||||||
public static Texture2D DTXnmToRGBA(Texture2D tex)
|
public static Texture2D DTXnmToRGBA(Texture2D tex)
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityExplorer.UI.IValues;
|
|
||||||
using System.Reflection;
|
|
||||||
using UnityExplorer.UI;
|
using UnityExplorer.UI;
|
||||||
|
using UnityExplorer.CacheObject.IValues;
|
||||||
#if CPP
|
#if CPP
|
||||||
using UnhollowerRuntimeLib;
|
using UnhollowerRuntimeLib;
|
||||||
using UnhollowerBaseLib;
|
using UnhollowerBaseLib;
|
||||||
@ -14,112 +14,31 @@ using UnhollowerBaseLib;
|
|||||||
|
|
||||||
namespace UnityExplorer.Tests
|
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 class TestClass
|
||||||
{
|
{
|
||||||
public static readonly TestIndexer AAAAATest = new TestIndexer();
|
static TestClass()
|
||||||
|
|
||||||
public static void ATestMethod(string s, float f, Vector3 vector, DateTime date, Quaternion quater, bool b, CameraClearFlags enumvalue)
|
|
||||||
{
|
{
|
||||||
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 };
|
// Test enumerables
|
||||||
public static Dictionary<string, int> AWritableDict = new Dictionary<string, int> { { "one", 1 }, { "two", 2 } };
|
public static List<object> ListOfInts;
|
||||||
|
public static List<List<List<string>>> NestedList;
|
||||||
public static IEnumerable ANestedList = new List<List<List<string>>>
|
public static IDictionary MixedDictionary;
|
||||||
{
|
public static Hashtable Hashtable;
|
||||||
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;
|
|
||||||
|
|
||||||
public static byte[] ByteArray = new byte[16];
|
public static byte[] ByteArray = new byte[16];
|
||||||
public static string LongString = new string('#', 10000);
|
public static List<short> ABigList = new List<short>(10000);
|
||||||
public static List<string> BigList = new List<string>(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
|
public static List<object> RandomList
|
||||||
{
|
{
|
||||||
@ -133,25 +52,7 @@ namespace UnityExplorer.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void TestGeneric<T>()
|
// Test methods
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static object GetRandomObject()
|
private static object GetRandomObject()
|
||||||
{
|
{
|
||||||
@ -165,109 +66,133 @@ namespace UnityExplorer.Tests
|
|||||||
case 2: return true;
|
case 2: return true;
|
||||||
case 3: return "hello";
|
case 3: return "hello";
|
||||||
case 4: return 50.5f;
|
case 4: return 50.5f;
|
||||||
case 5: return UnityEngine.CameraClearFlags.Color;
|
case 5: return CameraClearFlags.Color;
|
||||||
case 6: return new List<string> { "sub list", "lol" };
|
case 6: return new List<string> { "one", "two" };
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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
|
#if CPP
|
||||||
|
|
||||||
public static Il2CppSystem.Collections.IList IL2CPP_IList;
|
|
||||||
public static Il2CppSystem.Collections.Generic.List<string> IL2CPP_ListString;
|
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 List<Il2CppSystem.Object> IL2CPP_listOfBoxedObjects;
|
||||||
public static Il2CppStructArray<int> IL2CPP_structArray;
|
public static Il2CppStructArray<int> IL2CPP_structArray;
|
||||||
public static Il2CppStringArray IL2CPP_stringArray;
|
|
||||||
public static Il2CppReferenceArray<Il2CppSystem.Object> IL2CPP_ReferenceArray;
|
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.Object cppBoxedInt;
|
||||||
public static Il2CppSystem.Int32 cppInt;
|
public static Il2CppSystem.Int32 cppInt;
|
||||||
public static Il2CppSystem.Decimal cppDecimal;
|
public static Il2CppSystem.Decimal cppDecimal;
|
||||||
public static Il2CppSystem.Object cppDecimalBoxed;
|
public static Il2CppSystem.Object cppDecimalBoxed;
|
||||||
public static Il2CppSystem.Object cppVector3Boxed;
|
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
|
ExplorerCore.Log($"IL2CPP 1: Il2Cpp Dictionary<string, string>");
|
||||||
{
|
|
||||||
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
|
|
||||||
IL2CPP_Dict = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
|
IL2CPP_Dict = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
|
||||||
IL2CPP_Dict.Add("key1", "value1");
|
IL2CPP_Dict.Add("key1", "value1");
|
||||||
IL2CPP_Dict.Add("key2", "value2");
|
IL2CPP_Dict.Add("key2", "value2");
|
||||||
IL2CPP_Dict.Add("key3", "value3");
|
IL2CPP_Dict.Add("key3", "value3");
|
||||||
|
|
||||||
|
ExplorerCore.Log($"IL2CPP 2: Il2Cpp Hashtable");
|
||||||
IL2CPP_HashTable = new Il2CppSystem.Collections.Hashtable();
|
IL2CPP_HashTable = new Il2CppSystem.Collections.Hashtable();
|
||||||
IL2CPP_HashTable.Add("key1", "value1");
|
IL2CPP_HashTable.Add("key1", "value1");
|
||||||
IL2CPP_HashTable.Add("key2", "value2");
|
IL2CPP_HashTable.Add("key2", "value2");
|
||||||
IL2CPP_HashTable.Add("key3", "value3");
|
IL2CPP_HashTable.Add("key3", "value3");
|
||||||
|
|
||||||
|
ExplorerCore.Log($"IL2CPP 3: Il2Cpp IDictionary");
|
||||||
var dict2 = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
|
var dict2 = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
|
||||||
dict2.Add("key1", "value1");
|
dict2.Add("key1", "value1");
|
||||||
IL2CPP_IDict = dict2.TryCast<Il2CppSystem.Collections.IDictionary>();
|
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);
|
var list = new Il2CppSystem.Collections.Generic.List<Il2CppSystem.Object>(5);
|
||||||
list.Add("one");
|
list.Add("one");
|
||||||
list.Add("two");
|
list.Add("two");
|
||||||
IL2CPP_IList = list.TryCast<Il2CppSystem.Collections.IList>();
|
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 = new Il2CppSystem.Collections.Generic.List<string>();
|
||||||
IL2CPP_ListString.Add("hello,");
|
IL2CPP_ListString.Add("hello,");
|
||||||
IL2CPP_ListString.Add("world!");
|
IL2CPP_ListString.Add("world!");
|
||||||
|
|
||||||
|
ExplorerCore.Log($"IL2CPP 6: Il2Cpp HashSet of strings");
|
||||||
IL2CPP_HashSet = new Il2CppSystem.Collections.Generic.HashSet<string>();
|
IL2CPP_HashSet = new Il2CppSystem.Collections.Generic.HashSet<string>();
|
||||||
IL2CPP_HashSet.Add("one");
|
IL2CPP_HashSet.Add("one");
|
||||||
IL2CPP_HashSet.Add("two");
|
IL2CPP_HashSet.Add("two");
|
||||||
|
|
||||||
|
ExplorerCore.Log($"IL2CPP 7: Dictionary of Il2Cpp String and Il2Cpp Object");
|
||||||
CppBoxedDict = new Dictionary<Il2CppSystem.String, Il2CppSystem.Object>();
|
CppBoxedDict = new Dictionary<Il2CppSystem.String, Il2CppSystem.Object>();
|
||||||
CppBoxedDict.Add("1", new Il2CppSystem.Int32 { m_value = 1 }.BoxIl2CppObject());
|
CppBoxedDict.Add("1", new Il2CppSystem.Int32 { m_value = 1 }.BoxIl2CppObject());
|
||||||
CppBoxedDict.Add("2", new Il2CppSystem.Int32 { m_value = 2 }.BoxIl2CppObject());
|
CppBoxedDict.Add("2", new Il2CppSystem.Int32 { m_value = 2 }.BoxIl2CppObject());
|
||||||
CppBoxedDict.Add("3", new Il2CppSystem.Int32 { m_value = 3 }.BoxIl2CppObject());
|
CppBoxedDict.Add("3", new Il2CppSystem.Int32 { m_value = 3 }.BoxIl2CppObject());
|
||||||
CppBoxedDict.Add("4", new Il2CppSystem.Int32 { m_value = 4 }.BoxIl2CppObject());
|
CppBoxedDict.Add("4", new Il2CppSystem.Int32 { m_value = 4 }.BoxIl2CppObject());
|
||||||
|
|
||||||
cppDecimal = new Il2CppSystem.Decimal(1f);
|
ExplorerCore.Log($"IL2CPP 8: List of boxed Il2Cpp Objects");
|
||||||
cppDecimalBoxed = new Il2CppSystem.Decimal(1f).BoxIl2CppObject();
|
|
||||||
cppVector3Boxed = Vector3.down.BoxIl2CppObject();
|
|
||||||
|
|
||||||
|
|
||||||
IL2CPP_listOfBoxedObjects = new List<Il2CppSystem.Object>();
|
IL2CPP_listOfBoxedObjects = new List<Il2CppSystem.Object>();
|
||||||
IL2CPP_listOfBoxedObjects.Add((Il2CppSystem.String)"boxedString");
|
IL2CPP_listOfBoxedObjects.Add((Il2CppSystem.String)"boxedString");
|
||||||
IL2CPP_listOfBoxedObjects.Add(new Il2CppSystem.Int32 { m_value = 5 }.BoxIl2CppObject());
|
IL2CPP_listOfBoxedObjects.Add(new Il2CppSystem.Int32 { m_value = 5 }.BoxIl2CppObject());
|
||||||
IL2CPP_listOfBoxedObjects.Add(Color.red.BoxIl2CppObject());
|
IL2CPP_listOfBoxedObjects.Add(Color.red.BoxIl2CppObject());
|
||||||
|
// boxed enum test
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var cppType = Il2CppType.Of<CameraClearFlags>();
|
var cppType = Il2CppType.Of<CameraClearFlags>();
|
||||||
@ -283,9 +208,10 @@ namespace UnityExplorer.Tests
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
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 = new UnhollowerBaseLib.Il2CppStructArray<int>(5);
|
||||||
IL2CPP_structArray[0] = 0;
|
IL2CPP_structArray[0] = 0;
|
||||||
IL2CPP_structArray[1] = 1;
|
IL2CPP_structArray[1] = 1;
|
||||||
@ -293,24 +219,21 @@ namespace UnityExplorer.Tests
|
|||||||
IL2CPP_structArray[3] = 3;
|
IL2CPP_structArray[3] = 3;
|
||||||
IL2CPP_structArray[4] = 4;
|
IL2CPP_structArray[4] = 4;
|
||||||
|
|
||||||
IL2CPP_stringArray = new UnhollowerBaseLib.Il2CppStringArray(2);
|
ExplorerCore.Log($"IL2CPP 10: Il2Cpp reference array of boxed objects");
|
||||||
IL2CPP_stringArray[0] = "hello, ";
|
|
||||||
IL2CPP_stringArray[1] = "world!";
|
|
||||||
|
|
||||||
IL2CPP_ReferenceArray = new UnhollowerBaseLib.Il2CppReferenceArray<Il2CppSystem.Object>(3);
|
IL2CPP_ReferenceArray = new UnhollowerBaseLib.Il2CppReferenceArray<Il2CppSystem.Object>(3);
|
||||||
IL2CPP_ReferenceArray[0] = new Il2CppSystem.Int32 { m_value = 5 }.BoxIl2CppObject();
|
IL2CPP_ReferenceArray[0] = new Il2CppSystem.Int32 { m_value = 5 }.BoxIl2CppObject();
|
||||||
IL2CPP_ReferenceArray[1] = null;
|
IL2CPP_ReferenceArray[1] = null;
|
||||||
IL2CPP_ReferenceArray[2] = (Il2CppSystem.String)"whats up";
|
IL2CPP_ReferenceArray[2] = (Il2CppSystem.String)"whats up";
|
||||||
|
|
||||||
|
ExplorerCore.Log($"IL2CPP 11: Misc il2cpp members");
|
||||||
cppBoxedInt = new Il2CppSystem.Int32() { m_value = 5 }.BoxIl2CppObject();
|
cppBoxedInt = new Il2CppSystem.Int32() { m_value = 5 }.BoxIl2CppObject();
|
||||||
cppInt = new Il2CppSystem.Int32 { m_value = 420 };
|
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();
|
ExplorerCore.Log($"Finished Init_Il2Cpp");
|
||||||
cppHashset.Add("key1", "itemOne");
|
}
|
||||||
cppHashset.Add("key2", "itemTwo");
|
|
||||||
cppHashset.Add("key3", "itemThree");
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -13,7 +13,7 @@ namespace UnityExplorer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool ContainsIgnoreCase(this string _this, string s)
|
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>
|
/// <summary>
|
||||||
|
@ -10,8 +10,6 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
public static class ParseUtility
|
public static class ParseUtility
|
||||||
{
|
{
|
||||||
public static CultureInfo en_US = new CultureInfo("en-US");
|
|
||||||
|
|
||||||
private static readonly HashSet<Type> nonPrimitiveTypes = new HashSet<Type>
|
private static readonly HashSet<Type> nonPrimitiveTypes = new HashSet<Type>
|
||||||
{
|
{
|
||||||
typeof(string),
|
typeof(string),
|
||||||
@ -19,20 +17,18 @@ namespace UnityExplorer
|
|||||||
typeof(DateTime),
|
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>();
|
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)
|
public static string FormatDecimalSequence(params object[] numbers)
|
||||||
{
|
{
|
||||||
if (numbers.Length <= 0)
|
if (numbers.Length <= 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
int count = numbers.Length;
|
return string.Format(CultureInfo.CurrentCulture, GetSequenceFormatString(numbers.Length), numbers);
|
||||||
var formatString = GetSequenceFormatString(count);
|
|
||||||
|
|
||||||
return string.Format(en_US, formatString, numbers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetSequenceFormatString(int count)
|
public static string GetSequenceFormatString(int count)
|
||||||
@ -46,19 +42,19 @@ namespace UnityExplorer
|
|||||||
string[] strings = new string[count];
|
string[] strings = new string[count];
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
strings[i] = $"{{{i}:{NUMBER_FORMAT}}}";
|
strings[i] = $"{{{i}:{NumberFormatString}}}";
|
||||||
|
|
||||||
string s = string.Join(", ", strings);
|
string ret = string.Join(" ", strings);
|
||||||
|
numSequenceStrings.Add(count, ret);
|
||||||
numSequenceStrings.Add(count, s);
|
return ret;
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Main parsing API
|
||||||
|
|
||||||
public static bool CanParse(Type type)
|
public static bool CanParse(Type type)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(type.FullName))
|
return !string.IsNullOrEmpty(type?.FullName)
|
||||||
return false;
|
&& (type.IsPrimitive || type.IsEnum || nonPrimitiveTypes.Contains(type) || customTypes.ContainsKey(type.FullName));
|
||||||
return 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)
|
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))
|
else if (formattedTypes.Contains(type))
|
||||||
{
|
{
|
||||||
return ReflectionUtility.GetMethodInfo(type, "ToString", new Type[] { typeof(string), typeof(IFormatProvider) })
|
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;
|
as string;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -166,9 +162,7 @@ namespace UnityExplorer
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (type.IsEnum)
|
if (type.IsEnum)
|
||||||
{
|
|
||||||
typeInputExamples.Add(type.AssemblyQualifiedName, Enum.GetNames(type).First());
|
typeInputExamples.Add(type.AssemblyQualifiedName, Enum.GetNames(type).First());
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var instance = Activator.CreateInstance(type);
|
var instance = Activator.CreateInstance(type);
|
||||||
@ -222,10 +216,10 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
Vector2 vector = default;
|
Vector2 vector = default;
|
||||||
|
|
||||||
var split = input.Split(',');
|
var split = input.Split(' ');
|
||||||
|
|
||||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
vector.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
vector.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||||
|
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
@ -244,11 +238,11 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
Vector3 vector = default;
|
Vector3 vector = default;
|
||||||
|
|
||||||
var split = input.Split(',');
|
var split = input.Split(' ');
|
||||||
|
|
||||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
vector.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
vector.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||||
vector.z = float.Parse(split[2].Trim(), en_US);
|
vector.z = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||||
|
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
@ -267,12 +261,12 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
Vector4 vector = default;
|
Vector4 vector = default;
|
||||||
|
|
||||||
var split = input.Split(',');
|
var split = input.Split(' ');
|
||||||
|
|
||||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
vector.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
vector.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||||
vector.z = float.Parse(split[2].Trim(), en_US);
|
vector.z = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||||
vector.w = float.Parse(split[3].Trim(), en_US);
|
vector.w = float.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||||
|
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
@ -291,22 +285,22 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
Vector3 vector = default;
|
Vector3 vector = default;
|
||||||
|
|
||||||
var split = input.Split(',');
|
var split = input.Split(' ');
|
||||||
|
|
||||||
if (split.Length == 4)
|
if (split.Length == 4)
|
||||||
{
|
{
|
||||||
Quaternion quat = default;
|
Quaternion quat = default;
|
||||||
quat.x = float.Parse(split[0].Trim(), en_US);
|
quat.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||||
quat.y = float.Parse(split[1].Trim(), en_US);
|
quat.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||||
quat.z = float.Parse(split[2].Trim(), en_US);
|
quat.z = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||||
quat.w = float.Parse(split[3].Trim(), en_US);
|
quat.w = float.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||||
return quat;
|
return quat;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vector.x = float.Parse(split[0].Trim(), en_US);
|
vector.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||||
vector.y = float.Parse(split[1].Trim(), en_US);
|
vector.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||||
vector.z = float.Parse(split[2].Trim(), en_US);
|
vector.z = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||||
return Quaternion.Euler(vector);
|
return Quaternion.Euler(vector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,12 +321,12 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
Rect rect = default;
|
Rect rect = default;
|
||||||
|
|
||||||
var split = input.Split(',');
|
var split = input.Split(' ');
|
||||||
|
|
||||||
rect.x = float.Parse(split[0].Trim(), en_US);
|
rect.x = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||||
rect.y = float.Parse(split[1].Trim(), en_US);
|
rect.y = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||||
rect.width = float.Parse(split[2].Trim(), en_US);
|
rect.width = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||||
rect.height = float.Parse(split[3].Trim(), en_US);
|
rect.height = float.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||||
|
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
@ -351,13 +345,13 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
Color color = default;
|
Color color = default;
|
||||||
|
|
||||||
var split = input.Split(',');
|
var split = input.Split(' ');
|
||||||
|
|
||||||
color.r = float.Parse(split[0].Trim(), en_US);
|
color.r = float.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||||
color.g = float.Parse(split[1].Trim(), en_US);
|
color.g = float.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||||
color.b = float.Parse(split[2].Trim(), en_US);
|
color.b = float.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||||
if (split.Length > 3)
|
if (split.Length > 3)
|
||||||
color.a = float.Parse(split[3].Trim(), en_US);
|
color.a = float.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||||
else
|
else
|
||||||
color.a = 1;
|
color.a = 1;
|
||||||
|
|
||||||
@ -378,13 +372,13 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
Color32 color = default;
|
Color32 color = default;
|
||||||
|
|
||||||
var split = input.Split(',');
|
var split = input.Split(' ');
|
||||||
|
|
||||||
color.r = byte.Parse(split[0].Trim(), en_US);
|
color.r = byte.Parse(split[0].Trim(), CultureInfo.CurrentCulture);
|
||||||
color.g = byte.Parse(split[1].Trim(), en_US);
|
color.g = byte.Parse(split[1].Trim(), CultureInfo.CurrentCulture);
|
||||||
color.b = byte.Parse(split[2].Trim(), en_US);
|
color.b = byte.Parse(split[2].Trim(), CultureInfo.CurrentCulture);
|
||||||
if (split.Length > 3)
|
if (split.Length > 3)
|
||||||
color.a = byte.Parse(split[3].Trim(), en_US);
|
color.a = byte.Parse(split[3].Trim(), CultureInfo.CurrentCulture);
|
||||||
else
|
else
|
||||||
color.a = 255;
|
color.a = 255;
|
||||||
|
|
||||||
@ -397,7 +391,7 @@ namespace UnityExplorer
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
// ints, this is fine
|
// ints, this is fine
|
||||||
return $"{color.r}, {color.g}, {color.b}, {color.a}";
|
return $"{color.r} {color.g} {color.b} {color.a}";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layermask (Int32)
|
// Layermask (Int32)
|
||||||
|
@ -13,7 +13,6 @@ namespace UnityExplorer
|
|||||||
public static class ToStringUtility
|
public static class ToStringUtility
|
||||||
{
|
{
|
||||||
internal static Dictionary<string, MethodInfo> toStringMethods = new Dictionary<string, MethodInfo>();
|
internal static Dictionary<string, MethodInfo> toStringMethods = new Dictionary<string, MethodInfo>();
|
||||||
internal static Dictionary<string, MethodInfo> toStringFormattedMethods = new Dictionary<string, MethodInfo>();
|
|
||||||
|
|
||||||
private const string nullString = "<color=grey>null</color>";
|
private const string nullString = "<color=grey>null</color>";
|
||||||
private const string nullUnknown = nullString + " (?)";
|
private const string nullUnknown = nullString + " (?)";
|
||||||
@ -132,23 +131,13 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
var type = value.GetActualType();
|
var type = value.GetActualType();
|
||||||
|
|
||||||
// Find and cache the relevant ToString method for this Type, if haven't already.
|
// Find and cache the ToString method for this Type, if haven't already.
|
||||||
|
|
||||||
if (!toStringMethods.ContainsKey(type.AssemblyQualifiedName))
|
if (!toStringMethods.ContainsKey(type.AssemblyQualifiedName))
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var formatMethod = type.GetMethod("ToString", ArgumentUtility.ParseArgs);
|
|
||||||
formatMethod.Invoke(value, new object[] { ParseUtility.NUMBER_FORMAT });
|
|
||||||
toStringFormattedMethods.Add(type.AssemblyQualifiedName, formatMethod);
|
|
||||||
toStringMethods.Add(type.AssemblyQualifiedName, null);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
{
|
||||||
var toStringMethod = type.GetMethod("ToString", ArgumentUtility.EmptyTypes);
|
var toStringMethod = type.GetMethod("ToString", ArgumentUtility.EmptyTypes);
|
||||||
toStringMethods.Add(type.AssemblyQualifiedName, toStringMethod);
|
toStringMethods.Add(type.AssemblyQualifiedName, toStringMethod);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke the ToString method on the object
|
// Invoke the ToString method on the object
|
||||||
|
|
||||||
@ -157,9 +146,6 @@ namespace UnityExplorer
|
|||||||
string toString;
|
string toString;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (toStringFormattedMethods.TryGetValue(type.AssemblyQualifiedName, out MethodInfo formatMethod))
|
|
||||||
toString = (string)formatMethod.Invoke(value, new object[] { ParseUtility.NUMBER_FORMAT });
|
|
||||||
else
|
|
||||||
toString = (string)toStringMethods[type.AssemblyQualifiedName].Invoke(value, ArgumentUtility.EmptyArgs);
|
toString = (string)toStringMethods[type.AssemblyQualifiedName].Invoke(value, ArgumentUtility.EmptyArgs);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.UI;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
// Project-wide namespace for accessibility
|
// Project-wide namespace for accessibility
|
||||||
@ -107,5 +109,16 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
return color;
|
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>>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,8 @@ using UnityExplorer.Core.Input;
|
|||||||
using UnityExplorer.Core.Runtime;
|
using UnityExplorer.Core.Runtime;
|
||||||
using UnityExplorer.Tests;
|
using UnityExplorer.Tests;
|
||||||
using UnityExplorer.UI;
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
|
using UnityExplorer.ObjectExplorer;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
|
|
||||||
namespace UnityExplorer
|
namespace UnityExplorer
|
||||||
@ -19,13 +20,15 @@ namespace UnityExplorer
|
|||||||
public static class ExplorerCore
|
public static class ExplorerCore
|
||||||
{
|
{
|
||||||
public const string NAME = "UnityExplorer";
|
public const string NAME = "UnityExplorer";
|
||||||
public const string VERSION = "4.0.2";
|
public const string VERSION = "4.2.0";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
public const string GUID = "com.sinai.unityexplorer";
|
public const string GUID = "com.sinai.unityexplorer";
|
||||||
|
|
||||||
public static IExplorerLoader Loader { get; private set; }
|
public static IExplorerLoader Loader { get; private set; }
|
||||||
public static RuntimeContext Context { get; internal set; }
|
public static RuntimeContext Context { get; internal set; }
|
||||||
|
|
||||||
|
public static HarmonyLib.Harmony Harmony { get; } = new HarmonyLib.Harmony(GUID);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize UnityExplorer with the provided Loader implementation.
|
/// Initialize UnityExplorer with the provided Loader implementation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -46,10 +49,9 @@ namespace UnityExplorer
|
|||||||
Directory.CreateDirectory(Loader.ExplorerFolder);
|
Directory.CreateDirectory(Loader.ExplorerFolder);
|
||||||
|
|
||||||
ConfigManager.Init(Loader.ConfigHandler);
|
ConfigManager.Init(Loader.ConfigHandler);
|
||||||
|
|
||||||
ReflectionUtility.Init();
|
ReflectionUtility.Init();
|
||||||
|
|
||||||
RuntimeProvider.Init();
|
RuntimeProvider.Init();
|
||||||
|
|
||||||
SceneHandler.Init();
|
SceneHandler.Init();
|
||||||
InputManager.Init();
|
InputManager.Init();
|
||||||
|
|
||||||
|
@ -2,19 +2,32 @@
|
|||||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
|
||||||
<Target Name="ILRepacker" AfterTargets="Build">
|
<Target Name="ILRepacker" AfterTargets="Build">
|
||||||
|
<!-- Actual merged assemblies -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<InputAssemblies Include="$(OutputPath)$(AssemblyName).dll" />
|
<InputAssemblies Include="$(OutputPath)$(AssemblyName).dll" />
|
||||||
<InputAssemblies Include="..\lib\mcs-unity\mcs\bin\Release\mcs.dll" />
|
<InputAssemblies Include="..\lib\mcs-unity\mcs\bin\Release\mcs.dll" />
|
||||||
<InputAssemblies Include="packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll" />
|
<InputAssemblies Include="packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- MonoMod for MelonLoader 0.3.0 -->
|
||||||
|
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
|
||||||
|
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.dll" />
|
||||||
|
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Mdb.dll" />
|
||||||
|
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Pdb.dll" />
|
||||||
|
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Rocks.dll" />
|
||||||
|
<InputAssemblies Include="packages\MonoMod.RuntimeDetour.20.1.1.4\lib\net35\MonoMod.RuntimeDetour.dll" />
|
||||||
|
<InputAssemblies Include="packages\MonoMod.Utils.20.1.1.4\lib\net35\MonoMod.Utils.dll" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Required references for ILRepack -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ReferenceFolders Include="..\lib\" />
|
<ReferenceFolders Include="packages\HarmonyX.2.4.2\lib\net35\" />
|
||||||
<ReferenceFolders Include="..\lib\HarmonyX\Harmony\bin\Release\net35\" />
|
|
||||||
<ReferenceFolders Include="..\lib\BepInEx.6.IL2CPP\" />
|
<ReferenceFolders Include="..\lib\BepInEx.6.IL2CPP\" />
|
||||||
<ReferenceFolders Include="..\lib\BepInEx.6.Mono\" />
|
<ReferenceFolders Include="..\lib\BepInEx.6.Mono\" />
|
||||||
<ReferenceFolders Include="..\lib\BepInEx.5\" />
|
<ReferenceFolders Include="..\lib\BepInEx.5\" />
|
||||||
<ReferenceFolders Include="..\lib\MelonLoader\" />
|
<ReferenceFolders Include="..\lib\MelonLoader\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ILRepack
|
<ILRepack
|
||||||
Parallel="true"
|
Parallel="true"
|
||||||
Internalize="true"
|
Internalize="true"
|
||||||
@ -22,7 +35,8 @@
|
|||||||
LibraryPath="@(ReferenceFolders)"
|
LibraryPath="@(ReferenceFolders)"
|
||||||
InputAssemblies="@(InputAssemblies)"
|
InputAssemblies="@(InputAssemblies)"
|
||||||
TargetKind="Dll"
|
TargetKind="Dll"
|
||||||
OutputFile="$(OutputPath)$(AssemblyName).dll" />
|
OutputFile="$(OutputPath)$(AssemblyName).dll"
|
||||||
|
/>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -6,13 +6,13 @@ using System.Text;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
using UnityExplorer.UI;
|
||||||
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Inspectors
|
namespace UnityExplorer.Inspectors
|
||||||
{
|
{
|
||||||
public class GameObjectInspector : InspectorBase
|
public class GameObjectInspector : InspectorBase
|
||||||
{
|
{
|
||||||
@ -64,7 +64,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
addCompInput.Text = "";
|
addCompInput.Text = "";
|
||||||
|
|
||||||
TransformTree.Clear();
|
TransformTree.Clear();
|
||||||
ComponentList.Clear();
|
UpdateComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CloseInspector()
|
public override void CloseInspector()
|
||||||
@ -113,6 +113,9 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
private IEnumerable<GameObject> GetTransformEntries()
|
private IEnumerable<GameObject> GetTransformEntries()
|
||||||
{
|
{
|
||||||
|
if (!GOTarget)
|
||||||
|
return Enumerable.Empty<GameObject>();
|
||||||
|
|
||||||
cachedChildren.Clear();
|
cachedChildren.Clear();
|
||||||
for (int i = 0; i < GOTarget.transform.childCount; i++)
|
for (int i = 0; i < GOTarget.transform.childCount; i++)
|
||||||
cachedChildren.Add(GOTarget.transform.GetChild(i).gameObject);
|
cachedChildren.Add(GOTarget.transform.GetChild(i).gameObject);
|
||||||
@ -125,41 +128,59 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
private readonly List<bool> behaviourEnabledStates = new List<bool>();
|
private readonly List<bool> behaviourEnabledStates = new List<bool>();
|
||||||
|
|
||||||
// ComponentList.GetRootEntriesMethod
|
// ComponentList.GetRootEntriesMethod
|
||||||
private List<Component> GetComponentEntries() => componentEntries;
|
private List<Component> GetComponentEntries() => GOTarget ? componentEntries : Enumerable.Empty<Component>().ToList();
|
||||||
|
|
||||||
public void UpdateComponents()
|
public void UpdateComponents()
|
||||||
{
|
{
|
||||||
|
if (!GOTarget)
|
||||||
|
{
|
||||||
|
componentEntries.Clear();
|
||||||
|
compInstanceIDs.Clear();
|
||||||
|
behaviourEntries.Clear();
|
||||||
|
behaviourEnabledStates.Clear();
|
||||||
|
ComponentList.RefreshData();
|
||||||
|
ComponentList.ScrollPool.Refresh(true, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we actually need to refresh the component cells or not.
|
// Check if we actually need to refresh the component cells or not.
|
||||||
var comps = GOTarget.GetComponents<Component>();
|
var comps = GOTarget.GetComponents<Component>();
|
||||||
var behaviours = GOTarget.GetComponents<Behaviour>();
|
var behaviours = GOTarget.GetComponents<Behaviour>();
|
||||||
|
|
||||||
bool needRefresh = false;
|
bool needRefresh = false;
|
||||||
if (comps.Length != componentEntries.Count || behaviours.Length != behaviourEntries.Count)
|
|
||||||
{
|
int count = 0;
|
||||||
needRefresh = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var comp in comps)
|
foreach (var comp in comps)
|
||||||
{
|
{
|
||||||
|
if (!comp)
|
||||||
|
continue;
|
||||||
|
count++;
|
||||||
if (!compInstanceIDs.Contains(comp.GetInstanceID()))
|
if (!compInstanceIDs.Contains(comp.GetInstanceID()))
|
||||||
{
|
{
|
||||||
needRefresh = true;
|
needRefresh = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needRefresh)
|
if (!needRefresh)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < behaviours.Length; i++)
|
if (count != componentEntries.Count)
|
||||||
|
needRefresh = true;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var behaviour = behaviours[i];
|
count = 0;
|
||||||
if (behaviour.enabled != behaviourEnabledStates[i])
|
foreach (var behaviour in behaviours)
|
||||||
|
{
|
||||||
|
if (!behaviour)
|
||||||
|
continue;
|
||||||
|
if (count >= behaviourEnabledStates.Count || behaviour.enabled != behaviourEnabledStates[count])
|
||||||
{
|
{
|
||||||
needRefresh = true;
|
needRefresh = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
if (!needRefresh && count != behaviourEntries.Count)
|
||||||
|
needRefresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,9 +189,9 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
componentEntries.Clear();
|
componentEntries.Clear();
|
||||||
compInstanceIDs.Clear();
|
compInstanceIDs.Clear();
|
||||||
|
|
||||||
foreach (var comp in comps)
|
foreach (var comp in comps)
|
||||||
{
|
{
|
||||||
|
if (!comp) continue;
|
||||||
componentEntries.Add(comp);
|
componentEntries.Add(comp);
|
||||||
compInstanceIDs.Add(comp.GetInstanceID());
|
compInstanceIDs.Add(comp.GetInstanceID());
|
||||||
}
|
}
|
||||||
@ -179,6 +200,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
behaviourEnabledStates.Clear();
|
behaviourEnabledStates.Clear();
|
||||||
foreach (var behaviour in behaviours)
|
foreach (var behaviour in behaviours)
|
||||||
{
|
{
|
||||||
|
if (!behaviour) continue;
|
||||||
behaviourEntries.Add(behaviour);
|
behaviourEntries.Add(behaviour);
|
||||||
behaviourEnabledStates.Add(behaviour.enabled);
|
behaviourEnabledStates.Add(behaviour.enabled);
|
||||||
}
|
}
|
||||||
@ -198,7 +220,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
private void OnAddComponentClicked(string input)
|
private void OnAddComponentClicked(string input)
|
||||||
{
|
{
|
||||||
if (ReflectionUtility.AllTypes.TryGetValue(input, out Type type))
|
if (ReflectionUtility.GetTypeByName(input) is Type type)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -221,8 +243,8 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
public override GameObject CreateContent(GameObject parent)
|
public override GameObject CreateContent(GameObject parent)
|
||||||
{
|
{
|
||||||
UIRoot = UIFactory.CreateVerticalGroup(Pool<GameObjectInspector>.Instance.InactiveHolder,
|
UIRoot = UIFactory.CreateVerticalGroup(parent, "GameObjectInspector", true, false, true, true, 5,
|
||||||
"GameObjectInspector", true, false, true, true, 5, new Vector4(4, 4, 4, 4), new Color(0.065f, 0.065f, 0.065f));
|
new Vector4(4, 4, 4, 4), new Color(0.065f, 0.065f, 0.065f));
|
||||||
|
|
||||||
var scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out var scrollbar,
|
var scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out var scrollbar,
|
||||||
new Color(0.065f, 0.065f, 0.065f));
|
new Color(0.065f, 0.065f, 0.065f));
|
@ -4,9 +4,10 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Inspectors
|
namespace UnityExplorer.Inspectors
|
||||||
{
|
{
|
||||||
public class ComponentCell : ButtonCell
|
public class ComponentCell : ButtonCell
|
||||||
{
|
{
|
@ -5,7 +5,7 @@ using System.Text;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Inspectors
|
namespace UnityExplorer.Inspectors
|
||||||
{
|
{
|
||||||
public class ComponentList : ButtonListHandler<Component, ComponentCell>
|
public class ComponentList : ButtonListHandler<Component, ComponentCell>
|
||||||
{
|
{
|
||||||
@ -21,7 +21,8 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
this.currentEntries.Clear();
|
RefreshData();
|
||||||
|
ScrollPool.Refresh(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CheckShouldDisplay(Component _, string __) => true;
|
private bool CheckShouldDisplay(Component _, string __) => true;
|
@ -5,8 +5,9 @@ using System.Text;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Inspectors
|
namespace UnityExplorer.Inspectors
|
||||||
{
|
{
|
||||||
public class GameObjectControls
|
public class GameObjectControls
|
||||||
{
|
{
|
||||||
@ -232,6 +233,12 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnExploreButtonClicked()
|
||||||
|
{
|
||||||
|
var panel = UIManager.GetPanel<UI.Panels.ObjectExplorerPanel>(UIManager.Panels.ObjectExplorer);
|
||||||
|
panel.SceneExplorer.JumpToTransform(this.Parent.GOTarget.transform);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnLayerDropdownChanged(int value)
|
private void OnLayerDropdownChanged(int value)
|
||||||
{
|
{
|
||||||
GOTarget.layer = value;
|
GOTarget.layer = value;
|
||||||
@ -462,7 +469,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
//UIFactory.SetLayoutElement(pathApplyBtn.Component.gameObject, minHeight: 25, minWidth: 120);
|
//UIFactory.SetLayoutElement(pathApplyBtn.Component.gameObject, minHeight: 25, minWidth: 120);
|
||||||
//pathApplyBtn.OnClick += () => { OnPathEndEdit(PathInput.Text); };
|
//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
|
// Title and update row
|
||||||
|
|
||||||
@ -478,7 +485,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
NameInput = UIFactory.CreateInputField(titleRow, "NameInput", "untitled");
|
NameInput = UIFactory.CreateInputField(titleRow, "NameInput", "untitled");
|
||||||
UIFactory.SetLayoutElement(NameInput.Component.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999);
|
UIFactory.SetLayoutElement(NameInput.Component.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999);
|
||||||
NameInput.Component.textComponent.fontSize = 15;
|
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)
|
// second row (toggles, instanceID, tag, buttons)
|
||||||
|
|
||||||
@ -515,7 +522,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
TagInput = UIFactory.CreateInputField(secondRow, "TagInput", "none");
|
TagInput = UIFactory.CreateInputField(secondRow, "TagInput", "none");
|
||||||
UIFactory.SetLayoutElement(TagInput.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
|
UIFactory.SetLayoutElement(TagInput.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
|
||||||
TagInput.Component.textComponent.color = Color.white;
|
TagInput.Component.textComponent.color = Color.white;
|
||||||
TagInput.Component.onEndEdit.AddListener((string val) => { OnTagEndEdit(val); });
|
TagInput.Component.GetOnEndEdit().AddListener((string val) => { OnTagEndEdit(val); });
|
||||||
|
|
||||||
// Instantiate
|
// Instantiate
|
||||||
var instantiateBtn = UIFactory.CreateButton(secondRow, "InstantiateBtn", "Instantiate", new Color(0.2f, 0.2f, 0.2f));
|
var instantiateBtn = UIFactory.CreateButton(secondRow, "InstantiateBtn", "Instantiate", new Color(0.2f, 0.2f, 0.2f));
|
||||||
@ -533,6 +540,12 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default);
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default);
|
||||||
UIFactory.SetLayoutElement(thirdrow, minHeight: 25, flexibleWidth: 9999);
|
UIFactory.SetLayoutElement(thirdrow, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
// Inspect in Explorer button
|
||||||
|
var explorerBtn = UIFactory.CreateButton(thirdrow, "ExploreBtn", "Show in Explorer", new Color(0.15f, 0.15f, 0.15f));
|
||||||
|
UIFactory.SetLayoutElement(explorerBtn.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||||
|
explorerBtn.ButtonText.fontSize = 12;
|
||||||
|
explorerBtn.OnClick += OnExploreButtonClicked;
|
||||||
|
|
||||||
// Scene
|
// Scene
|
||||||
var sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey);
|
var sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey);
|
||||||
UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50);
|
UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||||
@ -547,7 +560,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50);
|
UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||||
|
|
||||||
var layerDrop = UIFactory.CreateDropdown(thirdrow, out LayerDropdown, "0", 14, OnLayerDropdownChanged);
|
var layerDrop = UIFactory.CreateDropdown(thirdrow, out LayerDropdown, "0", 14, OnLayerDropdownChanged);
|
||||||
UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 120, flexibleWidth: 999);
|
UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 110, flexibleWidth: 999);
|
||||||
LayerDropdown.captionText.color = SignatureHighlighter.EnumGreen;
|
LayerDropdown.captionText.color = SignatureHighlighter.EnumGreen;
|
||||||
if (layerToNames == null)
|
if (layerToNames == null)
|
||||||
GetLayerNames();
|
GetLayerNames();
|
||||||
@ -632,7 +645,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
var inputField = UIFactory.CreateInputField(rowObj, "InputField", "...");
|
var inputField = UIFactory.CreateInputField(rowObj, "InputField", "...");
|
||||||
UIFactory.SetLayoutElement(inputField.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
|
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);
|
var control = new TransformControl(type, inputField);
|
||||||
|
|
@ -11,7 +11,7 @@ using UnityExplorer.Core.Runtime;
|
|||||||
using UnityExplorer.UI;
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Inspectors
|
namespace UnityExplorer.Inspectors
|
||||||
{
|
{
|
||||||
public enum MouseInspectMode
|
public enum MouseInspectMode
|
||||||
{
|
{
|
||||||
@ -64,12 +64,15 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
internal static Camera MainCamera;
|
internal static Camera MainCamera;
|
||||||
internal static GraphicRaycaster[] graphicRaycasters;
|
internal static GraphicRaycaster[] graphicRaycasters;
|
||||||
|
|
||||||
|
|
||||||
public void StartInspect(MouseInspectMode mode)
|
public void StartInspect(MouseInspectMode mode)
|
||||||
{
|
{
|
||||||
MainCamera = Camera.main;
|
MainCamera = Camera.main;
|
||||||
if (!MainCamera)
|
|
||||||
|
if (!MainCamera && mode == MouseInspectMode.World)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning("No MainCamera found! Cannot inspect world!");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PanelDragger.ForceEnd();
|
PanelDragger.ForceEnd();
|
||||||
|
|
||||||
@ -94,8 +97,14 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
public void StopInspect()
|
public void StopInspect()
|
||||||
{
|
{
|
||||||
Inspecting = false;
|
Inspecting = false;
|
||||||
|
|
||||||
UIManager.NavBarRect.gameObject.SetActive(true);
|
UIManager.NavBarRect.gameObject.SetActive(true);
|
||||||
UIManager.PanelHolder.SetActive(true);
|
UIManager.PanelHolder.SetActive(true);
|
||||||
|
|
||||||
|
var drop = UIManager.MouseInspectDropdown;
|
||||||
|
if (drop.transform.Find("Dropdown List") is Transform list)
|
||||||
|
drop.DestroyDropdownList(list.gameObject);
|
||||||
|
|
||||||
UIRoot.SetActive(false);
|
UIRoot.SetActive(false);
|
||||||
|
|
||||||
if (Mode == MouseInspectMode.UI)
|
if (Mode == MouseInspectMode.UI)
|
@ -4,10 +4,11 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
using UnityExplorer.UI;
|
||||||
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Inspectors
|
namespace UnityExplorer.Inspectors
|
||||||
{
|
{
|
||||||
public abstract class InspectorBase : IPooledObject
|
public abstract class InspectorBase : IPooledObject
|
||||||
{
|
{
|
@ -5,9 +5,9 @@ using System.Text;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI;
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
|
|
||||||
namespace UnityExplorer
|
namespace UnityExplorer
|
@ -4,10 +4,11 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
using UnityExplorer.UI;
|
||||||
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Inspectors
|
namespace UnityExplorer.Inspectors
|
||||||
{
|
{
|
||||||
public class InspectorTab : IPooledObject
|
public class InspectorTab : IPooledObject
|
||||||
{
|
{
|
@ -10,14 +10,13 @@ using UnityEngine;
|
|||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.Core.Runtime;
|
using UnityExplorer.Core.Runtime;
|
||||||
using UnityExplorer.UI.CacheObject;
|
using UnityExplorer.CacheObject;
|
||||||
using UnityExplorer.UI.CacheObject.Views;
|
using UnityExplorer.CacheObject.Views;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
using UnityExplorer.UI;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Inspectors
|
namespace UnityExplorer.Inspectors
|
||||||
{
|
{
|
||||||
public class ReflectionInspector : InspectorBase, ICellPoolDataSource<CacheMemberCell>, ICacheObjectController
|
public class ReflectionInspector : InspectorBase, ICellPoolDataSource<CacheMemberCell>, ICacheObjectController
|
||||||
{
|
{
|
||||||
@ -56,6 +55,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
private readonly Color disabledButtonColor = new Color(0.24f, 0.24f, 0.24f);
|
private readonly Color disabledButtonColor = new Color(0.24f, 0.24f, 0.24f);
|
||||||
private readonly Color enabledButtonColor = new Color(0.2f, 0.27f, 0.2f);
|
private readonly Color enabledButtonColor = new Color(0.2f, 0.27f, 0.2f);
|
||||||
|
|
||||||
private readonly Dictionary<BindingFlags, ButtonRef> scopeFilterButtons = new Dictionary<BindingFlags, ButtonRef>();
|
private readonly Dictionary<BindingFlags, ButtonRef> scopeFilterButtons = new Dictionary<BindingFlags, ButtonRef>();
|
||||||
private readonly List<Toggle> memberTypeToggles = new List<Toggle>();
|
private readonly List<Toggle> memberTypeToggles = new List<Toggle>();
|
||||||
private InputFieldRef filterInputField;
|
private InputFieldRef filterInputField;
|
||||||
@ -75,7 +75,6 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
private IEnumerator InitCoroutine()
|
private IEnumerator InitCoroutine()
|
||||||
{
|
{
|
||||||
yield return null;
|
yield return null;
|
||||||
|
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(InspectorPanel.Instance.ContentRect);
|
LayoutRebuilder.ForceRebuildLayoutImmediate(InspectorPanel.Instance.ContentRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,11 +308,8 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
private void CalculateLayouts()
|
private void CalculateLayouts()
|
||||||
{
|
{
|
||||||
// Calculate sizes
|
LeftGroupWidth = (int)Math.Max(200, (0.4f * InspectorManager.PanelWidth) - 5);
|
||||||
LeftGroupWidth = (int)Math.Max(200, (0.4f * InspectorManager.PanelWidth) - 5);// Math.Min(450f, 0.4f * InspectorManager.PanelWidth - 5));
|
|
||||||
RightGroupWidth = (int)Math.Max(200, InspectorManager.PanelWidth - LeftGroupWidth - 65);
|
RightGroupWidth = (int)Math.Max(200, InspectorManager.PanelWidth - LeftGroupWidth - 65);
|
||||||
|
|
||||||
//memberTitleLayout.minWidth = LeftGroupWidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCellLayout(CacheObjectCell cell)
|
private void SetCellLayout(CacheObjectCell cell)
|
||||||
@ -482,7 +478,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
private void SetUnityTargets()
|
private void SetUnityTargets()
|
||||||
{
|
{
|
||||||
if (!typeof(UnityEngine.Object).IsAssignableFrom(TargetType))
|
if (StaticOnly || !typeof(UnityEngine.Object).IsAssignableFrom(TargetType))
|
||||||
{
|
{
|
||||||
unityObjectRow.SetActive(false);
|
unityObjectRow.SetActive(false);
|
||||||
textureViewer.SetActive(false);
|
textureViewer.SetActive(false);
|
||||||
@ -619,12 +615,15 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
// Actual texture viewer
|
// Actual texture viewer
|
||||||
|
|
||||||
var imageObj = UIFactory.CreateUIObject("TextureViewerImage", textureViewer);
|
var imageViewport = UIFactory.CreateVerticalGroup(textureViewer, "Viewport", false, false, true, true);
|
||||||
textureImage = imageObj.AddComponent<Image>();
|
imageViewport.GetComponent<Image>().color = Color.white;
|
||||||
textureImageLayout = textureImage.gameObject.AddComponent<LayoutElement>();
|
imageViewport.AddComponent<Mask>().showMaskGraphic = false;
|
||||||
|
|
||||||
|
var imageObj = UIFactory.CreateUIObject("Image", imageViewport);
|
||||||
var fitter = imageObj.AddComponent<ContentSizeFitter>();
|
var fitter = imageObj.AddComponent<ContentSizeFitter>();
|
||||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||||
|
textureImage = imageObj.AddComponent<Image>();
|
||||||
|
textureImageLayout = UIFactory.SetLayoutElement(imageObj, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||||
|
|
||||||
textureViewer.SetActive(false);
|
textureViewer.SetActive(false);
|
||||||
}
|
}
|
@ -1,119 +0,0 @@
|
|||||||
#if BIE
|
|
||||||
using BepInEx;
|
|
||||||
using BepInEx.Logging;
|
|
||||||
using HarmonyLib;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using UnityExplorer.Core.Config;
|
|
||||||
using UnityExplorer.Loader.BIE;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityExplorer.Core;
|
|
||||||
using UnityEngine.EventSystems;
|
|
||||||
using UnityExplorer.Core.Input;
|
|
||||||
#if CPP
|
|
||||||
using BepInEx.IL2CPP;
|
|
||||||
using UnhollowerRuntimeLib;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace UnityExplorer
|
|
||||||
{
|
|
||||||
[BepInPlugin(ExplorerCore.GUID, "UnityExplorer", ExplorerCore.VERSION)]
|
|
||||||
|
|
||||||
public class ExplorerBepInPlugin :
|
|
||||||
#if MONO
|
|
||||||
BaseUnityPlugin
|
|
||||||
#else
|
|
||||||
BasePlugin
|
|
||||||
#endif
|
|
||||||
, IExplorerLoader
|
|
||||||
{
|
|
||||||
public static ExplorerBepInPlugin Instance;
|
|
||||||
|
|
||||||
public ManualLogSource LogSource
|
|
||||||
#if MONO
|
|
||||||
=> Logger;
|
|
||||||
#else
|
|
||||||
=> Log;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public ConfigHandler ConfigHandler => _configHandler;
|
|
||||||
private BepInExConfigHandler _configHandler;
|
|
||||||
|
|
||||||
public Harmony HarmonyInstance => s_harmony;
|
|
||||||
private static readonly Harmony s_harmony = new Harmony(ExplorerCore.GUID);
|
|
||||||
|
|
||||||
public string ExplorerFolder => Path.Combine(Paths.PluginPath, ExplorerCore.NAME);
|
|
||||||
public string ConfigFolder => Path.Combine(Paths.ConfigPath, ExplorerCore.NAME);
|
|
||||||
|
|
||||||
public Action<object> OnLogMessage => LogSource.LogMessage;
|
|
||||||
public Action<object> OnLogWarning => LogSource.LogWarning;
|
|
||||||
public Action<object> OnLogError => LogSource.LogError;
|
|
||||||
|
|
||||||
// Init common to Mono and Il2Cpp
|
|
||||||
internal void UniversalInit()
|
|
||||||
{
|
|
||||||
Instance = this;
|
|
||||||
_configHandler = new BepInExConfigHandler();
|
|
||||||
ExplorerCore.Init(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MONO // Mono
|
|
||||||
internal void Awake()
|
|
||||||
{
|
|
||||||
UniversalInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // Il2Cpp
|
|
||||||
public override void Load()
|
|
||||||
{
|
|
||||||
UniversalInit();
|
|
||||||
}
|
|
||||||
#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
|
|
@ -21,11 +21,7 @@ namespace UnityExplorer.Loader.BIE
|
|||||||
|
|
||||||
public override void RegisterConfigElement<T>(ConfigElement<T> config)
|
public override void RegisterConfigElement<T>(ConfigElement<T> config)
|
||||||
{
|
{
|
||||||
object[] tags = null;
|
var entry = Config.Bind(CTG_NAME, config.Name, config.Value, config.Description);
|
||||||
if (config.IsInternal)
|
|
||||||
tags = new[] { "Advanced" };
|
|
||||||
|
|
||||||
var entry = Config.Bind(CTG_NAME, config.Name, config.Value, new ConfigDescription(config.Description, null, tags));
|
|
||||||
|
|
||||||
entry.SettingChanged += (object o, EventArgs e) =>
|
entry.SettingChanged += (object o, EventArgs e) =>
|
||||||
{
|
{
|
75
src/Loader/BepInEx/ExplorerBepInPlugin.cs
Normal file
75
src/Loader/BepInEx/ExplorerBepInPlugin.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#if BIE
|
||||||
|
using BepInEx;
|
||||||
|
using BepInEx.Logging;
|
||||||
|
using HarmonyLib;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
using UnityExplorer.Core;
|
||||||
|
using UnityExplorer.Core.Config;
|
||||||
|
using UnityExplorer.Core.Input;
|
||||||
|
using UnityExplorer.Loader.BIE;
|
||||||
|
#if CPP
|
||||||
|
using BepInEx.IL2CPP;
|
||||||
|
using UnhollowerRuntimeLib;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace UnityExplorer
|
||||||
|
{
|
||||||
|
[BepInPlugin(ExplorerCore.GUID, "UnityExplorer", ExplorerCore.VERSION)]
|
||||||
|
|
||||||
|
public class ExplorerBepInPlugin :
|
||||||
|
#if MONO
|
||||||
|
BaseUnityPlugin
|
||||||
|
#else
|
||||||
|
BasePlugin
|
||||||
|
#endif
|
||||||
|
, IExplorerLoader
|
||||||
|
{
|
||||||
|
public static ExplorerBepInPlugin Instance;
|
||||||
|
|
||||||
|
public ManualLogSource LogSource
|
||||||
|
#if MONO
|
||||||
|
=> Logger;
|
||||||
|
#else
|
||||||
|
=> Log;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public ConfigHandler ConfigHandler => _configHandler;
|
||||||
|
private BepInExConfigHandler _configHandler;
|
||||||
|
|
||||||
|
public Harmony HarmonyInstance => s_harmony;
|
||||||
|
private static readonly Harmony s_harmony = new Harmony(ExplorerCore.GUID);
|
||||||
|
|
||||||
|
public string ExplorerFolder => Path.Combine(Paths.PluginPath, ExplorerCore.NAME);
|
||||||
|
|
||||||
|
public Action<object> OnLogMessage => LogSource.LogMessage;
|
||||||
|
public Action<object> OnLogWarning => LogSource.LogWarning;
|
||||||
|
public Action<object> OnLogError => LogSource.LogError;
|
||||||
|
|
||||||
|
private void Init()
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
_configHandler = new BepInExConfigHandler();
|
||||||
|
ExplorerCore.Init(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MONO // Mono
|
||||||
|
internal void Awake()
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // Il2Cpp
|
||||||
|
public override void Load()
|
||||||
|
{
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -10,13 +10,10 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
string ExplorerFolder { get; }
|
string ExplorerFolder { get; }
|
||||||
|
|
||||||
string ConfigFolder { get; }
|
|
||||||
ConfigHandler ConfigHandler { get; }
|
ConfigHandler ConfigHandler { get; }
|
||||||
|
|
||||||
Action<object> OnLogMessage { get; }
|
Action<object> OnLogMessage { get; }
|
||||||
Action<object> OnLogWarning { get; }
|
Action<object> OnLogWarning { get; }
|
||||||
Action<object> OnLogError { get; }
|
Action<object> OnLogError { get; }
|
||||||
|
|
||||||
void SetupCursorPatches();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,79 +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;
|
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
|
|
||||||
[assembly: MelonGame(null, null)]
|
|
||||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
|
|
||||||
[assembly: MelonColor(ConsoleColor.DarkCyan)]
|
|
||||||
|
|
||||||
namespace UnityExplorer
|
|
||||||
{
|
|
||||||
public class ExplorerMelonMod : MelonMod, IExplorerLoader
|
|
||||||
{
|
|
||||||
public static ExplorerMelonMod Instance;
|
|
||||||
|
|
||||||
public string ExplorerFolder => Path.Combine("Mods", ExplorerCore.NAME);
|
|
||||||
public string ConfigFolder => ExplorerFolder;
|
|
||||||
|
|
||||||
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);
|
|
||||||
HarmonyInstance.Patch(prop.GetSetMethod(), prefix: prefix);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
ExplorerCore.Log($"Unable to patch {type.Name}.set_{property}: {e.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
43
src/Loader/MelonLoader/ExplorerMelonMod.cs
Normal file
43
src/Loader/MelonLoader/ExplorerMelonMod.cs
Normal 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
|
@ -1,4 +1,4 @@
|
|||||||
#if ML
|
#if ML
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -74,5 +74,4 @@ namespace UnityExplorer.Loader.ML
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -21,8 +21,7 @@ namespace UnityExplorer
|
|||||||
/// Call this to initialize UnityExplorer without adding a log listener.
|
/// Call this to initialize UnityExplorer without adding a log listener.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The new (or active, if one exists) instance of ExplorerStandalone.</returns>
|
/// <returns>The new (or active, if one exists) instance of ExplorerStandalone.</returns>
|
||||||
public static ExplorerStandalone CreateInstance()
|
public static ExplorerStandalone CreateInstance() => CreateInstance(null);
|
||||||
=> CreateInstance(null);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Call this to initialize UnityExplorer and add a listener for UnityExplorer's log messages.
|
/// Call this to initialize UnityExplorer and add a listener for UnityExplorer's log messages.
|
||||||
@ -34,6 +33,7 @@ namespace UnityExplorer
|
|||||||
if (Instance != null)
|
if (Instance != null)
|
||||||
return Instance;
|
return Instance;
|
||||||
|
|
||||||
|
if (logListener != null)
|
||||||
OnLog += logListener;
|
OnLog += logListener;
|
||||||
|
|
||||||
var instance = new ExplorerStandalone();
|
var instance = new ExplorerStandalone();
|
||||||
@ -48,9 +48,6 @@ namespace UnityExplorer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static event Action<string, LogType> OnLog;
|
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;
|
public ConfigHandler ConfigHandler => _configHandler;
|
||||||
private StandaloneConfigHandler _configHandler;
|
private StandaloneConfigHandler _configHandler;
|
||||||
|
|
||||||
@ -58,26 +55,12 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (s_explorerFolder == null)
|
CheckExplorerFolder();
|
||||||
{
|
|
||||||
s_explorerFolder =
|
|
||||||
Path.Combine(
|
|
||||||
Path.GetDirectoryName(
|
|
||||||
Uri.UnescapeDataString(new Uri(Assembly.GetExecutingAssembly().CodeBase)
|
|
||||||
.AbsolutePath)),
|
|
||||||
"UnityExplorer");
|
|
||||||
|
|
||||||
if (!Directory.Exists(s_explorerFolder))
|
|
||||||
Directory.CreateDirectory(s_explorerFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
return s_explorerFolder;
|
return s_explorerFolder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static string s_explorerFolder;
|
private static string s_explorerFolder;
|
||||||
|
|
||||||
public string ConfigFolder => ExplorerFolder;
|
|
||||||
|
|
||||||
Action<object> IExplorerLoader.OnLogMessage => (object log) => { OnLog?.Invoke(log?.ToString() ?? "", LogType.Log); };
|
Action<object> IExplorerLoader.OnLogMessage => (object log) => { OnLog?.Invoke(log?.ToString() ?? "", LogType.Log); };
|
||||||
Action<object> IExplorerLoader.OnLogWarning => (object log) => { OnLog?.Invoke(log?.ToString() ?? "", LogType.Warning); };
|
Action<object> IExplorerLoader.OnLogWarning => (object log) => { OnLog?.Invoke(log?.ToString() ?? "", LogType.Warning); };
|
||||||
Action<object> IExplorerLoader.OnLogError => (object log) => { OnLog?.Invoke(log?.ToString() ?? "", LogType.Error); };
|
Action<object> IExplorerLoader.OnLogError => (object log) => { OnLog?.Invoke(log?.ToString() ?? "", LogType.Error); };
|
||||||
@ -90,45 +73,18 @@ namespace UnityExplorer
|
|||||||
ExplorerCore.Init(this);
|
ExplorerCore.Init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetupCursorPatches()
|
private void CheckExplorerFolder()
|
||||||
{
|
{
|
||||||
try
|
if (s_explorerFolder == null)
|
||||||
{
|
{
|
||||||
this.HarmonyInstance.PatchAll();
|
s_explorerFolder =
|
||||||
}
|
Path.Combine(
|
||||||
catch (Exception ex)
|
Path.GetDirectoryName(
|
||||||
{
|
Uri.UnescapeDataString(new Uri(Assembly.GetExecutingAssembly().CodeBase).AbsolutePath)),
|
||||||
ExplorerCore.Log($"Exception setting up Harmony patches:\r\n{ex.ReflectionExToString()}");
|
"UnityExplorer");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(EventSystem), "current", MethodType.Setter)]
|
if (!Directory.Exists(s_explorerFolder))
|
||||||
public class PATCH_EventSystem_current
|
Directory.CreateDirectory(s_explorerFolder);
|
||||||
{
|
|
||||||
[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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,11 +13,11 @@ namespace UnityExplorer.Loader.STANDALONE
|
|||||||
public class StandaloneConfigHandler : ConfigHandler
|
public class StandaloneConfigHandler : ConfigHandler
|
||||||
{
|
{
|
||||||
internal static IniDataParser _parser;
|
internal static IniDataParser _parser;
|
||||||
internal static string INI_PATH;
|
internal static string CONFIG_PATH;
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
INI_PATH = Path.Combine(ExplorerCore.Loader.ConfigFolder, "config.ini");
|
CONFIG_PATH = Path.Combine(ExplorerCore.Loader.ExplorerFolder, "config.ini");
|
||||||
_parser = new IniDataParser();
|
_parser = new IniDataParser();
|
||||||
_parser.Configuration.CommentString = "#";
|
_parser.Configuration.CommentString = "#";
|
||||||
}
|
}
|
||||||
@ -49,10 +49,10 @@ namespace UnityExplorer.Loader.STANDALONE
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!File.Exists(INI_PATH))
|
if (!File.Exists(CONFIG_PATH))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
string ini = File.ReadAllText(INI_PATH);
|
string ini = File.ReadAllText(CONFIG_PATH);
|
||||||
|
|
||||||
var data = _parser.Parse(ini);
|
var data = _parser.Parse(ini);
|
||||||
|
|
||||||
@ -97,10 +97,10 @@ namespace UnityExplorer.Loader.STANDALONE
|
|||||||
foreach (var entry in ConfigManager.ConfigElements)
|
foreach (var entry in ConfigManager.ConfigElements)
|
||||||
sec.AddKey(entry.Key, entry.Value.BoxedValue.ToString());
|
sec.AddKey(entry.Key, entry.Value.BoxedValue.ToString());
|
||||||
|
|
||||||
if (!Directory.Exists(ExplorerCore.Loader.ConfigFolder))
|
if (!Directory.Exists(ExplorerCore.Loader.ExplorerFolder))
|
||||||
Directory.CreateDirectory(ExplorerCore.Loader.ConfigFolder);
|
Directory.CreateDirectory(ExplorerCore.Loader.ExplorerFolder);
|
||||||
|
|
||||||
File.WriteAllText(INI_PATH, data.ToString());
|
File.WriteAllText(CONFIG_PATH, data.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,15 +4,13 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Models;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.ObjectExplorer
|
namespace UnityExplorer.ObjectExplorer
|
||||||
{
|
{
|
||||||
public class ObjectSearch : UIModel
|
public class ObjectSearch : UIModel
|
||||||
{
|
{
|
||||||
@ -55,8 +53,8 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
|
|
||||||
if (m_context == SearchContext.Singleton)
|
if (m_context == SearchContext.Singleton)
|
||||||
currentResults = SearchProvider.SingletonSearch(nameInputField.Text);
|
currentResults = SearchProvider.SingletonSearch(nameInputField.Text);
|
||||||
else if (m_context == SearchContext.StaticClass)
|
else if (m_context == SearchContext.Class)
|
||||||
currentResults = SearchProvider.StaticClassSearch(nameInputField.Text);
|
currentResults = SearchProvider.ClassSearch(nameInputField.Text);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string compType = "";
|
string compType = "";
|
||||||
@ -79,7 +77,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
lastCheckedTypeInput = desiredTypeInput;
|
lastCheckedTypeInput = desiredTypeInput;
|
||||||
|
|
||||||
//var type = ReflectionUtility.GetTypeByName(desiredTypeInput);
|
//var type = ReflectionUtility.GetTypeByName(desiredTypeInput);
|
||||||
if (ReflectionUtility.AllTypes.TryGetValue(desiredTypeInput, out var cachedType))
|
if (ReflectionUtility.GetTypeByName(desiredTypeInput) is Type cachedType)
|
||||||
{
|
{
|
||||||
var type = cachedType;
|
var type = cachedType;
|
||||||
lastTypeCanHaveGO = typeof(Component).IsAssignableFrom(type) || type == typeof(GameObject);
|
lastTypeCanHaveGO = typeof(Component).IsAssignableFrom(type) || type == typeof(GameObject);
|
||||||
@ -132,8 +130,11 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
if (!cachedCellTexts.ContainsKey(index))
|
if (!cachedCellTexts.ContainsKey(index))
|
||||||
{
|
{
|
||||||
string text;
|
string text;
|
||||||
if (m_context == SearchContext.StaticClass)
|
if (m_context == SearchContext.Class)
|
||||||
text = SignatureHighlighter.Parse(currentResults[index] as Type, true);
|
{
|
||||||
|
var type = currentResults[index] as Type;
|
||||||
|
text = $"{SignatureHighlighter.Parse(type, true)} <color=grey><i>({type.Assembly.GetName().Name})</i></color>";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
text = ToStringUtility.ToStringWithType(currentResults[index], currentResults[index]?.GetActualType());
|
text = ToStringUtility.ToStringWithType(currentResults[index], currentResults[index]?.GetActualType());
|
||||||
|
|
||||||
@ -145,7 +146,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
|
|
||||||
private void OnCellClicked(int dataIndex)
|
private void OnCellClicked(int dataIndex)
|
||||||
{
|
{
|
||||||
if (m_context == SearchContext.StaticClass)
|
if (m_context == SearchContext.Class)
|
||||||
InspectorManager.Inspect(currentResults[dataIndex] as Type);
|
InspectorManager.Inspect(currentResults[dataIndex] as Type);
|
||||||
else
|
else
|
||||||
InspectorManager.Inspect(currentResults[dataIndex]);
|
InspectorManager.Inspect(currentResults[dataIndex]);
|
@ -8,11 +8,12 @@ using UnityEngine;
|
|||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core;
|
using UnityExplorer.Core;
|
||||||
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.Models;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.ObjectExplorer
|
namespace UnityExplorer.ObjectExplorer
|
||||||
{
|
{
|
||||||
public class SceneExplorer : UIModel
|
public class SceneExplorer : UIModel
|
||||||
{
|
{
|
||||||
@ -39,7 +40,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
|
|
||||||
private GameObject refreshRow;
|
private GameObject refreshRow;
|
||||||
private Dropdown sceneDropdown;
|
private Dropdown sceneDropdown;
|
||||||
private readonly Dictionary<int, Dropdown.OptionData> sceneToDropdownOption = new Dictionary<int, Dropdown.OptionData>();
|
private readonly Dictionary<Scene, Dropdown.OptionData> sceneToDropdownOption = new Dictionary<Scene, Dropdown.OptionData>();
|
||||||
|
|
||||||
private IEnumerable<GameObject> GetRootEntries() => SceneHandler.CurrentRootObjects;
|
private IEnumerable<GameObject> GetRootEntries() => SceneHandler.CurrentRootObjects;
|
||||||
|
|
||||||
@ -58,6 +59,26 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
Tree.RefreshData(true);
|
Tree.RefreshData(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void JumpToTransform(Transform transform)
|
||||||
|
{
|
||||||
|
if (!transform)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UIManager.SetPanelActive(this.Parent, true);
|
||||||
|
this.Parent.SetTab(0);
|
||||||
|
|
||||||
|
// select the transform's scene
|
||||||
|
var go = transform.gameObject;
|
||||||
|
if (SceneHandler.SelectedScene != go.scene)
|
||||||
|
{
|
||||||
|
int idx = sceneDropdown.options.IndexOf(sceneToDropdownOption[go.scene]);
|
||||||
|
sceneDropdown.value = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let the TransformTree handle the rest
|
||||||
|
Tree.JumpAndExpandToTransform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnDropdownChanged(int value)
|
private void OnDropdownChanged(int value)
|
||||||
{
|
{
|
||||||
if (value < 0 || SceneHandler.LoadedScenes.Count <= value)
|
if (value < 0 || SceneHandler.LoadedScenes.Count <= value)
|
||||||
@ -71,12 +92,12 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
|
|
||||||
private void SceneHandler_OnInspectedSceneChanged(Scene scene)
|
private void SceneHandler_OnInspectedSceneChanged(Scene scene)
|
||||||
{
|
{
|
||||||
if (!sceneToDropdownOption.ContainsKey(scene.handle))
|
if (!sceneToDropdownOption.ContainsKey(scene))
|
||||||
PopulateSceneDropdown();
|
PopulateSceneDropdown();
|
||||||
|
|
||||||
if (sceneToDropdownOption.ContainsKey(scene.handle))
|
if (sceneToDropdownOption.ContainsKey(scene))
|
||||||
{
|
{
|
||||||
var opt = sceneToDropdownOption[scene.handle];
|
var opt = sceneToDropdownOption[scene];
|
||||||
int idx = sceneDropdown.options.IndexOf(opt);
|
int idx = sceneDropdown.options.IndexOf(opt);
|
||||||
if (sceneDropdown.value != idx)
|
if (sceneDropdown.value != idx)
|
||||||
sceneDropdown.value = idx;
|
sceneDropdown.value = idx;
|
||||||
@ -93,7 +114,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
refreshRow.SetActive(!scene.IsValid());
|
refreshRow.SetActive(!scene.IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SceneHandler_OnLoadedScenesChanged(ReadOnlyCollection<Scene> loadedScenes)
|
private void SceneHandler_OnLoadedScenesChanged(List<Scene> loadedScenes)
|
||||||
{
|
{
|
||||||
PopulateSceneDropdown();
|
PopulateSceneDropdown();
|
||||||
}
|
}
|
||||||
@ -105,6 +126,9 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
|
|
||||||
foreach (var scene in SceneHandler.LoadedScenes)
|
foreach (var scene in SceneHandler.LoadedScenes)
|
||||||
{
|
{
|
||||||
|
if (sceneToDropdownOption.ContainsKey(scene))
|
||||||
|
continue;
|
||||||
|
|
||||||
string name = scene.name?.Trim();
|
string name = scene.name?.Trim();
|
||||||
|
|
||||||
if (!scene.IsValid())
|
if (!scene.IsValid())
|
||||||
@ -114,7 +138,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
|
|
||||||
var option = new Dropdown.OptionData(name);
|
var option = new Dropdown.OptionData(name);
|
||||||
sceneDropdown.options.Add(option);
|
sceneDropdown.options.Add(option);
|
||||||
sceneToDropdownOption.Add(scene.handle, option);
|
sceneToDropdownOption.Add(scene, option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +146,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
{
|
{
|
||||||
if ((!string.IsNullOrEmpty(input) && !Tree.Filtering) || (string.IsNullOrEmpty(input) && Tree.Filtering))
|
if ((!string.IsNullOrEmpty(input) && !Tree.Filtering) || (string.IsNullOrEmpty(input) && Tree.Filtering))
|
||||||
{
|
{
|
||||||
Tree.displayedObjects.Clear();
|
Tree.cachedTransforms.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Tree.CurrentFilter = input;
|
Tree.CurrentFilter = input;
|
@ -6,7 +6,7 @@ using System.Text;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
|
|
||||||
namespace UnityExplorer.Core
|
namespace UnityExplorer.ObjectExplorer
|
||||||
{
|
{
|
||||||
public static class SceneHandler
|
public static class SceneHandler
|
||||||
{
|
{
|
||||||
@ -15,28 +15,27 @@ namespace UnityExplorer.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static Scene? SelectedScene
|
public static Scene? SelectedScene
|
||||||
{
|
{
|
||||||
get => m_selectedScene;
|
get => selectedScene;
|
||||||
internal set
|
internal set
|
||||||
{
|
{
|
||||||
if (m_selectedScene != null && m_selectedScene?.handle == value?.handle)
|
if (selectedScene != null && selectedScene == value)
|
||||||
return;
|
return;
|
||||||
m_selectedScene = value;
|
selectedScene = value;
|
||||||
OnInspectedSceneChanged?.Invoke((Scene)m_selectedScene);
|
OnInspectedSceneChanged?.Invoke((Scene)selectedScene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static Scene? m_selectedScene;
|
private static Scene? selectedScene;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The GameObjects in the currently inspected scene.
|
/// The GameObjects in the currently inspected scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ReadOnlyCollection<GameObject> CurrentRootObjects => new ReadOnlyCollection<GameObject>(rootObjects);
|
public static GameObject[] CurrentRootObjects { get; private set; } = new GameObject[0];
|
||||||
private static GameObject[] rootObjects = new GameObject[0];
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All currently loaded Scenes.
|
/// All currently loaded Scenes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ReadOnlyCollection<Scene> LoadedScenes => new ReadOnlyCollection<Scene>(allLoadedScenes);
|
public static List<Scene> LoadedScenes { get; private set; } = new List<Scene>();
|
||||||
private static readonly List<Scene> allLoadedScenes = new List<Scene>();
|
private static HashSet<Scene> previousLoadedScenes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The names of all scenes in the build settings, if they could be retrieved.
|
/// The names of all scenes in the build settings, if they could be retrieved.
|
||||||
@ -58,10 +57,10 @@ namespace UnityExplorer.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked whenever the list of currently loaded Scenes changes. The argument contains all loaded scenes after the change.
|
/// Invoked whenever the list of currently loaded Scenes changes. The argument contains all loaded scenes after the change.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static event Action<ReadOnlyCollection<Scene>> OnLoadedScenesChanged;
|
public static event Action<List<Scene>> OnLoadedScenesChanged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Equivalent to <see cref="SceneManager.sceneCount"/> + 2, to include 'DontDestroyOnLoad'.
|
/// Equivalent to <see cref="SceneManager.sceneCount"/> + 2, to include 'DontDestroyOnLoad' and the 'None' scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static int LoadedSceneCount => SceneManager.sceneCount + 2;
|
public static int LoadedSceneCount => SceneManager.sceneCount + 2;
|
||||||
|
|
||||||
@ -82,25 +81,7 @@ namespace UnityExplorer.Core
|
|||||||
}
|
}
|
||||||
private static GameObject dontDestroyObject;
|
private static GameObject dontDestroyObject;
|
||||||
|
|
||||||
public static bool InspectingAssetScene => SelectedScene == AssetScene;
|
public static bool InspectingAssetScene => SelectedScene.HasValue && SelectedScene.Value == default;
|
||||||
|
|
||||||
internal static Scene AssetScene => AssetObject.scene;
|
|
||||||
internal static int AssetHandle => AssetScene.handle;
|
|
||||||
|
|
||||||
internal static GameObject AssetObject
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (!assetObject)
|
|
||||||
{
|
|
||||||
assetObject = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GameObject))
|
|
||||||
.First(it => !it.TryCast<GameObject>().scene.IsValid())
|
|
||||||
.TryCast<GameObject>();
|
|
||||||
}
|
|
||||||
return assetObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static GameObject assetObject;
|
|
||||||
|
|
||||||
internal static void Init()
|
internal static void Init()
|
||||||
{
|
{
|
||||||
@ -122,73 +103,63 @@ namespace UnityExplorer.Core
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
gotAllScenesInBuild = false;
|
gotAllScenesInBuild = false;
|
||||||
ExplorerCore.Log($"Unable to generate list of all Scenes in the build: {ex}");
|
ExplorerCore.LogWarning($"Unable to generate list of all Scenes in the build: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Update()
|
internal static void Update()
|
||||||
{
|
{
|
||||||
int curHandle = SelectedScene?.handle ?? -1;
|
// check if the loaded scenes changed. always confirm DontDestroy / HideAndDontSave
|
||||||
// DontDestroyOnLoad always exists, so default to true if our curHandle is that handle.
|
int confirmedCount = 2;
|
||||||
// otherwise we will check while iterating.
|
bool inspectedExists = SelectedScene == DontDestroyScene || (SelectedScene.HasValue && SelectedScene.Value == default);
|
||||||
bool inspectedExists = curHandle == DontDestroyHandle || curHandle == AssetHandle;
|
|
||||||
|
|
||||||
// Quick sanity check if the loaded scenes changed
|
LoadedScenes.Clear();
|
||||||
bool anyChange = LoadedSceneCount != allLoadedScenes.Count;
|
|
||||||
// otherwise keep a lookup table of the previous handles to check if the list changed at all.
|
|
||||||
HashSet<int> previousHandles = null;
|
|
||||||
if (!anyChange)
|
|
||||||
previousHandles = new HashSet<int>(allLoadedScenes.Select(it => it.handle));
|
|
||||||
|
|
||||||
allLoadedScenes.Clear();
|
|
||||||
|
|
||||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||||
{
|
{
|
||||||
Scene scene = SceneManager.GetSceneAt(i);
|
Scene scene = SceneManager.GetSceneAt(i);
|
||||||
if (scene == default || scene.handle == -1 || !scene.isLoaded)
|
if (scene == default || !scene.isLoaded)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// If no changes yet, ensure the previous list contained this handle.
|
// If no changes yet, ensure the previous list contained the scene
|
||||||
if (!anyChange && !previousHandles.Contains(scene.handle))
|
if (previousLoadedScenes != null && previousLoadedScenes.Contains(scene))
|
||||||
anyChange = true;
|
confirmedCount++;
|
||||||
|
|
||||||
// If we have not yet confirmed inspectedExists, check if this scene is our currently inspected one.
|
// If we have not yet confirmed inspectedExists, check if this scene is our currently inspected one.
|
||||||
if (curHandle != -1 && !inspectedExists && scene.handle == curHandle)
|
if (!inspectedExists && scene == SelectedScene)
|
||||||
inspectedExists = true;
|
inspectedExists = true;
|
||||||
|
|
||||||
allLoadedScenes.Add(scene);
|
LoadedScenes.Add(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always add the DontDestroyOnLoad scene and the "none" scene.
|
bool anyChange = confirmedCount != LoadedScenes.Count;
|
||||||
allLoadedScenes.Add(DontDestroyScene);
|
|
||||||
allLoadedScenes.Add(AssetScene);
|
LoadedScenes.Add(DontDestroyScene);
|
||||||
|
LoadedScenes.Add(default);
|
||||||
|
previousLoadedScenes = new HashSet<Scene>(LoadedScenes);
|
||||||
|
|
||||||
// Default to first scene if none selected or previous selection no longer exists.
|
// Default to first scene if none selected or previous selection no longer exists.
|
||||||
if (!inspectedExists)
|
if (!inspectedExists)
|
||||||
{
|
SelectedScene = LoadedScenes.First();
|
||||||
SelectedScene = allLoadedScenes.First();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify on the list changing at all
|
// Notify on the list changing at all
|
||||||
if (anyChange)
|
if (anyChange)
|
||||||
{
|
|
||||||
OnLoadedScenesChanged?.Invoke(LoadedScenes);
|
OnLoadedScenesChanged?.Invoke(LoadedScenes);
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, update the root objects list.
|
// Finally, update the root objects list.
|
||||||
if (SelectedScene != null && ((Scene)SelectedScene).IsValid())
|
if (SelectedScene != null && ((Scene)SelectedScene).IsValid())
|
||||||
rootObjects = RuntimeProvider.Instance.GetRootGameObjects((Scene)SelectedScene);
|
CurrentRootObjects = RuntimeProvider.Instance.GetRootGameObjects((Scene)SelectedScene);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GameObject));
|
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GameObject));
|
||||||
var list = new List<GameObject>();
|
var objects = new List<GameObject>();
|
||||||
foreach (var obj in allObjects)
|
foreach (var obj in allObjects)
|
||||||
{
|
{
|
||||||
var go = obj.TryCast<GameObject>();
|
var go = obj.TryCast<GameObject>();
|
||||||
if (go.transform.parent == null && !go.scene.IsValid())
|
if (go.transform.parent == null && !go.scene.IsValid())
|
||||||
list.Add(go);
|
objects.Add(go);
|
||||||
}
|
}
|
||||||
rootObjects = list.ToArray();
|
CurrentRootObjects = objects.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,14 +8,13 @@ using UnityEngine.SceneManagement;
|
|||||||
using UnityExplorer.Core;
|
using UnityExplorer.Core;
|
||||||
using UnityExplorer.Core.Runtime;
|
using UnityExplorer.Core.Runtime;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.ObjectExplorer
|
namespace UnityExplorer.ObjectExplorer
|
||||||
{
|
{
|
||||||
public enum SearchContext
|
public enum SearchContext
|
||||||
{
|
{
|
||||||
UnityObject,
|
UnityObject,
|
||||||
// GameObject,
|
|
||||||
Singleton,
|
Singleton,
|
||||||
StaticClass
|
Class
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ChildFilter
|
public enum ChildFilter
|
||||||
@ -45,9 +44,9 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
case SceneFilter.DontDestroyOnLoad:
|
case SceneFilter.DontDestroyOnLoad:
|
||||||
return scene == SceneHandler.DontDestroyScene;
|
return scene == SceneHandler.DontDestroyScene;
|
||||||
case SceneFilter.HideAndDontSave:
|
case SceneFilter.HideAndDontSave:
|
||||||
return scene == SceneHandler.AssetScene;
|
return scene == default;
|
||||||
case SceneFilter.ActivelyLoaded:
|
case SceneFilter.ActivelyLoaded:
|
||||||
return scene != SceneHandler.DontDestroyScene && scene != SceneHandler.AssetScene;
|
return scene != SceneHandler.DontDestroyScene && scene != default;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -58,25 +57,13 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
{
|
{
|
||||||
var results = new List<object>();
|
var results = new List<object>();
|
||||||
|
|
||||||
Type searchType;
|
Type searchType = null;
|
||||||
switch (context)
|
|
||||||
{
|
|
||||||
//case SearchContext.GameObject:
|
|
||||||
// searchType = typeof(GameObject);
|
|
||||||
// break;
|
|
||||||
|
|
||||||
case SearchContext.UnityObject:
|
|
||||||
default:
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(customTypeInput))
|
if (!string.IsNullOrEmpty(customTypeInput))
|
||||||
{
|
{
|
||||||
if (ReflectionUtility.GetTypeByName(customTypeInput) is Type customType)
|
if (ReflectionUtility.GetTypeByName(customTypeInput) is Type customType)
|
||||||
{
|
{
|
||||||
if (typeof(UnityEngine.Object).IsAssignableFrom(customType))
|
if (typeof(UnityEngine.Object).IsAssignableFrom(customType))
|
||||||
{
|
|
||||||
searchType = customType;
|
searchType = customType;
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
ExplorerCore.LogWarning($"Custom type '{customType.FullName}' is not assignable from UnityEngine.Object!");
|
ExplorerCore.LogWarning($"Custom type '{customType.FullName}' is not assignable from UnityEngine.Object!");
|
||||||
}
|
}
|
||||||
@ -84,13 +71,8 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
ExplorerCore.LogWarning($"Could not find any type by name '{customTypeInput}'!");
|
ExplorerCore.LogWarning($"Could not find any type by name '{customTypeInput}'!");
|
||||||
}
|
}
|
||||||
|
|
||||||
searchType = typeof(UnityEngine.Object);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (searchType == null)
|
if (searchType == null)
|
||||||
return results;
|
searchType = typeof(UnityEngine.Object);
|
||||||
|
|
||||||
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(searchType);
|
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(searchType);
|
||||||
|
|
||||||
@ -100,7 +82,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
if (!string.IsNullOrEmpty(input))
|
if (!string.IsNullOrEmpty(input))
|
||||||
nameFilter = input;
|
nameFilter = input;
|
||||||
|
|
||||||
bool canGetGameObject = searchType == typeof(GameObject) || typeof(Component).IsAssignableFrom(searchType);
|
bool shouldFilterGOs = searchType == typeof(GameObject) || typeof(Component).IsAssignableFrom(searchType);
|
||||||
|
|
||||||
foreach (var obj in allObjects)
|
foreach (var obj in allObjects)
|
||||||
{
|
{
|
||||||
@ -108,13 +90,21 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
if (!string.IsNullOrEmpty(nameFilter) && !obj.name.ContainsIgnoreCase(nameFilter))
|
if (!string.IsNullOrEmpty(nameFilter) && !obj.name.ContainsIgnoreCase(nameFilter))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (canGetGameObject)
|
GameObject go = null;
|
||||||
{
|
var type = obj.GetActualType();
|
||||||
var go = searchType == typeof(GameObject)
|
|
||||||
? obj.TryCast<GameObject>()
|
if (type == typeof(GameObject))
|
||||||
: obj.TryCast<Component>().gameObject;
|
go = obj.TryCast<GameObject>();
|
||||||
|
else if (typeof(Component).IsAssignableFrom(type))
|
||||||
|
go = obj.TryCast<Component>()?.gameObject;
|
||||||
|
|
||||||
if (go)
|
if (go)
|
||||||
|
{
|
||||||
|
// hide unityexplorer objects
|
||||||
|
if (go.transform.root.name == "ExplorerCanvas")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (shouldFilterGOs)
|
||||||
{
|
{
|
||||||
// scene check
|
// scene check
|
||||||
if (sceneFilter != SceneFilter.Any)
|
if (sceneFilter != SceneFilter.Any)
|
||||||
@ -143,7 +133,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<object> StaticClassSearch(string input)
|
internal static List<object> ClassSearch(string input)
|
||||||
{
|
{
|
||||||
var list = new List<object>();
|
var list = new List<object>();
|
||||||
|
|
||||||
@ -153,11 +143,10 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
|
|
||||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
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))
|
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ContainsIgnoreCase(nameFilter))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
list.Add(type);
|
list.Add(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/Resources/legacy.5.6.bundle
Normal file
BIN
src/Resources/legacy.5.6.bundle
Normal file
Binary file not shown.
BIN
src/Resources/legacy.bundle
Normal file
BIN
src/Resources/legacy.bundle
Normal file
Binary file not shown.
BIN
src/Resources/modern.bundle
Normal file
BIN
src/Resources/modern.bundle
Normal file
Binary file not shown.
@ -16,8 +16,11 @@ namespace UnityExplorer.UI
|
|||||||
{
|
{
|
||||||
if (inputsPendingUpdate.Any())
|
if (inputsPendingUpdate.Any())
|
||||||
{
|
{
|
||||||
foreach (var entry in inputsPendingUpdate)
|
var array = inputsPendingUpdate.ToArray();
|
||||||
|
|
||||||
|
for (int i = array.Length - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
var entry = array[i];
|
||||||
LayoutRebuilder.MarkLayoutForRebuild(entry.Rect);
|
LayoutRebuilder.MarkLayoutForRebuild(entry.Rect);
|
||||||
entry.OnValueChanged?.Invoke(entry.Component.text);
|
entry.OnValueChanged?.Invoke(entry.Component.text);
|
||||||
}
|
}
|
||||||
@ -47,8 +50,8 @@ namespace UnityExplorer.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TextGenerator TextGenerator => Component.cachedInputTextGenerator;
|
public TextGenerator TextGenerator => Component.cachedInputTextGenerator;
|
||||||
public bool ReachedMaxVerts => TextGenerator.vertexCount >= UIManager.MAX_TEXT_VERTS;
|
|
||||||
|
|
||||||
|
public bool ReachedMaxVerts => TextGenerator.vertexCount >= UIManager.MAX_TEXT_VERTS;
|
||||||
|
|
||||||
private void OnInputChanged(string value)
|
private void OnInputChanged(string value)
|
||||||
{
|
{
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace UnityExplorer.UI.ObjectPool
|
|
||||||
{
|
|
||||||
public interface IPooledObject
|
|
||||||
{
|
|
||||||
GameObject UIRoot { get; set; }
|
|
||||||
|
|
||||||
GameObject CreateContent(GameObject parent);
|
|
||||||
|
|
||||||
float DefaultHeight { get; }
|
|
||||||
|
|
||||||
//GameObject CreatePrototype();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -6,8 +7,8 @@ using UnityEngine;
|
|||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.UI.CSConsole;
|
using UnityExplorer.CSConsole;
|
||||||
using UnityExplorer.UI.Utility;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Panels
|
namespace UnityExplorer.UI.Panels
|
||||||
{
|
{
|
||||||
@ -18,10 +19,11 @@ namespace UnityExplorer.UI.Panels
|
|||||||
public override int MinWidth => 750;
|
public override int MinWidth => 750;
|
||||||
public override int MinHeight => 300;
|
public override int MinHeight => 300;
|
||||||
|
|
||||||
public InputFieldScroller InputScroll { get; private set; }
|
public InputFieldScroller InputScroller { get; private set; }
|
||||||
public InputFieldRef Input => InputScroll.InputField;
|
public InputFieldRef Input => InputScroller.InputField;
|
||||||
public Text InputText { get; private set; }
|
public Text InputText { get; private set; }
|
||||||
public Text HighlightText { get; private set; }
|
public Text HighlightText { get; private set; }
|
||||||
|
public Text LineNumberText { get; private set; }
|
||||||
|
|
||||||
public Dropdown HelpDropdown { get; private set; }
|
public Dropdown HelpDropdown { get; private set; }
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ namespace UnityExplorer.UI.Panels
|
|||||||
public Action<bool> OnCtrlRToggled;
|
public Action<bool> OnCtrlRToggled;
|
||||||
public Action<bool> OnSuggestionsToggled;
|
public Action<bool> OnSuggestionsToggled;
|
||||||
public Action<bool> OnAutoIndentToggled;
|
public Action<bool> OnAutoIndentToggled;
|
||||||
|
public Action OnPanelResized;
|
||||||
|
|
||||||
private void InvokeOnValueChanged(string value)
|
private void InvokeOnValueChanged(string value)
|
||||||
{
|
{
|
||||||
@ -60,6 +63,11 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
// UI Construction
|
// UI Construction
|
||||||
|
|
||||||
|
public override void OnFinishResize(RectTransform panel)
|
||||||
|
{
|
||||||
|
OnPanelResized?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
protected internal override void DoSetDefaultPosAndAnchors()
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
{
|
{
|
||||||
Rect.localPosition = Vector2.zero;
|
Rect.localPosition = Vector2.zero;
|
||||||
@ -121,19 +129,53 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
// Console Input
|
// 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;
|
int fontSize = 16;
|
||||||
|
|
||||||
var inputObj = UIFactory.CreateScrollInputField(this.content, "ConsoleInput", ConsoleController.STARTUP_TEXT, out var inputScroller, fontSize);
|
var inputObj = UIFactory.CreateScrollInputField(inputArea, "ConsoleInput", ConsoleController.STARTUP_TEXT,
|
||||||
InputScroll = inputScroller;
|
out var inputScroller, fontSize);
|
||||||
|
InputScroller = inputScroller;
|
||||||
ConsoleController.defaultInputFieldAlpha = Input.Component.selectionColor.a;
|
ConsoleController.defaultInputFieldAlpha = Input.Component.selectionColor.a;
|
||||||
Input.OnValueChanged += InvokeOnValueChanged;
|
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 = Input.Component.textComponent;
|
||||||
InputText.supportRichText = false;
|
InputText.supportRichText = false;
|
||||||
Input.PlaceholderText.fontSize = fontSize;
|
|
||||||
InputText.color = Color.clear;
|
InputText.color = Color.clear;
|
||||||
Input.Component.customCaretColor = true;
|
Input.Component.customCaretColor = true;
|
||||||
Input.Component.caretColor = Color.white;
|
Input.Component.caretColor = Color.white;
|
||||||
|
Input.PlaceholderText.fontSize = fontSize;
|
||||||
|
|
||||||
// Lexer highlight text overlay
|
// Lexer highlight text overlay
|
||||||
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", InputText.gameObject);
|
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", InputText.gameObject);
|
||||||
@ -154,7 +196,19 @@ namespace UnityExplorer.UI.Panels
|
|||||||
Input.PlaceholderText.font = UIManager.ConsoleFont;
|
Input.PlaceholderText.font = UIManager.ConsoleFont;
|
||||||
HighlightText.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ using System.Text;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Panels
|
namespace UnityExplorer.UI.Panels
|
||||||
{
|
{
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user