mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-03 20:12:33 +08:00
Compare commits
130 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
084aee617c | |||
d0e508727a | |||
a9a53ba924 | |||
3cd9819790 | |||
5abfa3da67 | |||
e5d2d29a47 | |||
6a47e542e5 | |||
f1b83e7c9e | |||
44c6503ae2 | |||
6970dcbbc7 | |||
ac9c2d5286 | |||
496a5de55e | |||
b062924af7 | |||
5aef8ddc99 | |||
c134c1752e |
61
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
61
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
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 0.4+ IL2CPP
|
||||||
|
- MelonLoader 0.4+ Mono
|
||||||
|
- MelonLoader 0.3 IL2CPP
|
||||||
|
- MelonLoader 0.3 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: Log output
|
||||||
|
description: |
|
||||||
|
Please copy and paste your mod loader's log output.
|
||||||
|
* BepInEx: `BepInEx\LogOutput.log`
|
||||||
|
* MelonLoader: `MelonLoader\latest.log`
|
||||||
|
* Standalone: `{DLL_Location}\UnityExplorer\Logs\` (pick the most recent one)
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
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
|
113
.github/workflows/dotnet.yml
vendored
Normal file
113
.github/workflows/dotnet.yml
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
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/*
|
||||||
|
|
||||||
|
# MelonLoader 0.3.0 Il2Cpp
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_MLLegacy_Cpp
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.MelonLoader_Legacy.Il2Cpp
|
||||||
|
path: ./Release/UnityExplorer.MelonLoader_Legacy.Il2Cpp/*
|
||||||
|
|
||||||
|
# MelonLoader 0.3.0 Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_MLLegacy_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.MelonLoader_Legacy.Mono
|
||||||
|
path: ./Release/UnityExplorer.MelonLoader_Legacy.Mono/*
|
||||||
|
|
||||||
|
# Standalone Il2Cpp
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_STANDALONE_Cpp
|
||||||
|
|
||||||
|
- 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
|
||||||
|
116
README.md
116
README.md
@ -3,45 +3,45 @@
|
|||||||
</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
|
||||||
* UI layouts broken/unusable after changing resolutions: delete the file `data.ini` in the UnityExplorer folder (same place as where you put the DLL). Better fix being worked on.
|
|
||||||
* 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.0 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Mono.zip) |
|
||||||
|
| ML 0.3.0 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Mono.zip) |
|
||||||
|
|
||||||
### 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).
|
||||||
|
|
||||||
@ -50,7 +50,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">
|
||||||
@ -60,49 +60,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.
|
||||||
|
* BepInEx: `BepInEx\config\com.sinai.unityexplorer.cfg`
|
||||||
|
* MelonLoader: `UserData\MelonPreferences.cfg`
|
||||||
|
* Standalone `{DLL_location}\UnityExplorer\config.ini`
|
||||||
|
|
||||||
Depending on the release you are using, the config file will be found at:
|
# Building
|
||||||
* BepInEx: `BepInEx\config\com.sinai.unityexplorer.cfg`
|
|
||||||
* MelonLoader: `UserData\MelonPreferences.cfg`
|
|
||||||
* Standalone `{DLL_location}\UnityExplorer\config.ini`
|
|
||||||
|
|
||||||
## 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):
|
||||||
|
|
||||||
Building the project should be straight-forward, the references are all inside the `lib\` folder.
|
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.
|
||||||
|
|
||||||
1. Open the `src\UnityExplorer.sln` project in Visual Studio.
|
For Visual Studio:
|
||||||
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.
|
|
||||||
3. The DLLs are built to the `Release\` folder in the root of the repository.
|
|
||||||
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
|
0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
|
||||||
|
1. Open the `src\UnityExplorer.sln` project.
|
||||||
|
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. Build the UnityExplorer release(s) you want to use, either by selecting the config as the Active Config, or batch-building.
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
Submodule lib/HarmonyX deleted from 64462b3e31
BIN
lib/MelonLoader_Legacy/MelonLoader.dll
Normal file
BIN
lib/MelonLoader_Legacy/MelonLoader.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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)
|
||||||
{
|
{
|
||||||
OnAutocompleteEscaped();
|
if (AutoCompleteModal.CheckEscape(Completer))
|
||||||
return;
|
{
|
||||||
}
|
OnAutocompleteEscaped();
|
||||||
|
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,48 +402,91 @@ 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;
|
|
||||||
|
|
||||||
// Calculate visible text if necessary
|
|
||||||
if (Input.Rect.rect.height > Panel.InputScroll.ViewportRect.rect.height)
|
|
||||||
{
|
{
|
||||||
topLine = -1;
|
Panel.HighlightText.text = "";
|
||||||
int bottomLine = -1;
|
Panel.LineNumberText.text = "1";
|
||||||
|
return false;
|
||||||
// the top and bottom position of the viewport in relation to the text height
|
|
||||||
// they need the half-height adjustment to normalize against the 'line.topY' value.
|
|
||||||
var viewportMin = Input.Rect.rect.height - Input.Rect.anchoredPosition.y - (Input.Rect.rect.height * 0.5f);
|
|
||||||
var viewportMax = viewportMin - Panel.InputScroll.ViewportRect.rect.height;
|
|
||||||
|
|
||||||
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
|
|
||||||
{
|
|
||||||
var line = Input.TextGenerator.lines[i];
|
|
||||||
// if not set the top line yet, and top of line is below the viewport top
|
|
||||||
if (topLine == -1 && line.topY <= viewportMin)
|
|
||||||
topLine = i;
|
|
||||||
// if bottom of line is below the viewport bottom
|
|
||||||
if ((line.topY - line.height) >= viewportMax)
|
|
||||||
bottomLine = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
topLine = Math.Max(0, topLine - 1);
|
|
||||||
bottomLine = Math.Min(Input.TextGenerator.lineCount - 1, bottomLine + 1);
|
|
||||||
|
|
||||||
startIdx = Input.TextGenerator.lines[topLine].startCharIdx;
|
|
||||||
endIdx = (bottomLine >= Input.TextGenerator.lineCount - 1)
|
|
||||||
? Input.Text.Length - 1
|
|
||||||
: (Input.TextGenerator.lines[bottomLine + 1].startCharIdx - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate the visible lines
|
||||||
|
|
||||||
|
int topLine = -1;
|
||||||
|
int bottomLine = -1;
|
||||||
|
|
||||||
|
// the top and bottom position of the viewport in relation to the text height
|
||||||
|
// they need the half-height adjustment to normalize against the 'line.topY' value.
|
||||||
|
var viewportMin = Input.Rect.rect.height - Input.Rect.anchoredPosition.y - (Input.Rect.rect.height * 0.5f);
|
||||||
|
var viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
|
||||||
|
|
||||||
|
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
|
||||||
|
{
|
||||||
|
var line = Input.TextGenerator.lines[i];
|
||||||
|
// if not set the top line yet, and top of line is below the viewport top
|
||||||
|
if (topLine == -1 && line.topY <= viewportMin)
|
||||||
|
topLine = i;
|
||||||
|
// if bottom of line is below the viewport bottom
|
||||||
|
if ((line.topY - line.height) >= viewportMax)
|
||||||
|
bottomLine = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
topLine = Math.Max(0, topLine - 1);
|
||||||
|
bottomLine = Math.Min(Input.TextGenerator.lineCount - 1, bottomLine + 1);
|
||||||
|
|
||||||
|
int startIdx = Input.TextGenerator.lines[topLine].startCharIdx;
|
||||||
|
int endIdx = (bottomLine >= Input.TextGenerator.lineCount - 1)
|
||||||
|
? Input.Text.Length - 1
|
||||||
|
: (Input.TextGenerator.lines[bottomLine + 1].startCharIdx - 1);
|
||||||
|
|
||||||
|
|
||||||
// Highlight the visible text with the LexerBuilder
|
// 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,11 +1,11 @@
|
|||||||
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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Welcome to the UnityExplorer C# Console!
|
Welcome to the UnityExplorer C# Console!
|
||||||
@ -13,7 +13,7 @@ using System.Text;
|
|||||||
To see your output, use the Log panel or a Console Log window.
|
To see your output, use the Log panel or a Console Log window.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace UnityExplorer.UI.CSConsole
|
namespace UnityExplorer.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
|
||||||
{
|
{
|
||||||
@ -246,7 +246,6 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
var sig = GetSig(member);
|
var sig = GetSig(member);
|
||||||
|
|
||||||
//ExplorerCore.Log($"Trying to cache member {sig}...");
|
//ExplorerCore.Log($"Trying to cache member {sig}...");
|
||||||
//ExplorerCore.Log(member.DeclaringType.FullName + "." + member.Name);
|
|
||||||
|
|
||||||
CacheMember cached;
|
CacheMember cached;
|
||||||
Type returnType;
|
Type returnType;
|
||||||
@ -324,7 +323,8 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GetSig(MemberInfo member) => $"{member.DeclaringType.Name}.{member.Name}";
|
internal static string GetSig(MemberInfo member)
|
||||||
|
=> $"{member.DeclaringType.Name}.{member.Name}";
|
||||||
|
|
||||||
internal static string GetArgumentString(ParameterInfo[] args)
|
internal static string GetArgumentString(ParameterInfo[] args)
|
||||||
{
|
{
|
@ -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
|
||||||
{
|
{
|
||||||
@ -181,8 +181,8 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
return ValueState.Enum;
|
return ValueState.Enum;
|
||||||
else if (type == typeof(Color) || type == typeof(Color32))
|
else if (type == typeof(Color) || type == typeof(Color32))
|
||||||
return ValueState.Color;
|
return ValueState.Color;
|
||||||
else if (InteractiveValueStruct.SupportsType(type))
|
else if (InteractiveValueStruct.SupportsType(type))
|
||||||
return ValueState.ValueStruct;
|
return ValueState.ValueStruct;
|
||||||
else if (ReflectionUtility.IsDictionary(type))
|
else if (ReflectionUtility.IsDictionary(type))
|
||||||
return ValueState.Dictionary;
|
return ValueState.Dictionary;
|
||||||
else if (!typeof(Transform).IsAssignableFrom(type) && ReflectionUtility.IsEnumerable(type))
|
else if (!typeof(Transform).IsAssignableFrom(type) && ReflectionUtility.IsEnumerable(type))
|
@ -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
|
||||||
{
|
{
|
@ -2,16 +2,17 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
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
|
||||||
{
|
{
|
||||||
@ -21,8 +22,8 @@ namespace UnityExplorer.UI.IValues
|
|||||||
|
|
||||||
public override bool CanWrite => base.CanWrite && RefIDictionary != null && !RefIDictionary.IsReadOnly;
|
public override bool CanWrite => base.CanWrite && RefIDictionary != null && !RefIDictionary.IsReadOnly;
|
||||||
|
|
||||||
public Type KeyType;
|
public Type KeysType;
|
||||||
public Type ValueType;
|
public Type ValuesType;
|
||||||
public IDictionary RefIDictionary;
|
public IDictionary RefIDictionary;
|
||||||
|
|
||||||
public int ItemCount => cachedEntries.Count;
|
public int ItemCount => cachedEntries.Count;
|
||||||
@ -75,23 +76,13 @@ namespace UnityExplorer.UI.IValues
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var type = value.GetActualType();
|
var type = value.GetActualType();
|
||||||
if (type.IsGenericType && type.GetGenericArguments().Length == 2)
|
ReflectionUtility.TryGetEntryTypes(type, out KeysType, out ValuesType);
|
||||||
{
|
|
||||||
KeyType = type.GetGenericArguments()[0];
|
|
||||||
ValueType = type.GetGenericArguments()[1];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KeyType = typeof(object);
|
|
||||||
ValueType = typeof(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
CacheEntries(value);
|
CacheEntries(value);
|
||||||
|
|
||||||
TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.Parse(type, false)}";
|
TopLabel.text = $"[{cachedEntries.Count}] {SignatureHighlighter.Parse(type, false)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.DictScrollPool.Refresh(true, false);
|
this.DictScrollPool.Refresh(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +107,7 @@ namespace UnityExplorer.UI.IValues
|
|||||||
else
|
else
|
||||||
cache = cachedEntries[idx];
|
cache = cachedEntries[idx];
|
||||||
|
|
||||||
cache.SetFallbackType(ValueType);
|
cache.SetFallbackType(ValuesType);
|
||||||
cache.SetKey(dictEnumerator.Current.Key);
|
cache.SetKey(dictEnumerator.Current.Key);
|
||||||
cache.SetValueFromSource(dictEnumerator.Current.Value);
|
cache.SetValueFromSource(dictEnumerator.Current.Value);
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
@ -2,16 +2,17 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
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
|
||||||
{
|
{
|
||||||
@ -19,13 +20,15 @@ namespace UnityExplorer.UI.IValues
|
|||||||
object ICacheObjectController.Target => this.CurrentOwner.Value;
|
object ICacheObjectController.Target => this.CurrentOwner.Value;
|
||||||
public Type TargetType { get; private set; }
|
public Type TargetType { get; private set; }
|
||||||
|
|
||||||
public override bool CanWrite => base.CanWrite && RefIList != null && !RefIList.IsReadOnly;
|
public override bool CanWrite => base.CanWrite && ((RefIList != null && !RefIList.IsReadOnly) || IsWritableGenericIList);
|
||||||
|
|
||||||
public Type EntryType;
|
public Type EntryType;
|
||||||
public IList RefIList;
|
public IList RefIList;
|
||||||
|
|
||||||
public int ItemCount => values.Count;
|
private bool IsWritableGenericIList;
|
||||||
private readonly List<object> values = new List<object>();
|
private PropertyInfo genericIndexer;
|
||||||
|
|
||||||
|
public int ItemCount => cachedEntries.Count;
|
||||||
private readonly List<CacheListEntry> cachedEntries = new List<CacheListEntry>();
|
private readonly List<CacheListEntry> cachedEntries = new List<CacheListEntry>();
|
||||||
|
|
||||||
public ScrollPool<CacheListEntryCell> ListScrollPool { get; private set; }
|
public ScrollPool<CacheListEntryCell> ListScrollPool { get; private set; }
|
||||||
@ -49,7 +52,6 @@ namespace UnityExplorer.UI.IValues
|
|||||||
private void ClearAndRelease()
|
private void ClearAndRelease()
|
||||||
{
|
{
|
||||||
RefIList = null;
|
RefIList = null;
|
||||||
values.Clear();
|
|
||||||
|
|
||||||
foreach (var entry in cachedEntries)
|
foreach (var entry in cachedEntries)
|
||||||
{
|
{
|
||||||
@ -66,18 +68,13 @@ namespace UnityExplorer.UI.IValues
|
|||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
// should never be null
|
// should never be null
|
||||||
if (values.Any())
|
if (cachedEntries.Any())
|
||||||
ClearAndRelease();
|
ClearAndRelease();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var type = value.GetActualType();
|
var type = value.GetActualType();
|
||||||
if (type.IsGenericType)
|
ReflectionUtility.TryGetEntryType(type, out EntryType);
|
||||||
EntryType = type.GetGenericArguments()[0];
|
|
||||||
else if (type.HasElementType)
|
|
||||||
EntryType = type.GetElementType();
|
|
||||||
else
|
|
||||||
EntryType = typeof(object);
|
|
||||||
|
|
||||||
CacheEntries(value);
|
CacheEntries(value);
|
||||||
|
|
||||||
@ -92,7 +89,12 @@ namespace UnityExplorer.UI.IValues
|
|||||||
{
|
{
|
||||||
RefIList = value as IList;
|
RefIList = value as IList;
|
||||||
|
|
||||||
values.Clear();
|
// Check if the type implements IList<T> but not IList (ie. Il2CppArrayBase)
|
||||||
|
if (RefIList == null)
|
||||||
|
CheckGenericIList(value);
|
||||||
|
else
|
||||||
|
IsWritableGenericIList = false;
|
||||||
|
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
|
|
||||||
if (ReflectionUtility.TryGetEnumerator(value, out IEnumerator enumerator))
|
if (ReflectionUtility.TryGetEnumerator(value, out IEnumerator enumerator))
|
||||||
@ -103,8 +105,6 @@ namespace UnityExplorer.UI.IValues
|
|||||||
{
|
{
|
||||||
var entry = enumerator.Current;
|
var entry = enumerator.Current;
|
||||||
|
|
||||||
values.Add(entry);
|
|
||||||
|
|
||||||
// If list count increased, create new cache entries
|
// If list count increased, create new cache entries
|
||||||
CacheListEntry cache;
|
CacheListEntry cache;
|
||||||
if (idx >= cachedEntries.Count)
|
if (idx >= cachedEntries.Count)
|
||||||
@ -122,9 +122,9 @@ namespace UnityExplorer.UI.IValues
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove excess cached entries if list count decreased
|
// Remove excess cached entries if list count decreased
|
||||||
if (cachedEntries.Count > values.Count)
|
if (cachedEntries.Count > idx)
|
||||||
{
|
{
|
||||||
for (int i = cachedEntries.Count - 1; i >= values.Count; i--)
|
for (int i = cachedEntries.Count - 1; i >= idx; i--)
|
||||||
{
|
{
|
||||||
var cache = cachedEntries[i];
|
var cache = cachedEntries[i];
|
||||||
if (cache.CellView != null)
|
if (cache.CellView != null)
|
||||||
@ -141,14 +141,61 @@ namespace UnityExplorer.UI.IValues
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CheckGenericIList(object value)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var type = value.GetType();
|
||||||
|
if (type.GetInterfaces().Any(it => it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||||
|
IsWritableGenericIList = !(bool)type.GetProperty("IsReadOnly").GetValue(value, null);
|
||||||
|
else
|
||||||
|
IsWritableGenericIList = false;
|
||||||
|
|
||||||
|
if (IsWritableGenericIList)
|
||||||
|
{
|
||||||
|
// Find the "this[int index]" property.
|
||||||
|
// It might be a private implementation.
|
||||||
|
foreach (var prop in type.GetProperties(ReflectionUtility.FLAGS))
|
||||||
|
{
|
||||||
|
if ((prop.Name == "Item"
|
||||||
|
|| (prop.Name.StartsWith("System.Collections.Generic.IList<") && prop.Name.EndsWith(">.Item")))
|
||||||
|
&& prop.GetIndexParameters() is ParameterInfo[] parameters
|
||||||
|
&& parameters.Length == 1
|
||||||
|
&& parameters[0].ParameterType == typeof(int))
|
||||||
|
{
|
||||||
|
genericIndexer = prop;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (genericIndexer == null)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Failed to find indexer property for IList<T> type '{type.FullName}'!");
|
||||||
|
IsWritableGenericIList = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception processing IEnumerable for IList<T> check: {ex.ReflectionExToString()}");
|
||||||
|
IsWritableGenericIList = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Setting the value of an index to the list
|
// Setting the value of an index to the list
|
||||||
|
|
||||||
public void TrySetValueToIndex(object value, int index)
|
public void TrySetValueToIndex(object value, int index)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//value = value.TryCast(this.EntryType);
|
if (!IsWritableGenericIList)
|
||||||
RefIList[index] = value;
|
{
|
||||||
|
RefIList[index] = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
genericIndexer.SetValue(CurrentOwner.Value, value, new object[] { index });
|
||||||
|
}
|
||||||
|
|
||||||
var entry = cachedEntries[index];
|
var entry = cachedEntries[index];
|
||||||
entry.SetValueFromSource(value);
|
entry.SetValueFromSource(value);
|
@ -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
|
||||||
{
|
{
|
@ -16,17 +16,18 @@ namespace UnityExplorer.Core.Config
|
|||||||
// See the UnityExplorer.Loader namespace for the implementations.
|
// See the UnityExplorer.Loader namespace for the implementations.
|
||||||
public static ConfigHandler Handler { get; private set; }
|
public static ConfigHandler Handler { get; private set; }
|
||||||
|
|
||||||
public static ConfigElement<KeyCode> Master_Toggle;
|
public static ConfigElement<KeyCode> Master_Toggle;
|
||||||
public static ConfigElement<UIManager.VerticalAnchor> Main_Navbar_Anchor;
|
public static ConfigElement<UIManager.VerticalAnchor> Main_Navbar_Anchor;
|
||||||
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<string> Default_Output_Path;
|
public static ConfigElement<bool> Disable_EventSystem_Override;
|
||||||
public static ConfigElement<bool> Log_Unity_Debug;
|
public static ConfigElement<string> Default_Output_Path;
|
||||||
public static ConfigElement<bool> Hide_On_Startup;
|
public static ConfigElement<bool> Log_Unity_Debug;
|
||||||
public static ConfigElement<float> Startup_Delay_Time;
|
public static ConfigElement<bool> Hide_On_Startup;
|
||||||
|
public static ConfigElement<float> Startup_Delay_Time;
|
||||||
|
|
||||||
public static ConfigElement<string> Reflection_Signature_Blacklist;
|
public static ConfigElement<string> Reflection_Signature_Blacklist;
|
||||||
|
|
||||||
// internal configs
|
// internal configs
|
||||||
internal static InternalConfigHandler InternalHandler { get; private set; }
|
internal static InternalConfigHandler InternalHandler { get; private set; }
|
||||||
@ -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 '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,16 +32,32 @@ 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,13 @@
|
|||||||
using System;
|
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 BF = System.Reflection.BindingFlags;
|
||||||
using HarmonyLib;
|
|
||||||
|
|
||||||
namespace UnityExplorer.Core.Input
|
namespace UnityExplorer.Core.Input
|
||||||
{
|
{
|
||||||
@ -26,25 +26,26 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
public static bool ShouldActuallyUnlock => UIManager.ShowMenu && Unlock;
|
public static bool ShouldActuallyUnlock => UIManager.ShowMenu && Unlock;
|
||||||
|
|
||||||
private static CursorLockMode m_lastLockMode;
|
private static CursorLockMode lastLockMode;
|
||||||
private static bool m_lastVisibleState;
|
private static bool lastVisibleState;
|
||||||
|
|
||||||
private static bool m_currentlySettingCursor = false;
|
private static bool currentlySettingCursor = false;
|
||||||
|
|
||||||
private static Type CursorType
|
|
||||||
=> m_cursorType
|
|
||||||
?? (m_cursorType = ReflectionUtility.GetTypeByName("UnityEngine.Cursor"));
|
|
||||||
private static Type m_cursorType;
|
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
SetupPatches();
|
lastLockMode = Cursor.lockState;
|
||||||
|
lastVisibleState = Cursor.visible;
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
@ -61,13 +62,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();
|
||||||
@ -78,26 +79,26 @@ namespace UnityExplorer.Core.Input
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_currentlySettingCursor = true;
|
currentlySettingCursor = true;
|
||||||
|
|
||||||
if (ShouldActuallyUnlock)
|
if (ShouldActuallyUnlock)
|
||||||
{
|
{
|
||||||
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
|
||||||
{
|
{
|
||||||
Cursor.lockState = m_lastLockMode;
|
Cursor.lockState = lastLockMode;
|
||||||
Cursor.visible = m_lastVisibleState;
|
Cursor.visible = lastVisibleState;
|
||||||
|
|
||||||
if (UIManager.EventSys)
|
if (!ConfigManager.Disable_EventSystem_Override.Value && UIManager.EventSys)
|
||||||
ReleaseEventSystem();
|
ReleaseEventSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_currentlySettingCursor = false;
|
currentlySettingCursor = false;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -107,9 +108,9 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
// Event system overrides
|
// Event system overrides
|
||||||
|
|
||||||
private static bool m_settingEventSystem;
|
private static bool settingEventSystem;
|
||||||
private static EventSystem m_lastEventSystem;
|
private static EventSystem lastEventSystem;
|
||||||
private static BaseInputModule m_lastInputModule;
|
private static BaseInputModule lastInputModule;
|
||||||
|
|
||||||
public static void SetEventSystem()
|
public static void SetEventSystem()
|
||||||
{
|
{
|
||||||
@ -118,16 +119,16 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
if (EventSystem.current && EventSystem.current != UIManager.EventSys)
|
if (EventSystem.current && EventSystem.current != UIManager.EventSys)
|
||||||
{
|
{
|
||||||
m_lastEventSystem = EventSystem.current;
|
lastEventSystem = EventSystem.current;
|
||||||
m_lastEventSystem.enabled = false;
|
lastEventSystem.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set to our current system
|
// Set to our current system
|
||||||
m_settingEventSystem = true;
|
settingEventSystem = true;
|
||||||
UIManager.EventSys.enabled = true;
|
UIManager.EventSys.enabled = true;
|
||||||
EventSystem.current = UIManager.EventSys;
|
EventSystem.current = UIManager.EventSys;
|
||||||
InputManager.ActivateUIModule();
|
InputManager.ActivateUIModule();
|
||||||
m_settingEventSystem = false;
|
settingEventSystem = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ReleaseEventSystem()
|
public static void ReleaseEventSystem()
|
||||||
@ -135,14 +136,14 @@ namespace UnityExplorer.Core.Input
|
|||||||
if (InputManager.CurrentType == InputType.InputSystem)
|
if (InputManager.CurrentType == InputType.InputSystem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_lastEventSystem && m_lastEventSystem.gameObject.activeSelf)
|
if (lastEventSystem && lastEventSystem.gameObject.activeSelf)
|
||||||
{
|
{
|
||||||
m_lastEventSystem.enabled = true;
|
lastEventSystem.enabled = true;
|
||||||
|
|
||||||
m_settingEventSystem = true;
|
settingEventSystem = true;
|
||||||
EventSystem.current = m_lastEventSystem;
|
EventSystem.current = lastEventSystem;
|
||||||
m_lastInputModule?.ActivateModule();
|
lastInputModule?.ActivateModule();
|
||||||
m_settingEventSystem = false;
|
settingEventSystem = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,36 +153,29 @@ namespace UnityExplorer.Core.Input
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (CursorType == null)
|
|
||||||
throw new Exception("Could not load Type 'UnityEngine.Cursor'!");
|
|
||||||
|
|
||||||
// Get current cursor state and enable cursor
|
|
||||||
m_lastLockMode = (CursorLockMode?)CursorType.GetProperty("lockState", BF.Public | BF.Static)?.GetValue(null, null)
|
|
||||||
?? CursorLockMode.None;
|
|
||||||
|
|
||||||
m_lastVisibleState = (bool?)CursorType.GetProperty("visible", BF.Public | BF.Static)?.GetValue(null, null)
|
|
||||||
?? false;
|
|
||||||
|
|
||||||
ExplorerCore.Loader.SetupCursorPatches();
|
ExplorerCore.Loader.SetupCursorPatches();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExplorerCore.Log($"Error on CursorUnlocker.Init! {e.GetType()}, {e.Message}");
|
ExplorerCore.Log($"Exception setting up Cursor patches: {e.GetType()}, {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Prefix_EventSystem_set_current(ref EventSystem value)
|
public static void Prefix_EventSystem_set_current(ref EventSystem value)
|
||||||
{
|
{
|
||||||
if (!m_settingEventSystem && value != UIManager.EventSys)
|
if (!settingEventSystem && value)
|
||||||
{
|
{
|
||||||
m_lastEventSystem = value;
|
lastEventSystem = value;
|
||||||
m_lastInputModule = value?.currentInputModule;
|
lastInputModule = value.currentInputModule;
|
||||||
|
}
|
||||||
|
|
||||||
if (ShouldActuallyUnlock)
|
if (!UIManager.EventSys)
|
||||||
{
|
return;
|
||||||
value = UIManager.EventSys;
|
|
||||||
value.enabled = true;
|
if (!settingEventSystem && ShouldActuallyUnlock && !ConfigManager.Disable_EventSystem_Override.Value)
|
||||||
}
|
{
|
||||||
|
value = UIManager.EventSys;
|
||||||
|
value.enabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,9 +185,9 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
public static void Prefix_set_lockState(ref CursorLockMode value)
|
public static void Prefix_set_lockState(ref CursorLockMode value)
|
||||||
{
|
{
|
||||||
if (!m_currentlySettingCursor)
|
if (!currentlySettingCursor)
|
||||||
{
|
{
|
||||||
m_lastLockMode = value;
|
lastLockMode = value;
|
||||||
|
|
||||||
if (ShouldActuallyUnlock)
|
if (ShouldActuallyUnlock)
|
||||||
value = CursorLockMode.None;
|
value = CursorLockMode.None;
|
||||||
@ -202,9 +196,9 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
public static void Prefix_set_visible(ref bool value)
|
public static void Prefix_set_visible(ref bool value)
|
||||||
{
|
{
|
||||||
if (!m_currentlySettingCursor)
|
if (!currentlySettingCursor)
|
||||||
{
|
{
|
||||||
m_lastVisibleState = value;
|
lastVisibleState = value;
|
||||||
|
|
||||||
if (ShouldActuallyUnlock)
|
if (ShouldActuallyUnlock)
|
||||||
value = true;
|
value = true;
|
||||||
|
@ -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
|
||||||
@ -61,7 +61,7 @@ namespace UnityExplorer.Core.Input
|
|||||||
// First, just try to use the legacy input, see if its working.
|
// First, just try to use the legacy input, see if its working.
|
||||||
// The InputSystem package may be present but not actually activated, so we can find out this way.
|
// The InputSystem package may be present but not actually activated, so we can find out this way.
|
||||||
|
|
||||||
if (LegacyInput.TInput != null || (ReflectionUtility.LoadModule("UnityEngine.InputLegacyModule") && LegacyInput.TInput != null))
|
if (LegacyInput.TInput != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -80,7 +80,7 @@ namespace UnityExplorer.Core.Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InputSystem.TKeyboard != null || (ReflectionUtility.LoadModule("Unity.InputSystem") && InputSystem.TKeyboard != null))
|
if (InputSystem.TKeyboard != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
@ -15,6 +15,8 @@ using UnityExplorer.Core;
|
|||||||
using CppType = Il2CppSystem.Type;
|
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 UnityEngine;
|
||||||
|
|
||||||
namespace UnityExplorer
|
namespace UnityExplorer
|
||||||
{
|
{
|
||||||
@ -24,13 +26,18 @@ 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
|
||||||
|
|
||||||
// Extern C++ methods
|
// Extern C++ methods
|
||||||
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||||
@ -43,23 +50,23 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Deobfuscation cache
|
#region Deobfuscation cache
|
||||||
|
|
||||||
private static readonly Dictionary<string, Type> DeobfuscatedTypes = new Dictionary<string, Type>();
|
private static readonly Dictionary<string, Type> DeobfuscatedTypes = new Dictionary<string, Type>();
|
||||||
private static readonly Dictionary<string, string> reverseDeobCache = new Dictionary<string, string>();
|
private static readonly Dictionary<string, string> reverseDeobCache = new Dictionary<string, string>();
|
||||||
@ -71,24 +78,25 @@ 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)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Thanks to Slaynash for this
|
if (!type.CustomAttributes.Any())
|
||||||
if (type.CustomAttributes.Any(it => it.AttributeType.Name == "ObfuscatedNameAttribute"))
|
return;
|
||||||
{
|
|
||||||
var cppType = Il2CppType.From(type);
|
|
||||||
|
|
||||||
if (!DeobfuscatedTypes.ContainsKey(cppType.FullName))
|
foreach (var att in type.CustomAttributes)
|
||||||
|
{
|
||||||
|
// Thanks to Slaynash for this
|
||||||
|
|
||||||
|
if (att.AttributeType == typeof(ObfuscatedNameAttribute))
|
||||||
{
|
{
|
||||||
DeobfuscatedTypes.Add(cppType.FullName, type);
|
string obfuscatedName = att.ConstructorArguments[0].Value.ToString();
|
||||||
reverseDeobCache.Add(type.FullName, cppType.FullName);
|
|
||||||
|
DeobfuscatedTypes.Add(obfuscatedName, type);
|
||||||
|
reverseDeobCache.Add(type.FullName, obfuscatedName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,7 +111,7 @@ namespace UnityExplorer
|
|||||||
return theString;
|
return theString;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
// Get type by name
|
// Get type by name
|
||||||
@ -116,7 +124,7 @@ namespace UnityExplorer
|
|||||||
return base.Internal_GetTypeByName(fullName);
|
return base.Internal_GetTypeByName(fullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Get actual type
|
#region Get actual type
|
||||||
|
|
||||||
internal override Type Internal_GetActualType(object obj)
|
internal override Type Internal_GetActualType(object obj)
|
||||||
{
|
{
|
||||||
@ -124,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))
|
||||||
@ -175,10 +182,10 @@ namespace UnityExplorer
|
|||||||
return monoType;
|
return monoType;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Casting
|
#region Casting
|
||||||
|
|
||||||
private static readonly Dictionary<string, IntPtr> cppClassPointers = new Dictionary<string, IntPtr>();
|
private static readonly Dictionary<string, IntPtr> cppClassPointers = new Dictionary<string, IntPtr>();
|
||||||
|
|
||||||
@ -208,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;
|
||||||
@ -232,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))
|
||||||
@ -258,10 +265,22 @@ namespace UnityExplorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
//private static bool IsAssignableFrom(Type thisType, Type fromType)
|
||||||
|
//{
|
||||||
|
// if (!Il2CppTypeNotNull(fromType, out IntPtr fromTypePtr)
|
||||||
|
// || !Il2CppTypeNotNull(thisType, out IntPtr thisTypePtr))
|
||||||
|
// {
|
||||||
|
// // one or both of the types are not Il2Cpp types, use normal check
|
||||||
|
// return thisType.IsAssignableFrom(fromType);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return il2cpp_class_is_assignable_from(thisTypePtr, fromTypePtr);
|
||||||
|
//}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Boxing and unboxing ValueTypes
|
#region Boxing and unboxing ValueTypes
|
||||||
|
|
||||||
// cached il2cpp unbox methods
|
// cached il2cpp unbox methods
|
||||||
internal static readonly Dictionary<string, MethodInfo> unboxMethods = new Dictionary<string, MethodInfo>();
|
internal static readonly Dictionary<string, MethodInfo> unboxMethods = new Dictionary<string, MethodInfo>();
|
||||||
@ -275,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;
|
||||||
|
|
||||||
@ -364,10 +403,10 @@ namespace UnityExplorer
|
|||||||
return cppStruct;
|
return cppStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region String boxing/unboxing
|
#region String boxing/unboxing
|
||||||
|
|
||||||
private const string IL2CPP_STRING_FULLNAME = "Il2CppSystem.String";
|
private const string IL2CPP_STRING_FULLNAME = "Il2CppSystem.String";
|
||||||
private const string STRING_FULLNAME = "System.String";
|
private const string STRING_FULLNAME = "System.String";
|
||||||
@ -408,10 +447,10 @@ namespace UnityExplorer
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Singleton finder
|
#region Singleton finder
|
||||||
|
|
||||||
internal override void Internal_FindSingleton(string[] possibleNames, Type type, BF flags, List<object> instances)
|
internal override void Internal_FindSingleton(string[] possibleNames, Type type, BF flags, List<object> instances)
|
||||||
{
|
{
|
||||||
@ -433,47 +472,32 @@ namespace UnityExplorer
|
|||||||
base.Internal_FindSingleton(possibleNames, type, flags, instances);
|
base.Internal_FindSingleton(possibleNames, type, flags, instances);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Force-loading game modules
|
#region Force-loading game modules
|
||||||
|
|
||||||
|
internal static string UnhollowedFolderPath => Path.GetFullPath(
|
||||||
|
#if ML
|
||||||
|
Path.Combine("MelonLoader", "Managed")
|
||||||
|
#elif BIE
|
||||||
|
Path.Combine(BepInEx.Paths.BepInExRootPath, "unhollowed")
|
||||||
|
#else
|
||||||
|
Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Modules")
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
// Helper for IL2CPP to try to make sure the Unhollowed game assemblies are actually loaded.
|
// Helper for IL2CPP to try to make sure the Unhollowed game assemblies are actually loaded.
|
||||||
|
|
||||||
internal override bool Internal_LoadModule(string moduleName)
|
|
||||||
{
|
|
||||||
if (!moduleName.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
moduleName += ".dll";
|
|
||||||
#if ML
|
|
||||||
var path = Path.Combine("MelonLoader", "Managed", $"{moduleName}");
|
|
||||||
#else
|
|
||||||
var path = Path.Combine("BepInEx", "unhollowed", $"{moduleName}");
|
|
||||||
#endif
|
|
||||||
return DoLoadModule(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force loading all il2cpp modules
|
// Force loading all il2cpp modules
|
||||||
|
|
||||||
internal void TryLoadGameModules()
|
internal void TryLoadGameModules()
|
||||||
{
|
{
|
||||||
string dirpath =
|
if (Directory.Exists(UnhollowedFolderPath))
|
||||||
#if ML
|
|
||||||
Path.Combine("MelonLoader", "Managed");
|
|
||||||
#elif BIE
|
|
||||||
Path.Combine("BepInEx", "unhollowed");
|
|
||||||
#else
|
|
||||||
Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Modules");
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
if (Directory.Exists(dirpath))
|
|
||||||
{
|
{
|
||||||
var files = Directory.GetFiles(dirpath);
|
var files = Directory.GetFiles(UnhollowedFolderPath);
|
||||||
foreach (var filePath in files)
|
foreach (var filePath in files)
|
||||||
{
|
{
|
||||||
var name = Path.GetFileName(filePath);
|
|
||||||
if (!name.StartsWith("Unity") && !name.StartsWith("Assembly-CSharp"))
|
|
||||||
continue;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DoLoadModule(filePath, true);
|
DoLoadModule(filePath, true);
|
||||||
@ -484,6 +508,8 @@ namespace UnityExplorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
ExplorerCore.LogWarning($"Expected Unhollowed folder path does not exist: '{UnhollowedFolderPath}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool DoLoadModule(string fullPath, bool suppressWarning = false)
|
internal bool DoLoadModule(string fullPath, bool suppressWarning = false)
|
||||||
@ -493,7 +519,8 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Assembly.Load(File.ReadAllBytes(fullPath));
|
Assembly.LoadFile(fullPath);
|
||||||
|
//Assembly.Load(File.ReadAllBytes(fullPath));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -510,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.
|
||||||
@ -636,6 +663,9 @@ namespace UnityExplorer
|
|||||||
"UnityEngine.Scripting.GarbageCollector+CollectIncrementalDelegate.Invoke",
|
"UnityEngine.Scripting.GarbageCollector+CollectIncrementalDelegate.Invoke",
|
||||||
"UnityEngine.Scripting.GarbageCollector.CollectIncremental",
|
"UnityEngine.Scripting.GarbageCollector.CollectIncremental",
|
||||||
"UnityEngine.SpherecastCommand.ScheduleBatch",
|
"UnityEngine.SpherecastCommand.ScheduleBatch",
|
||||||
|
"UnityEngine.Texture.GetPixelDataSize",
|
||||||
|
"UnityEngine.Texture.GetPixelDataOffset",
|
||||||
|
"UnityEngine.Texture.GetPixelDataOffset",
|
||||||
"UnityEngine.Texture2D+SetPixelDataImplArrayDelegate.Invoke",
|
"UnityEngine.Texture2D+SetPixelDataImplArrayDelegate.Invoke",
|
||||||
"UnityEngine.Texture2D+SetPixelDataImplDelegate.Invoke",
|
"UnityEngine.Texture2D+SetPixelDataImplDelegate.Invoke",
|
||||||
"UnityEngine.Texture2D.SetPixelDataImpl",
|
"UnityEngine.Texture2D.SetPixelDataImpl",
|
||||||
@ -657,7 +687,51 @@ namespace UnityExplorer
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Temp il2cpp list/dictionary fixes
|
#region IL2CPP IEnumerable and IDictionary
|
||||||
|
|
||||||
|
protected override bool Internal_TryGetEntryType(Type enumerableType, out Type type)
|
||||||
|
{
|
||||||
|
// Check for system types (not unhollowed)
|
||||||
|
if (base.Internal_TryGetEntryType(enumerableType, out type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Type is either an IL2CPP enumerable, or its not generic.
|
||||||
|
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
// Temporary naive solution until IL2CPP interface support improves.
|
||||||
|
// This will work fine for most cases, but there are edge cases which would not work.
|
||||||
|
type = type.GetGenericArguments()[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unable to determine entry type
|
||||||
|
type = typeof(object);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool Internal_TryGetEntryTypes(Type type, out Type keys, out Type values)
|
||||||
|
{
|
||||||
|
if (base.Internal_TryGetEntryTypes(type, out keys, out values))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Type is either an IL2CPP dictionary, or its not generic.
|
||||||
|
if (type.IsGenericType)
|
||||||
|
{
|
||||||
|
// Naive solution until IL2CPP interfaces improve.
|
||||||
|
var args = type.GetGenericArguments();
|
||||||
|
if (args.Length == 2)
|
||||||
|
{
|
||||||
|
keys = args[0];
|
||||||
|
values = args[1];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = typeof(object);
|
||||||
|
values = typeof(object);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Temp fix until Unhollower interface support improves
|
// Temp fix until Unhollower interface support improves
|
||||||
|
|
||||||
@ -730,7 +804,9 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
if (!getEnumeratorMethods.ContainsKey(key))
|
if (!getEnumeratorMethods.ContainsKey(key))
|
||||||
{
|
{
|
||||||
getEnumeratorMethods.Add(key, type.GetMethod("GetEnumerator"));
|
var method = type.GetMethod("System_Collections_IEnumerable_GetEnumerator", FLAGS)
|
||||||
|
?? type.GetMethod("GetEnumerator");
|
||||||
|
getEnumeratorMethods.Add(key, method);
|
||||||
|
|
||||||
// ensure the enumerator type is supported
|
// ensure the enumerator type is supported
|
||||||
try
|
try
|
||||||
@ -816,7 +892,9 @@ namespace UnityExplorer
|
|||||||
var cacheKey = keys.GetType().AssemblyQualifiedName;
|
var cacheKey = keys.GetType().AssemblyQualifiedName;
|
||||||
if (!getEnumeratorMethods.ContainsKey(cacheKey))
|
if (!getEnumeratorMethods.ContainsKey(cacheKey))
|
||||||
{
|
{
|
||||||
getEnumeratorMethods.Add(cacheKey, keyCollType.GetMethod("GetEnumerator"));
|
var method = keyCollType.GetMethod("System_Collections_IDictionary_GetEnumerator", FLAGS)
|
||||||
|
?? keyCollType.GetMethod("GetEnumerator");
|
||||||
|
getEnumeratorMethods.Add(cacheKey, method);
|
||||||
|
|
||||||
// test support
|
// test support
|
||||||
try
|
try
|
||||||
|
@ -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,12 +155,7 @@ 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
|
// Singleton finder
|
||||||
public static bool LoadModule(string moduleName)
|
|
||||||
=> Instance.Internal_LoadModule(moduleName);
|
|
||||||
|
|
||||||
internal virtual bool Internal_LoadModule(string moduleName)
|
|
||||||
=> false;
|
|
||||||
|
|
||||||
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)
|
||||||
=> Instance.Internal_FindSingleton(possibleNames, type, flags, instances);
|
=> Instance.Internal_FindSingleton(possibleNames, type, flags, instances);
|
||||||
@ -220,7 +219,7 @@ namespace UnityExplorer
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Type and Generic Parameter implementation cache
|
#region Type and Generic Parameter implementation cache
|
||||||
@ -355,7 +354,7 @@ namespace UnityExplorer
|
|||||||
return genericParameterInheritance[key];
|
return genericParameterInheritance[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Internal MemberInfo Cache
|
#region Internal MemberInfo Cache
|
||||||
@ -432,32 +431,44 @@ 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;
|
return;
|
||||||
ConfigManager.Handler.SaveConfig();
|
|
||||||
return;
|
try
|
||||||
|
{
|
||||||
|
var sigs = blacklist.Split(';');
|
||||||
|
foreach (var sig in sigs)
|
||||||
|
{
|
||||||
|
var s = sig.Trim();
|
||||||
|
if (string.IsNullOrEmpty(s))
|
||||||
|
continue;
|
||||||
|
if (!currentBlacklist.Contains(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;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
if (string.IsNullOrEmpty(blacklist))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var sigs = blacklist.Split(';');
|
|
||||||
foreach (var sig in sigs)
|
|
||||||
{
|
{
|
||||||
var s = sig.Trim();
|
ExplorerCore.LogWarning($"Exception setting up reflection blacklist: {ex.ReflectionExToString()}");
|
||||||
if (string.IsNullOrEmpty(s))
|
|
||||||
continue;
|
|
||||||
if (!currentBlacklist.Contains(s))
|
|
||||||
currentBlacklist.Add(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono.CSharp.IL2CPP.Blacklist.SignatureBlacklist = currentBlacklist;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsBlacklisted(MemberInfo member)
|
public static bool IsBlacklisted(MemberInfo member)
|
||||||
@ -466,6 +477,7 @@ namespace UnityExplorer
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
var sig = $"{member.DeclaringType.FullName}.{member.Name}";
|
var sig = $"{member.DeclaringType.FullName}.{member.Name}";
|
||||||
|
|
||||||
return currentBlacklist.Contains(sig);
|
return currentBlacklist.Contains(sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,6 +508,39 @@ namespace UnityExplorer
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TryGetEntryType
|
||||||
|
|
||||||
|
public static bool TryGetEntryType(Type enumerableType, out Type type)
|
||||||
|
=> Instance.Internal_TryGetEntryType(enumerableType, out type);
|
||||||
|
|
||||||
|
protected virtual bool Internal_TryGetEntryType(Type enumerableType, out Type type)
|
||||||
|
{
|
||||||
|
// Check for arrays
|
||||||
|
if (enumerableType.IsArray)
|
||||||
|
{
|
||||||
|
type = enumerableType.GetElementType();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for implementation of IEnumerable<T>, IList<T> or ICollection<T>
|
||||||
|
foreach (var t in enumerableType.GetInterfaces())
|
||||||
|
{
|
||||||
|
if (t.IsGenericType)
|
||||||
|
{
|
||||||
|
var typeDef = t.GetGenericTypeDefinition();
|
||||||
|
if (typeDef == typeof(IEnumerable<>) || typeDef == typeof(IList<>) || typeDef == typeof(ICollection<>))
|
||||||
|
{
|
||||||
|
type = t.GetGenericArguments()[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unable to determine any generic element type, just use object.
|
||||||
|
type = typeof(object);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// IsDictionary
|
// IsDictionary
|
||||||
|
|
||||||
public static bool IsDictionary(Type type) => Instance.Internal_IsDictionary(type);
|
public static bool IsDictionary(Type type) => Instance.Internal_IsDictionary(type);
|
||||||
@ -524,5 +569,28 @@ namespace UnityExplorer
|
|||||||
yield return new DictionaryEntry(enumerator.Key, enumerator.Value);
|
yield return new DictionaryEntry(enumerator.Key, enumerator.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TryGetEntryTypes
|
||||||
|
|
||||||
|
public static bool TryGetEntryTypes(Type dictionaryType, out Type keys, out Type values)
|
||||||
|
=> Instance.Internal_TryGetEntryTypes(dictionaryType, out keys, out values);
|
||||||
|
|
||||||
|
protected virtual bool Internal_TryGetEntryTypes(Type dictionaryType, out Type keys, out Type values)
|
||||||
|
{
|
||||||
|
foreach (var t in dictionaryType.GetInterfaces())
|
||||||
|
{
|
||||||
|
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IDictionary<,>))
|
||||||
|
{
|
||||||
|
var args = t.GetGenericArguments();
|
||||||
|
keys = args[0];
|
||||||
|
values = args[1];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keys = typeof(object);
|
||||||
|
values = typeof(object);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
ExplorerCore.Context = RuntimeContext.IL2CPP;
|
ExplorerCore.Context = RuntimeContext.IL2CPP;
|
||||||
//Reflection = new Il2CppReflection();
|
|
||||||
TextureUtil = new Il2CppTextureUtil();
|
TextureUtil = new Il2CppTextureUtil();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,19 +29,12 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Application.add_logMessageReceived(new Action<string, string, LogType>(ExplorerCore.Instance.OnUnityLog));
|
Application.add_logMessageReceived(new Action<string, string, LogType>(Application_logMessageReceived));
|
||||||
|
|
||||||
var logType = ReflectionUtility.GetTypeByName("UnityEngine.Application+LogCallback");
|
|
||||||
var castMethod = logType.GetMethod("op_Implicit", new[] { typeof(Action<string, string, LogType>) });
|
|
||||||
var addMethod = typeof(Application).GetMethod("add_logMessageReceived", BF.Static | BF.Public, null, new[] { logType }, null);
|
|
||||||
addMethod.Invoke(null, new[]
|
|
||||||
{
|
|
||||||
castMethod.Invoke(null, new[] { new Action<string, string, LogType>(Application_logMessageReceived) })
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
ExplorerCore.LogWarning("Exception setting up Unity log listener, make sure Unity libraries have been unstripped!");
|
ExplorerCore.LogWarning("Exception setting up Unity log listener, make sure Unity libraries have been unstripped!");
|
||||||
|
ExplorerCore.Log(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,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()
|
||||||
@ -61,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)
|
||||||
|
@ -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,8 +14,40 @@ 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();
|
||||||
|
|
||||||
public static void ATestMethod(string s, float f, Vector3 vector, DateTime date, Quaternion quater, bool b, CameraClearFlags enumvalue)
|
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}");
|
ExplorerCore.Log($"{s}, {f}, {vector.ToString()}, {date}, {quater.eulerAngles.ToString()}, {b}, {enumvalue}");
|
||||||
|
@ -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,22 +131,12 @@ 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 toStringMethod = type.GetMethod("ToString", ArgumentUtility.EmptyTypes);
|
||||||
{
|
toStringMethods.Add(type.AssemblyQualifiedName, toStringMethod);
|
||||||
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);
|
|
||||||
toStringMethods.Add(type.AssemblyQualifiedName, toStringMethod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke the ToString method on the object
|
// Invoke the ToString method on the object
|
||||||
@ -157,10 +146,7 @@ namespace UnityExplorer
|
|||||||
string toString;
|
string toString;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (toStringFormattedMethods.TryGetValue(type.AssemblyQualifiedName, out MethodInfo formatMethod))
|
toString = (string)toStringMethods[type.AssemblyQualifiedName].Invoke(value, ArgumentUtility.EmptyArgs);
|
||||||
toString = (string)formatMethod.Invoke(value, new object[] { ParseUtility.NUMBER_FORMAT });
|
|
||||||
else
|
|
||||||
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,7 +20,7 @@ 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.0";
|
public const string VERSION = "4.1.8";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
public const string GUID = "com.sinai.unityexplorer";
|
public const string GUID = "com.sinai.unityexplorer";
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ namespace UnityExplorer
|
|||||||
RuntimeProvider.Instance.ProcessOnPostRender();
|
RuntimeProvider.Instance.ProcessOnPostRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region LOGGING
|
#region LOGGING
|
||||||
|
|
||||||
public static void Log(object message)
|
public static void Log(object message)
|
||||||
=> Log(message, LogType.Log);
|
=> Log(message, LogType.Log);
|
||||||
@ -145,6 +146,6 @@ namespace UnityExplorer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|
||||||
{
|
|
||||||
needRefresh = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var comp in comps)
|
|
||||||
{
|
|
||||||
if (!compInstanceIDs.Contains(comp.GetInstanceID()))
|
|
||||||
{
|
|
||||||
needRefresh = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!needRefresh)
|
int count = 0;
|
||||||
|
foreach (var comp in comps)
|
||||||
|
{
|
||||||
|
if (!comp)
|
||||||
|
continue;
|
||||||
|
count++;
|
||||||
|
if (!compInstanceIDs.Contains(comp.GetInstanceID()))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < behaviours.Length; i++)
|
needRefresh = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!needRefresh)
|
||||||
|
{
|
||||||
|
if (count != componentEntries.Count)
|
||||||
|
needRefresh = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
foreach (var behaviour in behaviours)
|
||||||
{
|
{
|
||||||
var behaviour = behaviours[i];
|
if (!behaviour)
|
||||||
if (behaviour.enabled != behaviourEnabledStates[i])
|
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,12 +243,12 @@ 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));
|
||||||
UIFactory.SetLayoutElement(scrollObj, minHeight: 300, flexibleWidth: 9999, flexibleHeight: 1);
|
UIFactory.SetLayoutElement(scrollObj, minHeight: 250, preferredHeight: 300, flexibleHeight: 0, flexibleWidth: 9999);
|
||||||
|
|
||||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2);
|
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2);
|
||||||
|
|
||||||
@ -244,10 +266,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
{
|
{
|
||||||
var listHolder = UIFactory.CreateUIObject("ListHolders", UIRoot);
|
var listHolder = UIFactory.CreateUIObject("ListHolders", UIRoot);
|
||||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(listHolder, false, true, true, true, 8, 2, 2, 2, 2);
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(listHolder, false, true, true, true, 8, 2, 2, 2, 2);
|
||||||
UIFactory.SetLayoutElement(listHolder, minHeight: 350, flexibleWidth: 9999, flexibleHeight: 9999);
|
UIFactory.SetLayoutElement(listHolder, minHeight: 150, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||||
//var listRect = listHolder.GetComponent<RectTransform>();
|
|
||||||
//listRect.anchorMin = new Vector2(0, 1);
|
|
||||||
//listRect.anchorMax = new Vector2(1, 1);
|
|
||||||
|
|
||||||
// Left group (Children)
|
// Left group (Children)
|
||||||
|
|
@ -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)
|
||||||
@ -155,8 +164,8 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
mousePos.x = 350;
|
mousePos.x = 350;
|
||||||
if (mousePos.x > Screen.width - 350)
|
if (mousePos.x > Screen.width - 350)
|
||||||
mousePos.x = Screen.width - 350;
|
mousePos.x = Screen.width - 350;
|
||||||
if (mousePos.y < mainPanelRect.rect.height)
|
if (mousePos.y < Rect.rect.height)
|
||||||
mousePos.y += mainPanelRect.rect.height + 10;
|
mousePos.y += Rect.rect.height + 10;
|
||||||
else
|
else
|
||||||
mousePos.y -= 10;
|
mousePos.y -= 10;
|
||||||
|
|
||||||
@ -341,10 +350,10 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
protected internal override void DoSetDefaultPosAndAnchors()
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
{
|
{
|
||||||
mainPanelRect.anchorMin = Vector2.zero;
|
Rect.anchorMin = Vector2.zero;
|
||||||
mainPanelRect.anchorMax = Vector2.zero;
|
Rect.anchorMax = Vector2.zero;
|
||||||
mainPanelRect.pivot = new Vector2(0.5f, 1);
|
Rect.pivot = new Vector2(0.5f, 1);
|
||||||
mainPanelRect.sizeDelta = new Vector2(700, 150);
|
Rect.sizeDelta = new Vector2(700, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ConstructPanelContent()
|
public override void ConstructPanelContent()
|
@ -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)
|
||||||
@ -344,7 +340,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
ConstructUnityObjectRow();
|
ConstructUnityObjectRow();
|
||||||
|
|
||||||
mainContentHolder = UIFactory.CreateVerticalGroup(UIRoot, "MemberHolder", false, false, true, true, 5, new Vector4(2,2,2,2),
|
mainContentHolder = UIFactory.CreateVerticalGroup(UIRoot, "MemberHolder", false, false, true, true, 5, new Vector4(2, 2, 2, 2),
|
||||||
new Color(0.12f, 0.12f, 0.12f));
|
new Color(0.12f, 0.12f, 0.12f));
|
||||||
UIFactory.SetLayoutElement(mainContentHolder, flexibleWidth: 9999, flexibleHeight: 9999);
|
UIFactory.SetLayoutElement(mainContentHolder, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||||
|
|
||||||
@ -354,7 +350,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
// Member scroll pool
|
// Member scroll pool
|
||||||
|
|
||||||
var memberBorder = UIFactory.CreateVerticalGroup(mainContentHolder, "ScrollPoolHolder", false, false, true, true, padding: new Vector4(2,2,2,2),
|
var memberBorder = UIFactory.CreateVerticalGroup(mainContentHolder, "ScrollPoolHolder", false, false, true, true, padding: new Vector4(2, 2, 2, 2),
|
||||||
bgColor: new Color(0.05f, 0.05f, 0.05f));
|
bgColor: new Color(0.05f, 0.05f, 0.05f));
|
||||||
UIFactory.SetLayoutElement(memberBorder, flexibleWidth: 9999, flexibleHeight: 9999);
|
UIFactory.SetLayoutElement(memberBorder, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||||
|
|
||||||
@ -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);
|
||||||
}
|
}
|
@ -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) =>
|
||||||
{
|
{
|
||||||
|
@ -7,12 +7,12 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityExplorer.Core.Config;
|
|
||||||
using UnityExplorer.Loader.BIE;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityExplorer.Core;
|
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
|
using UnityExplorer.Core;
|
||||||
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
|
using UnityExplorer.Loader.BIE;
|
||||||
#if CPP
|
#if CPP
|
||||||
using BepInEx.IL2CPP;
|
using BepInEx.IL2CPP;
|
||||||
using UnhollowerRuntimeLib;
|
using UnhollowerRuntimeLib;
|
||||||
@ -46,11 +46,10 @@ namespace UnityExplorer
|
|||||||
private static readonly Harmony s_harmony = new Harmony(ExplorerCore.GUID);
|
private static readonly Harmony s_harmony = new Harmony(ExplorerCore.GUID);
|
||||||
|
|
||||||
public string ExplorerFolder => Path.Combine(Paths.PluginPath, ExplorerCore.NAME);
|
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> OnLogMessage => LogSource.LogMessage;
|
||||||
public Action<object> OnLogWarning => LogSource.LogWarning;
|
public Action<object> OnLogWarning => LogSource.LogWarning;
|
||||||
public Action<object> OnLogError => LogSource.LogError;
|
public Action<object> OnLogError => LogSource.LogError;
|
||||||
|
|
||||||
// Init common to Mono and Il2Cpp
|
// Init common to Mono and Il2Cpp
|
||||||
internal void UniversalInit()
|
internal void UniversalInit()
|
||||||
|
@ -10,7 +10,6 @@ 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; }
|
||||||
|
@ -9,11 +9,15 @@ using UnityExplorer.Core;
|
|||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
using UnityExplorer.Loader.ML;
|
using UnityExplorer.Loader.ML;
|
||||||
|
#if ML_LEGACY
|
||||||
|
using Harmony;
|
||||||
|
#else
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
|
||||||
|
#endif
|
||||||
|
|
||||||
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
|
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
|
||||||
[assembly: MelonGame(null, null)]
|
[assembly: MelonGame(null, null)]
|
||||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
|
|
||||||
[assembly: MelonColor(ConsoleColor.DarkCyan)]
|
[assembly: MelonColor(ConsoleColor.DarkCyan)]
|
||||||
|
|
||||||
namespace UnityExplorer
|
namespace UnityExplorer
|
||||||
@ -23,7 +27,6 @@ namespace UnityExplorer
|
|||||||
public static ExplorerMelonMod Instance;
|
public static ExplorerMelonMod Instance;
|
||||||
|
|
||||||
public string ExplorerFolder => Path.Combine("Mods", ExplorerCore.NAME);
|
public string ExplorerFolder => Path.Combine("Mods", ExplorerCore.NAME);
|
||||||
public string ConfigFolder => ExplorerFolder;
|
|
||||||
|
|
||||||
public ConfigHandler ConfigHandler => _configHandler;
|
public ConfigHandler ConfigHandler => _configHandler;
|
||||||
public MelonLoaderConfigHandler _configHandler;
|
public MelonLoaderConfigHandler _configHandler;
|
||||||
@ -67,7 +70,11 @@ namespace UnityExplorer
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var prop = type.GetProperty(property);
|
var prop = type.GetProperty(property);
|
||||||
|
#if ML_LEGACY
|
||||||
|
this.Harmony.Patch(prop.GetSetMethod(), prefix: prefix);
|
||||||
|
#else
|
||||||
HarmonyInstance.Patch(prop.GetSetMethod(), prefix: prefix);
|
HarmonyInstance.Patch(prop.GetSetMethod(), prefix: prefix);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#if ML
|
#if ML
|
||||||
|
|
||||||
|
#if !ML_LEGACY // ML 0.3.1+ config handler
|
||||||
|
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -75,4 +78,129 @@ namespace UnityExplorer.Loader.ML
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else // ML 0.3.0 config handler
|
||||||
|
|
||||||
|
using MelonLoader;
|
||||||
|
using MelonLoader.Tomlyn.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityExplorer.Core;
|
||||||
|
using UnityExplorer.Core.Config;
|
||||||
|
|
||||||
|
namespace UnityExplorer.Loader.ML
|
||||||
|
{
|
||||||
|
public class MelonLoaderConfigHandler : ConfigHandler
|
||||||
|
{
|
||||||
|
internal const string CTG_NAME = "UnityExplorer";
|
||||||
|
|
||||||
|
internal MelonPreferences_Category prefCategory;
|
||||||
|
|
||||||
|
public override void Init()
|
||||||
|
{
|
||||||
|
prefCategory = MelonPreferences.CreateCategory(CTG_NAME, $"{CTG_NAME} Settings");
|
||||||
|
|
||||||
|
try { MelonPreferences.Mapper.RegisterMapper(KeycodeReader, KeycodeWriter); } catch { }
|
||||||
|
try { MelonPreferences.Mapper.RegisterMapper(AnchorReader, AnchorWriter); } catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void LoadConfig()
|
||||||
|
{
|
||||||
|
foreach (var entry in ConfigManager.ConfigElements)
|
||||||
|
{
|
||||||
|
var key = entry.Key;
|
||||||
|
if (prefCategory.GetEntry(key) is MelonPreferences_Entry)
|
||||||
|
{
|
||||||
|
var config = entry.Value;
|
||||||
|
config.BoxedValue = config.GetLoaderConfigValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RegisterConfigElement<T>(ConfigElement<T> config)
|
||||||
|
{
|
||||||
|
var entry = prefCategory.CreateEntry(config.Name, config.Value, null, config.IsInternal) as MelonPreferences_Entry<T>;
|
||||||
|
|
||||||
|
entry.OnValueChangedUntyped += () =>
|
||||||
|
{
|
||||||
|
if ((entry.Value == null && config.Value == null) || config.Value.Equals(entry.Value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
config.Value = entry.Value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetConfigValue<T>(ConfigElement<T> config, T value)
|
||||||
|
{
|
||||||
|
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
|
||||||
|
{
|
||||||
|
entry.Value = value;
|
||||||
|
entry.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override T GetConfigValue<T>(ConfigElement<T> config)
|
||||||
|
{
|
||||||
|
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
|
||||||
|
return entry.Value;
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnAnyConfigChanged()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SaveConfig()
|
||||||
|
{
|
||||||
|
MelonPreferences.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enum config handlers
|
||||||
|
|
||||||
|
public static KeyCode KeycodeReader(TomlObject value)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
KeyCode kc = (KeyCode)Enum.Parse(typeof(KeyCode), (value as TomlString).Value);
|
||||||
|
|
||||||
|
if (kc == default)
|
||||||
|
throw new Exception();
|
||||||
|
|
||||||
|
return kc;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return KeyCode.F7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TomlObject KeycodeWriter(KeyCode value)
|
||||||
|
{
|
||||||
|
return MelonPreferences.Mapper.ToToml(value.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UI.UIManager.VerticalAnchor AnchorReader(TomlObject value)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (UI.UIManager.VerticalAnchor)Enum.Parse(typeof(UI.UIManager.VerticalAnchor), (value as TomlString).Value);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return UI.UIManager.VerticalAnchor.Top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TomlObject AnchorWriter(UI.UIManager.VerticalAnchor anchor)
|
||||||
|
{
|
||||||
|
return MelonPreferences.Mapper.ToToml(anchor.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -76,8 +76,6 @@ namespace UnityExplorer
|
|||||||
}
|
}
|
||||||
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); };
|
||||||
|
@ -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;
|
||||||
@ -114,7 +135,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 +143,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,16 +15,16 @@ 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.
|
||||||
@ -37,6 +37,7 @@ namespace UnityExplorer.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static ReadOnlyCollection<Scene> LoadedScenes => new ReadOnlyCollection<Scene>(allLoadedScenes);
|
public static ReadOnlyCollection<Scene> LoadedScenes => new ReadOnlyCollection<Scene>(allLoadedScenes);
|
||||||
private static readonly List<Scene> allLoadedScenes = 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.
|
||||||
@ -61,7 +62,7 @@ namespace UnityExplorer.Core
|
|||||||
public static event Action<ReadOnlyCollection<Scene>> OnLoadedScenesChanged;
|
public static event Action<ReadOnlyCollection<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 +83,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,46 +105,40 @@ 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
|
|
||||||
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();
|
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);
|
allLoadedScenes.Add(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always add the DontDestroyOnLoad scene and the "none" scene.
|
bool anyChange = confirmedCount != allLoadedScenes.Count;
|
||||||
|
|
||||||
allLoadedScenes.Add(DontDestroyScene);
|
allLoadedScenes.Add(DontDestroyScene);
|
||||||
allLoadedScenes.Add(AssetScene);
|
allLoadedScenes.Add(default);
|
||||||
|
previousLoadedScenes = new HashSet<Scene>(allLoadedScenes);
|
||||||
|
|
||||||
// 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)
|
||||||
@ -181,14 +158,14 @@ namespace UnityExplorer.Core
|
|||||||
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();
|
rootObjects = 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,39 +57,22 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
{
|
{
|
||||||
var results = new List<object>();
|
var results = new List<object>();
|
||||||
|
|
||||||
Type searchType;
|
Type searchType = null;
|
||||||
switch (context)
|
if (!string.IsNullOrEmpty(customTypeInput))
|
||||||
{
|
{
|
||||||
//case SearchContext.GameObject:
|
if (ReflectionUtility.GetTypeByName(customTypeInput) is Type customType)
|
||||||
// searchType = typeof(GameObject);
|
{
|
||||||
// break;
|
if (typeof(UnityEngine.Object).IsAssignableFrom(customType))
|
||||||
|
searchType = customType;
|
||||||
case SearchContext.UnityObject:
|
else
|
||||||
default:
|
ExplorerCore.LogWarning($"Custom type '{customType.FullName}' is not assignable from UnityEngine.Object!");
|
||||||
|
}
|
||||||
if (!string.IsNullOrEmpty(customTypeInput))
|
else
|
||||||
{
|
ExplorerCore.LogWarning($"Could not find any type by name '{customTypeInput}'!");
|
||||||
if (ReflectionUtility.GetTypeByName(customTypeInput) is Type customType)
|
|
||||||
{
|
|
||||||
if (typeof(UnityEngine.Object).IsAssignableFrom(customType))
|
|
||||||
{
|
|
||||||
searchType = customType;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ExplorerCore.LogWarning($"Custom type '{customType.FullName}' is not assignable from UnityEngine.Object!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
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>()
|
|
||||||
: obj.TryCast<Component>().gameObject;
|
|
||||||
|
|
||||||
if (go)
|
if (type == typeof(GameObject))
|
||||||
|
go = obj.TryCast<GameObject>();
|
||||||
|
else if (typeof(Component).IsAssignableFrom(type))
|
||||||
|
go = obj.TryCast<Component>()?.gameObject;
|
||||||
|
|
||||||
|
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.
@ -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,12 +63,17 @@ 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()
|
||||||
{
|
{
|
||||||
mainPanelRect.localPosition = Vector2.zero;
|
Rect.localPosition = Vector2.zero;
|
||||||
mainPanelRect.pivot = new Vector2(0f, 1f);
|
Rect.pivot = new Vector2(0f, 1f);
|
||||||
mainPanelRect.anchorMin = new Vector2(0.4f, 0.175f);
|
Rect.anchorMin = new Vector2(0.4f, 0.175f);
|
||||||
mainPanelRect.anchorMax = new Vector2(0.85f, 0.925f);
|
Rect.anchorMax = new Vector2(0.85f, 0.925f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ConstructPanelContent()
|
public override void ConstructPanelContent()
|
||||||
@ -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
|
||||||
{
|
{
|
||||||
@ -26,8 +26,8 @@ namespace UnityExplorer.UI.Panels
|
|||||||
public GameObject ContentHolder;
|
public GameObject ContentHolder;
|
||||||
public RectTransform ContentRect;
|
public RectTransform ContentRect;
|
||||||
|
|
||||||
public static float CurrentPanelWidth => Instance.mainPanelRect.rect.width;
|
public static float CurrentPanelWidth => Instance.Rect.rect.width;
|
||||||
public static float CurrentPanelHeight => Instance.mainPanelRect.rect.height;
|
public static float CurrentPanelHeight => Instance.Rect.rect.height;
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
@ -38,7 +38,7 @@ namespace UnityExplorer.UI.Panels
|
|||||||
{
|
{
|
||||||
base.OnFinishResize(panel);
|
base.OnFinishResize(panel);
|
||||||
|
|
||||||
InspectorManager.PanelWidth = this.mainPanelRect.rect.width;
|
InspectorManager.PanelWidth = this.Rect.rect.width;
|
||||||
InspectorManager.OnPanelResized(panel.rect.width);
|
InspectorManager.OnPanelResized(panel.rect.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +51,10 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
protected internal override void DoSetDefaultPosAndAnchors()
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
{
|
{
|
||||||
mainPanelRect.localPosition = Vector2.zero;
|
Rect.localPosition = Vector2.zero;
|
||||||
mainPanelRect.pivot = new Vector2(0f, 1f);
|
Rect.pivot = new Vector2(0f, 1f);
|
||||||
mainPanelRect.anchorMin = new Vector2(0.35f, 0.175f);
|
Rect.anchorMin = new Vector2(0.35f, 0.175f);
|
||||||
mainPanelRect.anchorMax = new Vector2(0.8f, 0.925f);
|
Rect.anchorMax = new Vector2(0.8f, 0.925f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ConstructPanelContent()
|
public override void ConstructPanelContent()
|
||||||
|
@ -51,7 +51,7 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
if (active && !DoneScrollPoolInit)
|
if (active && !DoneScrollPoolInit)
|
||||||
{
|
{
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(this.mainPanelRect);
|
LayoutRebuilder.ForceRebuildLayoutImmediate(this.Rect);
|
||||||
logScrollPool.Initialize(this);
|
logScrollPool.Initialize(this);
|
||||||
DoneScrollPoolInit = true;
|
DoneScrollPoolInit = true;
|
||||||
}
|
}
|
||||||
@ -158,10 +158,10 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
protected internal override void DoSetDefaultPosAndAnchors()
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
{
|
{
|
||||||
mainPanelRect.localPosition = Vector2.zero;
|
Rect.localPosition = Vector2.zero;
|
||||||
mainPanelRect.pivot = new Vector2(0f, 1f);
|
Rect.pivot = new Vector2(0f, 1f);
|
||||||
mainPanelRect.anchorMin = new Vector2(0.5f, 0.03f);
|
Rect.anchorMin = new Vector2(0.5f, 0.03f);
|
||||||
mainPanelRect.anchorMax = new Vector2(0.9f, 0.2f);
|
Rect.anchorMax = new Vector2(0.9f, 0.2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI Construction
|
// UI Construction
|
||||||
|
@ -11,8 +11,7 @@ using UnityEngine.UI;
|
|||||||
using UnityExplorer.Core;
|
using UnityExplorer.Core;
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.UI.Models;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.ObjectExplorer;
|
using UnityExplorer.ObjectExplorer;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Panels
|
namespace UnityExplorer.UI.Panels
|
||||||
@ -99,10 +98,10 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
protected internal override void DoSetDefaultPosAndAnchors()
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
{
|
{
|
||||||
mainPanelRect.localPosition = Vector2.zero;
|
Rect.localPosition = Vector2.zero;
|
||||||
mainPanelRect.pivot = new Vector2(0f, 1f);
|
Rect.pivot = new Vector2(0f, 1f);
|
||||||
mainPanelRect.anchorMin = new Vector2(0.125f, 0.175f);
|
Rect.anchorMin = new Vector2(0.125f, 0.175f);
|
||||||
mainPanelRect.anchorMax = new Vector2(0.325f, 0.925f);
|
Rect.anchorMax = new Vector2(0.325f, 0.925f);
|
||||||
//mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 350);
|
//mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 350);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ 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.CacheObject.Views;
|
using UnityExplorer.CacheObject.Views;
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Panels
|
namespace UnityExplorer.UI.Panels
|
||||||
@ -69,11 +69,11 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
protected internal override void DoSetDefaultPosAndAnchors()
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
{
|
{
|
||||||
mainPanelRect.localPosition = Vector2.zero;
|
Rect.localPosition = Vector2.zero;
|
||||||
mainPanelRect.pivot = new Vector2(0f, 1f);
|
Rect.pivot = new Vector2(0f, 1f);
|
||||||
mainPanelRect.anchorMin = new Vector2(0.5f, 0.1f);
|
Rect.anchorMin = new Vector2(0.5f, 0.1f);
|
||||||
mainPanelRect.anchorMax = new Vector2(0.5f, 0.85f);
|
Rect.anchorMax = new Vector2(0.5f, 0.85f);
|
||||||
mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 600f);
|
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 600f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI Construction
|
// UI Construction
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
using System.IO;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using UnityExplorer.UI.Models;
|
using UnityExplorer.UI.Models;
|
||||||
using System.Linq;
|
|
||||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Panels
|
namespace UnityExplorer.UI.Panels
|
||||||
@ -23,6 +23,7 @@ namespace UnityExplorer.UI.Panels
|
|||||||
{
|
{
|
||||||
s_resizeCursorObj.SetActive(false);
|
s_resizeCursorObj.SetActive(false);
|
||||||
wasAnyDragging = false;
|
wasAnyDragging = false;
|
||||||
|
Resizing = false;
|
||||||
|
|
||||||
foreach (var instance in Instances)
|
foreach (var instance in Instances)
|
||||||
{
|
{
|
||||||
@ -250,15 +251,9 @@ namespace UnityExplorer.UI.Panels
|
|||||||
Vector2 diff = (Vector2)mousePos - m_lastDragPosition;
|
Vector2 diff = (Vector2)mousePos - m_lastDragPosition;
|
||||||
m_lastDragPosition = mousePos;
|
m_lastDragPosition = mousePos;
|
||||||
|
|
||||||
var pos = Panel.localPosition + (Vector3)diff;
|
Panel.localPosition = Panel.localPosition + (Vector3)diff;
|
||||||
|
|
||||||
// Prevent panel going oustide screen bounds
|
UIPanel.EnsureValidPosition(Panel);
|
||||||
var halfW = Screen.width * 0.5f;
|
|
||||||
var halfH = Screen.height * 0.5f;
|
|
||||||
pos.x = Math.Max(-halfW, Math.Min(pos.x, halfW - Panel.rect.width));
|
|
||||||
pos.y = Math.Max(-halfH + Panel.rect.height, Math.Min(pos.y, halfH));
|
|
||||||
|
|
||||||
Panel.localPosition = pos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEndDrag()
|
public void OnEndDrag()
|
||||||
@ -425,6 +420,9 @@ namespace UnityExplorer.UI.Panels
|
|||||||
if ((Vector2)mousePos == m_lastResizePos)
|
if ((Vector2)mousePos == m_lastResizePos)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (mousePos.x < 0 || mousePos.y < 0 || mousePos.x > Screen.width || mousePos.y > Screen.height)
|
||||||
|
return;
|
||||||
|
|
||||||
m_lastResizePos = mousePos;
|
m_lastResizePos = mousePos;
|
||||||
|
|
||||||
float diffX = (float)((decimal)diff.x / Screen.width);
|
float diffX = (float)((decimal)diff.x / Screen.width);
|
||||||
|
@ -8,7 +8,6 @@ using UnityEngine.UI;
|
|||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
using UnityExplorer.UI.Models;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Panels
|
namespace UnityExplorer.UI.Panels
|
||||||
@ -44,8 +43,8 @@ namespace UnityExplorer.UI.Panels
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// check if our mouse is clicking inside the panel
|
// check if our mouse is clicking inside the panel
|
||||||
var pos = panel.mainPanelRect.InverseTransformPoint(mousePos);
|
var pos = panel.Rect.InverseTransformPoint(mousePos);
|
||||||
if (!panel.Enabled || !panel.mainPanelRect.rect.Contains(pos))
|
if (!panel.Enabled || !panel.Rect.rect.Contains(pos))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// if this is not the top panel, reorder and invoke the onchanged event
|
// if this is not the top panel, reorder and invoke the onchanged event
|
||||||
@ -88,9 +87,11 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
public override GameObject UIRoot => uiRoot;
|
public override GameObject UIRoot => uiRoot;
|
||||||
protected GameObject uiRoot;
|
protected GameObject uiRoot;
|
||||||
protected RectTransform mainPanelRect;
|
public RectTransform Rect;
|
||||||
public GameObject content;
|
public GameObject content;
|
||||||
|
|
||||||
|
public GameObject titleBar;
|
||||||
|
|
||||||
public abstract void ConstructPanelContent();
|
public abstract void ConstructPanelContent();
|
||||||
|
|
||||||
public virtual void OnFinishResize(RectTransform panel)
|
public virtual void OnFinishResize(RectTransform panel)
|
||||||
@ -136,14 +137,84 @@ namespace UnityExplorer.UI.Panels
|
|||||||
public void SetTransformDefaults()
|
public void SetTransformDefaults()
|
||||||
{
|
{
|
||||||
DoSetDefaultPosAndAnchors();
|
DoSetDefaultPosAndAnchors();
|
||||||
|
|
||||||
if (mainPanelRect.rect.width < MinWidth)
|
|
||||||
mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth);
|
|
||||||
if (mainPanelRect.rect.height < MinHeight)
|
|
||||||
mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameObject titleBar;
|
public void EnsureValidSize()
|
||||||
|
{
|
||||||
|
if (Rect.rect.width < MinWidth)
|
||||||
|
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth);
|
||||||
|
if (Rect.rect.height < MinHeight)
|
||||||
|
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EnsureValidPosition(RectTransform panel)
|
||||||
|
{
|
||||||
|
var pos = panel.localPosition;
|
||||||
|
|
||||||
|
// Prevent panel going oustide screen bounds
|
||||||
|
var halfW = Screen.width * 0.5f;
|
||||||
|
var halfH = Screen.height * 0.5f;
|
||||||
|
|
||||||
|
pos.x = Math.Max(-halfW - panel.rect.width + 50, Math.Min(pos.x, halfW - 50));
|
||||||
|
pos.y = Math.Max(-halfH + 50, Math.Min(pos.y, halfH));
|
||||||
|
|
||||||
|
panel.localPosition = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Save Data
|
||||||
|
|
||||||
|
public abstract void DoSaveToConfigElement();
|
||||||
|
|
||||||
|
public void SaveToConfigManager()
|
||||||
|
{
|
||||||
|
if (UIManager.Initializing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DoSaveToConfigElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract string GetSaveDataFromConfigManager();
|
||||||
|
|
||||||
|
public bool ApplyingSaveData { get; set; }
|
||||||
|
|
||||||
|
public virtual string ToSaveData()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return $"{ShouldSaveActiveState && Enabled}" +
|
||||||
|
$"|{Rect.RectAnchorsToString()}" +
|
||||||
|
$"|{Rect.RectPositionToString()}";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception generating Panel save data: {ex}");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void ApplySaveData(string data)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(data))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var split = data.Split('|');
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Rect.SetAnchorsFromString(split[1]);
|
||||||
|
Rect.SetPositionFromString(split[2]);
|
||||||
|
UIManager.SetPanelActive(this.PanelType, bool.Parse(split[0]));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning("Invalid or corrupt panel save data! Restoring to default.");
|
||||||
|
SetTransformDefaults();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// UI Construction
|
||||||
|
|
||||||
public void ConstructUI()
|
public void ConstructUI()
|
||||||
{
|
{
|
||||||
@ -153,7 +224,7 @@ namespace UnityExplorer.UI.Panels
|
|||||||
{
|
{
|
||||||
// create navbar button
|
// create navbar button
|
||||||
|
|
||||||
NavButton = UIFactory.CreateButton(UIManager.NavbarButtonHolder, $"Button_{PanelType}", Name);
|
NavButton = UIFactory.CreateButton(UIManager.NavbarTabButtonHolder, $"Button_{PanelType}", Name);
|
||||||
var navBtn = NavButton.Component.gameObject;
|
var navBtn = NavButton.Component.gameObject;
|
||||||
navBtn.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
navBtn.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navBtn, false, true, true, true, 0, 0, 0, 5, 5, TextAnchor.MiddleCenter);
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navBtn, false, true, true, true, 0, 0, 0, 5, 5, TextAnchor.MiddleCenter);
|
||||||
@ -168,7 +239,7 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
// create core canvas
|
// create core canvas
|
||||||
uiRoot = UIFactory.CreatePanel(Name, out GameObject panelContent);
|
uiRoot = UIFactory.CreatePanel(Name, out GameObject panelContent);
|
||||||
mainPanelRect = this.uiRoot.GetComponent<RectTransform>();
|
Rect = this.uiRoot.GetComponent<RectTransform>();
|
||||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.uiRoot, false, false, true, true, 0, 2, 2, 2, 2, TextAnchor.UpperLeft);
|
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.uiRoot, false, false, true, true, 0, 2, 2, 2, 2, TextAnchor.UpperLeft);
|
||||||
|
|
||||||
int id = this.uiRoot.transform.GetInstanceID();
|
int id = this.uiRoot.transform.GetInstanceID();
|
||||||
@ -177,9 +248,6 @@ namespace UnityExplorer.UI.Panels
|
|||||||
content = panelContent;
|
content = panelContent;
|
||||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.content, false, false, true, true, 2, 2, 2, 2, 2, TextAnchor.UpperLeft);
|
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.content, false, false, true, true, 2, 2, 2, 2, 2, TextAnchor.UpperLeft);
|
||||||
|
|
||||||
// always apply default pos and anchors (save data may only be partial)
|
|
||||||
SetTransformDefaults();
|
|
||||||
|
|
||||||
// Title bar
|
// Title bar
|
||||||
titleBar = UIFactory.CreateHorizontalGroup(content, "TitleBar", false, true, true, true, 2,
|
titleBar = UIFactory.CreateHorizontalGroup(content, "TitleBar", false, true, true, true, 2,
|
||||||
new Vector4(2, 2, 2, 2), new Color(0.06f, 0.06f, 0.06f));
|
new Vector4(2, 2, 2, 2), new Color(0.06f, 0.06f, 0.06f));
|
||||||
@ -210,7 +278,7 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
// Panel dragger
|
// Panel dragger
|
||||||
|
|
||||||
Dragger = new PanelDragger(titleBar.GetComponent<RectTransform>(), mainPanelRect, this);
|
Dragger = new PanelDragger(titleBar.GetComponent<RectTransform>(), Rect, this);
|
||||||
Dragger.OnFinishResize += OnFinishResize;
|
Dragger.OnFinishResize += OnFinishResize;
|
||||||
Dragger.OnFinishDrag += OnFinishDrag;
|
Dragger.OnFinishDrag += OnFinishDrag;
|
||||||
|
|
||||||
@ -223,6 +291,7 @@ namespace UnityExplorer.UI.Panels
|
|||||||
UIManager.SetPanelActive(this.PanelType, ShowByDefault);
|
UIManager.SetPanelActive(this.PanelType, ShowByDefault);
|
||||||
|
|
||||||
ApplyingSaveData = true;
|
ApplyingSaveData = true;
|
||||||
|
SetTransformDefaults();
|
||||||
// apply panel save data or revert to default
|
// apply panel save data or revert to default
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -234,6 +303,13 @@ namespace UnityExplorer.UI.Panels
|
|||||||
SetTransformDefaults();
|
SetTransformDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LayoutRebuilder.ForceRebuildLayoutImmediate(this.Rect);
|
||||||
|
|
||||||
|
// ensure initialized position is valid
|
||||||
|
EnsureValidSize();
|
||||||
|
EnsureValidPosition(this.Rect);
|
||||||
|
|
||||||
|
// update dragger and save data
|
||||||
Dragger.OnEndResize();
|
Dragger.OnEndResize();
|
||||||
|
|
||||||
// simple listener for saving enabled state
|
// simple listener for saving enabled state
|
||||||
@ -241,61 +317,11 @@ namespace UnityExplorer.UI.Panels
|
|||||||
{
|
{
|
||||||
SaveToConfigManager();
|
SaveToConfigManager();
|
||||||
};
|
};
|
||||||
|
|
||||||
ApplyingSaveData = false;
|
ApplyingSaveData = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ConstructUI(GameObject parent) => ConstructUI();
|
public override void ConstructUI(GameObject parent) => ConstructUI();
|
||||||
|
|
||||||
// SAVE DATA
|
|
||||||
|
|
||||||
public abstract void DoSaveToConfigElement();
|
|
||||||
|
|
||||||
public void SaveToConfigManager()
|
|
||||||
{
|
|
||||||
if (UIManager.Initializing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
DoSaveToConfigElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract string GetSaveDataFromConfigManager();
|
|
||||||
|
|
||||||
public bool ApplyingSaveData { get; set; }
|
|
||||||
|
|
||||||
public virtual string ToSaveData()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return $"{ShouldSaveActiveState && Enabled}" +
|
|
||||||
$"|{mainPanelRect.RectAnchorsToString()}" +
|
|
||||||
$"|{mainPanelRect.RectPositionToString()}";
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ExplorerCore.LogWarning($"Exception generating Panel save data: {ex}");
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void ApplySaveData(string data)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(data))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var split = data.Split('|');
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
mainPanelRect.SetAnchorsFromString(split[1]);
|
|
||||||
mainPanelRect.SetPositionFromString(split[2]);
|
|
||||||
UIManager.SetPanelActive(this.PanelType, bool.Parse(split[0]));
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
ExplorerCore.LogWarning("Invalid or corrupt panel save data! Restoring to default.");
|
|
||||||
SetTransformDefaults();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region WINDOW ANCHORS / POSITION HELPERS
|
#region WINDOW ANCHORS / POSITION HELPERS
|
||||||
|
@ -4,9 +4,16 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.ObjectPool
|
namespace UnityExplorer.UI
|
||||||
{
|
{
|
||||||
// Abstract non-generic class, handles the pool dictionary and interfacing with the generic pools.
|
public interface IPooledObject
|
||||||
|
{
|
||||||
|
GameObject UIRoot { get; set; }
|
||||||
|
float DefaultHeight { get; }
|
||||||
|
|
||||||
|
GameObject CreateContent(GameObject parent);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract class Pool
|
public abstract class Pool
|
||||||
{
|
{
|
||||||
protected static readonly Dictionary<Type, Pool> pools = new Dictionary<Type, Pool>();
|
protected static readonly Dictionary<Type, Pool> pools = new Dictionary<Type, Pool>();
|
||||||
@ -39,7 +46,6 @@ namespace UnityExplorer.UI.ObjectPool
|
|||||||
protected abstract void TryReturn(IPooledObject obj);
|
protected abstract void TryReturn(IPooledObject obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each generic implementation has its own pool, business logic is here
|
|
||||||
public class Pool<T> : Pool where T : IPooledObject
|
public class Pool<T> : Pool where T : IPooledObject
|
||||||
{
|
{
|
||||||
public static Pool<T> GetPool() => (Pool<T>)GetPool(typeof(T));
|
public static Pool<T> GetPool() => (Pool<T>)GetPool(typeof(T));
|
@ -5,7 +5,6 @@ using UnityEngine.UI;
|
|||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.Core.Runtime;
|
using UnityExplorer.Core.Runtime;
|
||||||
using UnityExplorer.UI.Models;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
using UnityExplorer.UI.Widgets;
|
using UnityExplorer.UI.Widgets;
|
||||||
|
|
||||||
namespace UnityExplorer.UI
|
namespace UnityExplorer.UI
|
||||||
@ -410,56 +409,49 @@ namespace UnityExplorer.UI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a Toggle control.
|
/// Create a Toggle control.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static GameObject CreateToggle(GameObject parent, string name, out Toggle toggle, out Text text, Color bgColor = default)
|
public static GameObject CreateToggle(GameObject parent, string name, out Toggle toggle, out Text text, Color bgColor = default,
|
||||||
|
int checkWidth = 20, int checkHeight = 20)
|
||||||
{
|
{
|
||||||
|
// Main obj
|
||||||
GameObject toggleObj = CreateUIObject(name, parent, _smallElementSize);
|
GameObject toggleObj = CreateUIObject(name, parent, _smallElementSize);
|
||||||
|
SetLayoutGroup<HorizontalLayoutGroup>(toggleObj, false, false, true, true, 5, 0,0,0,0, childAlignment: TextAnchor.MiddleLeft);
|
||||||
GameObject bgObj = CreateUIObject("Background", toggleObj);
|
|
||||||
GameObject checkObj = CreateUIObject("Checkmark", bgObj);
|
|
||||||
GameObject labelObj = CreateUIObject("Label", toggleObj);
|
|
||||||
|
|
||||||
toggle = toggleObj.AddComponent<Toggle>();
|
toggle = toggleObj.AddComponent<Toggle>();
|
||||||
toggle.isOn = true;
|
toggle.isOn = true;
|
||||||
|
SetDefaultSelectableColors(toggle);
|
||||||
|
// need a second reference so we can use it inside the lambda, since 'toggle' is an out var.
|
||||||
|
Toggle t2 = toggle;
|
||||||
|
toggle.onValueChanged.AddListener((bool _) => { t2.OnDeselect(null); });
|
||||||
|
|
||||||
// second reference so we can use it inside the lambda, 'toggle' is an out var.
|
// Check mark background
|
||||||
Toggle toggleComp = toggle;
|
|
||||||
toggle.onValueChanged.AddListener(Deselect);
|
|
||||||
void Deselect(bool _)
|
|
||||||
{
|
|
||||||
toggleComp.OnDeselect(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Image bgImage = bgObj.AddComponent<Image>();
|
GameObject checkBgObj = CreateUIObject("Background", toggleObj);
|
||||||
|
Image bgImage = checkBgObj.AddComponent<Image>();
|
||||||
bgImage.color = bgColor == default ? new Color(0.04f, 0.04f, 0.04f, 0.75f) : bgColor;
|
bgImage.color = bgColor == default ? new Color(0.04f, 0.04f, 0.04f, 0.75f) : bgColor;
|
||||||
|
|
||||||
Image checkImage = checkObj.AddComponent<Image>();
|
SetLayoutGroup<HorizontalLayoutGroup>(checkBgObj, true, true, true, true, 0, 2, 2, 2, 2);
|
||||||
|
SetLayoutElement(checkBgObj, minWidth: checkWidth, flexibleWidth: 0, minHeight: checkHeight, flexibleHeight: 0);
|
||||||
|
|
||||||
|
// Check mark image
|
||||||
|
|
||||||
|
GameObject checkMarkObj = CreateUIObject("Checkmark", checkBgObj);
|
||||||
|
Image checkImage = checkMarkObj.AddComponent<Image>();
|
||||||
checkImage.color = new Color(0.8f, 1, 0.8f, 0.3f);
|
checkImage.color = new Color(0.8f, 1, 0.8f, 0.3f);
|
||||||
|
|
||||||
|
// Label
|
||||||
|
|
||||||
|
GameObject labelObj = CreateUIObject("Label", toggleObj);
|
||||||
text = labelObj.AddComponent<Text>();
|
text = labelObj.AddComponent<Text>();
|
||||||
text.text = "Toggle";
|
text.text = "";
|
||||||
|
text.alignment = TextAnchor.MiddleLeft;
|
||||||
SetDefaultTextValues(text);
|
SetDefaultTextValues(text);
|
||||||
|
|
||||||
|
SetLayoutElement(labelObj, minWidth: 0, flexibleWidth: 0, minHeight: checkHeight, flexibleHeight: 0);
|
||||||
|
|
||||||
|
// References
|
||||||
|
|
||||||
toggle.graphic = checkImage;
|
toggle.graphic = checkImage;
|
||||||
toggle.targetGraphic = bgImage;
|
toggle.targetGraphic = bgImage;
|
||||||
SetDefaultSelectableColors(toggle);
|
|
||||||
|
|
||||||
RectTransform bgRect = bgObj.GetComponent<RectTransform>();
|
|
||||||
bgRect.anchorMin = new Vector2(0f, 1f);
|
|
||||||
bgRect.anchorMax = new Vector2(0f, 1f);
|
|
||||||
bgRect.anchoredPosition = new Vector2(13f, -13f);
|
|
||||||
bgRect.sizeDelta = new Vector2(20f, 20f);
|
|
||||||
|
|
||||||
RectTransform checkRect = checkObj.GetComponent<RectTransform>();
|
|
||||||
checkRect.anchorMin = new Vector2(0.5f, 0.5f);
|
|
||||||
checkRect.anchorMax = new Vector2(0.5f, 0.5f);
|
|
||||||
checkRect.anchoredPosition = Vector2.zero;
|
|
||||||
checkRect.sizeDelta = new Vector2(14f, 14f);
|
|
||||||
|
|
||||||
RectTransform labelRect = labelObj.GetComponent<RectTransform>();
|
|
||||||
labelRect.anchorMin = new Vector2(0f, 0f);
|
|
||||||
labelRect.anchorMax = new Vector2(1f, 1f);
|
|
||||||
labelRect.offsetMin = new Vector2(28f, 2f);
|
|
||||||
labelRect.offsetMax = new Vector2(-5f, -5f);
|
|
||||||
return toggleObj;
|
return toggleObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,7 +722,7 @@ namespace UnityExplorer.UI
|
|||||||
|
|
||||||
var sliderContainer = CreateVerticalGroup(mainObj, "SliderContainer",
|
var sliderContainer = CreateVerticalGroup(mainObj, "SliderContainer",
|
||||||
false, false, true, true, 0, default, new Color(0.05f, 0.05f, 0.05f));
|
false, false, true, true, 0, default, new Color(0.05f, 0.05f, 0.05f));
|
||||||
SetLayoutElement(sliderContainer, minWidth: 25, flexibleWidth:0, flexibleHeight: 9999);
|
SetLayoutElement(sliderContainer, minWidth: 25, flexibleWidth: 0, flexibleHeight: 9999);
|
||||||
sliderContainer.AddComponent<Mask>();
|
sliderContainer.AddComponent<Mask>();
|
||||||
|
|
||||||
CreateSliderScrollbar(sliderContainer, out Slider slider);
|
CreateSliderScrollbar(sliderContainer, out Slider slider);
|
||||||
|
@ -8,11 +8,10 @@ using UnityEngine.EventSystems;
|
|||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Core.Config;
|
using UnityExplorer.Core.Config;
|
||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
using UnityExplorer.UI.CSConsole;
|
using UnityExplorer.CSConsole;
|
||||||
using UnityExplorer.UI.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
using UnityExplorer.UI.Models;
|
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;
|
||||||
|
|
||||||
@ -56,9 +55,15 @@ namespace UnityExplorer.UI
|
|||||||
internal static Shader BackupShader { get; private set; }
|
internal static Shader BackupShader { get; private set; }
|
||||||
|
|
||||||
public static RectTransform NavBarRect;
|
public static RectTransform NavBarRect;
|
||||||
public static GameObject NavbarButtonHolder;
|
public static GameObject NavbarTabButtonHolder;
|
||||||
public static Dropdown MouseInspectDropdown;
|
public static Dropdown MouseInspectDropdown;
|
||||||
|
|
||||||
|
private static ButtonRef closeBtn;
|
||||||
|
private static ButtonRef pauseBtn;
|
||||||
|
private static InputFieldRef timeInput;
|
||||||
|
private static bool pauseButtonPausing;
|
||||||
|
private static float lastTimeScale;
|
||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
internal static readonly Color enabledButtonColor = new Color(0.2f, 0.4f, 0.28f);
|
internal static readonly Color enabledButtonColor = new Color(0.2f, 0.4f, 0.28f);
|
||||||
internal static readonly Color disabledButtonColor = new Color(0.25f, 0.25f, 0.25f);
|
internal static readonly Color disabledButtonColor = new Color(0.25f, 0.25f, 0.25f);
|
||||||
@ -81,6 +86,105 @@ namespace UnityExplorer.UI
|
|||||||
}
|
}
|
||||||
public static bool s_showMenu = true;
|
public static bool s_showMenu = true;
|
||||||
|
|
||||||
|
// Initialization
|
||||||
|
|
||||||
|
internal static void InitUI()
|
||||||
|
{
|
||||||
|
LoadBundle();
|
||||||
|
|
||||||
|
UIFactory.Init();
|
||||||
|
|
||||||
|
CreateRootCanvas();
|
||||||
|
|
||||||
|
// Global UI Pool Holder
|
||||||
|
PoolHolder = new GameObject("PoolHolder");
|
||||||
|
PoolHolder.transform.parent = CanvasRoot.transform;
|
||||||
|
PoolHolder.SetActive(false);
|
||||||
|
|
||||||
|
CreateTopNavBar();
|
||||||
|
|
||||||
|
UIPanels.Add(Panels.AutoCompleter, new AutoCompleteModal());
|
||||||
|
UIPanels.Add(Panels.ObjectExplorer, new ObjectExplorerPanel());
|
||||||
|
UIPanels.Add(Panels.Inspector, new InspectorPanel());
|
||||||
|
UIPanels.Add(Panels.CSConsole, new CSConsolePanel());
|
||||||
|
UIPanels.Add(Panels.ConsoleLog, new LogPanel());
|
||||||
|
UIPanels.Add(Panels.Options, new OptionsPanel());
|
||||||
|
UIPanels.Add(Panels.MouseInspector, new InspectUnderMouse());
|
||||||
|
|
||||||
|
foreach (var panel in UIPanels.Values)
|
||||||
|
panel.ConstructUI();
|
||||||
|
|
||||||
|
ConsoleController.Init();
|
||||||
|
|
||||||
|
ShowMenu = !ConfigManager.Hide_On_Startup.Value;
|
||||||
|
|
||||||
|
lastScreenWidth = Screen.width;
|
||||||
|
lastScreenHeight = Screen.height;
|
||||||
|
|
||||||
|
Initializing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main UI Update loop
|
||||||
|
|
||||||
|
private static int lastScreenWidth;
|
||||||
|
private static int lastScreenHeight;
|
||||||
|
|
||||||
|
public static void Update()
|
||||||
|
{
|
||||||
|
if (!CanvasRoot || Initializing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// if doing Mouse Inspect, update that and return.
|
||||||
|
if (InspectUnderMouse.Inspecting)
|
||||||
|
{
|
||||||
|
InspectUnderMouse.Instance.UpdateInspect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check master toggle
|
||||||
|
if (InputManager.GetKeyDown(ConfigManager.Master_Toggle.Value))
|
||||||
|
ShowMenu = !ShowMenu;
|
||||||
|
|
||||||
|
// return if menu closed
|
||||||
|
if (!ShowMenu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check forceUnlockMouse toggle
|
||||||
|
if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value))
|
||||||
|
CursorUnlocker.Unlock = !CursorUnlocker.Unlock;
|
||||||
|
|
||||||
|
// check event system state
|
||||||
|
if (!ConfigManager.Disable_EventSystem_Override.Value && EventSystem.current != EventSys)
|
||||||
|
CursorUnlocker.SetEventSystem();
|
||||||
|
|
||||||
|
// update focused panel
|
||||||
|
UIPanel.UpdateFocus();
|
||||||
|
// update UI model instances
|
||||||
|
PanelDragger.UpdateInstances();
|
||||||
|
InputFieldRef.UpdateInstances();
|
||||||
|
UIBehaviourModel.UpdateInstances();
|
||||||
|
|
||||||
|
// update the timescale value
|
||||||
|
if (!timeInput.Component.isFocused && lastTimeScale != Time.timeScale)
|
||||||
|
{
|
||||||
|
if (pauseButtonPausing && Time.timeScale != 0.0f)
|
||||||
|
{
|
||||||
|
pauseButtonPausing = false;
|
||||||
|
OnPauseButtonToggled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pauseButtonPausing)
|
||||||
|
{
|
||||||
|
timeInput.Text = Time.timeScale.ToString("F2");
|
||||||
|
lastTimeScale = Time.timeScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check screen dimension change
|
||||||
|
if (Screen.width != lastScreenWidth || Screen.height != lastScreenHeight)
|
||||||
|
OnScreenDimensionsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
// Panels
|
// Panels
|
||||||
|
|
||||||
public static UIPanel GetPanel(Panels panel)
|
public static UIPanel GetPanel(Panels panel)
|
||||||
@ -121,72 +225,89 @@ namespace UnityExplorer.UI
|
|||||||
SetPanelActive(panel, value);
|
SetPanelActive(panel, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main UI Update loop
|
// navbar
|
||||||
|
|
||||||
public static void Update()
|
public static void SetNavBarAnchor()
|
||||||
{
|
{
|
||||||
if (!CanvasRoot || Initializing)
|
switch (NavbarAnchor)
|
||||||
|
{
|
||||||
|
case VerticalAnchor.Top:
|
||||||
|
NavBarRect.anchorMin = new Vector2(0.5f, 1f);
|
||||||
|
NavBarRect.anchorMax = new Vector2(0.5f, 1f);
|
||||||
|
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 0);
|
||||||
|
NavBarRect.sizeDelta = new Vector2(1000f, 35f);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VerticalAnchor.Bottom:
|
||||||
|
NavBarRect.anchorMin = new Vector2(0.5f, 0f);
|
||||||
|
NavBarRect.anchorMax = new Vector2(0.5f, 0f);
|
||||||
|
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 35);
|
||||||
|
NavBarRect.sizeDelta = new Vector2(1000f, 35f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// listeners
|
||||||
|
|
||||||
|
private static void OnScreenDimensionsChanged()
|
||||||
|
{
|
||||||
|
lastScreenWidth = Screen.width;
|
||||||
|
lastScreenHeight = Screen.height;
|
||||||
|
|
||||||
|
foreach (var panel in UIPanels)
|
||||||
|
{
|
||||||
|
panel.Value.EnsureValidSize();
|
||||||
|
UIPanel.EnsureValidPosition(panel.Value.Rect);
|
||||||
|
panel.Value.Dragger.OnEndResize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnCloseButtonClicked()
|
||||||
|
{
|
||||||
|
ShowMenu = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Master_Toggle_OnValueChanged(KeyCode val)
|
||||||
|
{
|
||||||
|
closeBtn.ButtonText.text = val.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnTimeInputEndEdit(string val)
|
||||||
|
{
|
||||||
|
if (pauseButtonPausing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (InspectUnderMouse.Inspecting)
|
if (float.TryParse(val, out float f))
|
||||||
{
|
{
|
||||||
InspectUnderMouse.Instance.UpdateInspect();
|
Time.timeScale = f;
|
||||||
return;
|
lastTimeScale = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (InputManager.GetKeyDown(ConfigManager.Master_Toggle.Value))
|
timeInput.Text = Time.timeScale.ToString("F2");
|
||||||
ShowMenu = !ShowMenu;
|
|
||||||
|
|
||||||
if (!ShowMenu)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value))
|
|
||||||
CursorUnlocker.Unlock = !CursorUnlocker.Unlock;
|
|
||||||
|
|
||||||
if (EventSystem.current != EventSys)
|
|
||||||
CursorUnlocker.SetEventSystem();
|
|
||||||
|
|
||||||
UIPanel.UpdateFocus();
|
|
||||||
PanelDragger.UpdateInstances();
|
|
||||||
InputFieldRef.UpdateInstances();
|
|
||||||
UIBehaviourModel.UpdateInstances();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialization and UI Construction
|
private static void OnPauseButtonClicked()
|
||||||
|
|
||||||
internal static void InitUI()
|
|
||||||
{
|
{
|
||||||
LoadBundle();
|
pauseButtonPausing = !pauseButtonPausing;
|
||||||
|
|
||||||
UIFactory.Init();
|
Time.timeScale = pauseButtonPausing ? 0f : lastTimeScale;
|
||||||
|
|
||||||
CreateRootCanvas();
|
OnPauseButtonToggled();
|
||||||
|
|
||||||
// Global UI Pool Holder
|
|
||||||
PoolHolder = new GameObject("PoolHolder");
|
|
||||||
PoolHolder.transform.parent = CanvasRoot.transform;
|
|
||||||
PoolHolder.SetActive(false);
|
|
||||||
|
|
||||||
CreateTopNavBar();
|
|
||||||
|
|
||||||
UIPanels.Add(Panels.AutoCompleter, new AutoCompleteModal());
|
|
||||||
UIPanels.Add(Panels.ObjectExplorer, new ObjectExplorerPanel());
|
|
||||||
UIPanels.Add(Panels.Inspector, new InspectorPanel());
|
|
||||||
UIPanels.Add(Panels.CSConsole, new CSConsolePanel());
|
|
||||||
UIPanels.Add(Panels.ConsoleLog, new LogPanel());
|
|
||||||
UIPanels.Add(Panels.Options, new OptionsPanel());
|
|
||||||
UIPanels.Add(Panels.MouseInspector, new InspectUnderMouse());
|
|
||||||
|
|
||||||
foreach (var panel in UIPanels.Values)
|
|
||||||
panel.ConstructUI();
|
|
||||||
|
|
||||||
ConsoleController.Init();
|
|
||||||
|
|
||||||
ShowMenu = !ConfigManager.Hide_On_Startup.Value;
|
|
||||||
|
|
||||||
Initializing = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void OnPauseButtonToggled()
|
||||||
|
{
|
||||||
|
timeInput.Component.text = Time.timeScale.ToString("F2");
|
||||||
|
timeInput.Component.readOnly = pauseButtonPausing;
|
||||||
|
timeInput.Component.textComponent.color = pauseButtonPausing ? Color.grey : Color.white;
|
||||||
|
|
||||||
|
Color color = pauseButtonPausing ? new Color(0.3f, 0.3f, 0.2f) : new Color(0.2f, 0.2f, 0.2f);
|
||||||
|
RuntimeProvider.Instance.SetColorBlock(pauseBtn.Component, color, color * 1.2f, color * 0.7f);
|
||||||
|
pauseBtn.ButtonText.text = pauseButtonPausing ? "►" : "||";
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI Construction
|
||||||
|
|
||||||
private static void CreateRootCanvas()
|
private static void CreateRootCanvas()
|
||||||
{
|
{
|
||||||
CanvasRoot = new GameObject("ExplorerCanvas");
|
CanvasRoot = new GameObject("ExplorerCanvas");
|
||||||
@ -221,30 +342,10 @@ namespace UnityExplorer.UI
|
|||||||
PanelHolder.transform.SetAsFirstSibling();
|
PanelHolder.transform.SetAsFirstSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetNavBarAnchor()
|
|
||||||
{
|
|
||||||
switch (NavbarAnchor)
|
|
||||||
{
|
|
||||||
case VerticalAnchor.Top:
|
|
||||||
NavBarRect.anchorMin = new Vector2(0.5f, 1f);
|
|
||||||
NavBarRect.anchorMax = new Vector2(0.5f, 1f);
|
|
||||||
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 0);
|
|
||||||
NavBarRect.sizeDelta = new Vector2(900f, 35f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VerticalAnchor.Bottom:
|
|
||||||
NavBarRect.anchorMin = new Vector2(0.5f, 0f);
|
|
||||||
NavBarRect.anchorMax = new Vector2(0.5f, 0f);
|
|
||||||
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 35);
|
|
||||||
NavBarRect.sizeDelta = new Vector2(900f, 35f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CreateTopNavBar()
|
private static void CreateTopNavBar()
|
||||||
{
|
{
|
||||||
var navbarPanel = UIFactory.CreateUIObject("MainNavbar", CanvasRoot);
|
var navbarPanel = UIFactory.CreateUIObject("MainNavbar", CanvasRoot);
|
||||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navbarPanel, false, true, true, true, 5, 4, 4, 4, 4, TextAnchor.MiddleCenter);
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navbarPanel, false, false, true, true, 5, 4, 4, 4, 4, TextAnchor.MiddleCenter);
|
||||||
navbarPanel.AddComponent<Image>().color = new Color(0.1f, 0.1f, 0.1f);
|
navbarPanel.AddComponent<Image>().color = new Color(0.1f, 0.1f, 0.1f);
|
||||||
NavBarRect = navbarPanel.GetComponent<RectTransform>();
|
NavBarRect = navbarPanel.GetComponent<RectTransform>();
|
||||||
NavBarRect.pivot = new Vector2(0.5f, 1f);
|
NavBarRect.pivot = new Vector2(0.5f, 1f);
|
||||||
@ -260,14 +361,28 @@ namespace UnityExplorer.UI
|
|||||||
// UnityExplorer title
|
// UnityExplorer title
|
||||||
|
|
||||||
string titleTxt = $"{ExplorerCore.NAME} <i><color=grey>{ExplorerCore.VERSION}</color></i>";
|
string titleTxt = $"{ExplorerCore.NAME} <i><color=grey>{ExplorerCore.VERSION}</color></i>";
|
||||||
var title = UIFactory.CreateLabel(navbarPanel, "Title", titleTxt, TextAnchor.MiddleLeft, default, true, 18);
|
var title = UIFactory.CreateLabel(navbarPanel, "Title", titleTxt, TextAnchor.MiddleLeft, default, true, 17);
|
||||||
UIFactory.SetLayoutElement(title.gameObject, minWidth: 180, flexibleWidth: 0);
|
UIFactory.SetLayoutElement(title.gameObject, minWidth: 170, flexibleWidth: 0);
|
||||||
|
|
||||||
// Navbar
|
// panel tabs
|
||||||
|
|
||||||
NavbarButtonHolder = UIFactory.CreateUIObject("NavButtonHolder", navbarPanel);
|
NavbarTabButtonHolder = UIFactory.CreateUIObject("NavTabButtonHolder", navbarPanel);
|
||||||
UIFactory.SetLayoutElement(NavbarButtonHolder, flexibleHeight: 999, flexibleWidth: 999);
|
UIFactory.SetLayoutElement(NavbarTabButtonHolder, minHeight: 25, flexibleHeight: 999, flexibleWidth: 999);
|
||||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(NavbarButtonHolder, false, true, true, true, 4, 2, 2, 2, 2);
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(NavbarTabButtonHolder, false, true, true, true, 4, 2, 2, 2, 2);
|
||||||
|
|
||||||
|
// Time controls
|
||||||
|
|
||||||
|
var timeLabel = UIFactory.CreateLabel(navbarPanel, "TimeLabel", "Time:", TextAnchor.MiddleRight, Color.grey);
|
||||||
|
UIFactory.SetLayoutElement(timeLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||||
|
|
||||||
|
timeInput = UIFactory.CreateInputField(navbarPanel, "TimeInput", "timeScale");
|
||||||
|
UIFactory.SetLayoutElement(timeInput.Component.gameObject, minHeight: 25, minWidth: 40);
|
||||||
|
timeInput.Text = Time.timeScale.ToString("F2");
|
||||||
|
timeInput.Component.GetOnEndEdit().AddListener(OnTimeInputEndEdit);
|
||||||
|
|
||||||
|
pauseBtn = UIFactory.CreateButton(navbarPanel, "PauseButton", "||", new Color(0.2f, 0.2f, 0.2f));
|
||||||
|
UIFactory.SetLayoutElement(pauseBtn.Component.gameObject, minHeight: 25, minWidth: 25);
|
||||||
|
pauseBtn.OnClick += OnPauseButtonClicked;
|
||||||
|
|
||||||
// Inspect under mouse dropdown
|
// Inspect under mouse dropdown
|
||||||
|
|
||||||
@ -280,14 +395,13 @@ namespace UnityExplorer.UI
|
|||||||
|
|
||||||
// Hide menu button
|
// Hide menu button
|
||||||
|
|
||||||
var closeBtn = UIFactory.CreateButton(navbarPanel, "CloseButton", ConfigManager.Master_Toggle.Value.ToString());
|
closeBtn = UIFactory.CreateButton(navbarPanel, "CloseButton", ConfigManager.Master_Toggle.Value.ToString());
|
||||||
UIFactory.SetLayoutElement(closeBtn.Component.gameObject, minHeight: 25, minWidth: 80, flexibleWidth: 0);
|
UIFactory.SetLayoutElement(closeBtn.Component.gameObject, minHeight: 25, minWidth: 80, flexibleWidth: 0);
|
||||||
RuntimeProvider.Instance.SetColorBlock(closeBtn.Component, new Color(0.63f, 0.32f, 0.31f),
|
RuntimeProvider.Instance.SetColorBlock(closeBtn.Component, new Color(0.63f, 0.32f, 0.31f),
|
||||||
new Color(0.81f, 0.25f, 0.2f), new Color(0.6f, 0.18f, 0.16f));
|
new Color(0.81f, 0.25f, 0.2f), new Color(0.6f, 0.18f, 0.16f));
|
||||||
|
|
||||||
ConfigManager.Master_Toggle.OnValueChanged += (KeyCode val) => { closeBtn.ButtonText.text = val.ToString(); };
|
ConfigManager.Master_Toggle.OnValueChanged += Master_Toggle_OnValueChanged;
|
||||||
|
closeBtn.OnClick += OnCloseButtonClicked;
|
||||||
closeBtn.OnClick += () => { ShowMenu = false; };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region UI AssetBundle
|
#region UI AssetBundle
|
||||||
|
@ -7,7 +7,6 @@ using UnityEngine.UI;
|
|||||||
using UnityExplorer.Core.Input;
|
using UnityExplorer.Core.Input;
|
||||||
using UnityExplorer.Core.Runtime;
|
using UnityExplorer.Core.Runtime;
|
||||||
using UnityExplorer.UI;
|
using UnityExplorer.UI;
|
||||||
using UnityExplorer.UI.ObjectPool;
|
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||||
@ -170,7 +169,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
|||||||
|
|
||||||
// Setting autocomplete cell buttons
|
// Setting autocomplete cell buttons
|
||||||
|
|
||||||
private readonly Color selectedSuggestionColor = new Color(45/255f, 75/255f, 80/255f);
|
private readonly Color selectedSuggestionColor = new Color(45 / 255f, 75 / 255f, 80 / 255f);
|
||||||
private readonly Color inactiveSuggestionColor = new Color(0.11f, 0.11f, 0.11f);
|
private readonly Color inactiveSuggestionColor = new Color(0.11f, 0.11f, 0.11f);
|
||||||
|
|
||||||
private List<Suggestion> GetEntries() => Suggestions;
|
private List<Suggestion> GetEntries() => Suggestions;
|
||||||
@ -292,9 +291,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
|||||||
|
|
||||||
protected internal override void DoSetDefaultPosAndAnchors()
|
protected internal override void DoSetDefaultPosAndAnchors()
|
||||||
{
|
{
|
||||||
mainPanelRect.pivot = new Vector2(0f, 1f);
|
Rect.pivot = new Vector2(0f, 1f);
|
||||||
mainPanelRect.anchorMin = new Vector2(0.42f, 0.4f);
|
Rect.anchorMin = new Vector2(0.42f, 0.4f);
|
||||||
mainPanelRect.anchorMax = new Vector2(0.68f, 0.6f);
|
Rect.anchorMax = new Vector2(0.68f, 0.6f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ConstructPanelContent()
|
public override void ConstructPanelContent()
|
||||||
|
@ -9,7 +9,6 @@ using UnityExplorer.Core.Input;
|
|||||||
using UnityExplorer.Core.Runtime;
|
using UnityExplorer.Core.Runtime;
|
||||||
using UnityExplorer.UI.Models;
|
using UnityExplorer.UI.Models;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
using UnityExplorer.UI.Utility;
|
|
||||||
|
|
||||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||||
{
|
{
|
||||||
@ -88,7 +87,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for exact match first
|
// Check for exact match first
|
||||||
if (ReflectionUtility.AllTypes.TryGetValue(value, out Type t) && allowedTypes.Contains(t))
|
if (ReflectionUtility.GetTypeByName(value) is Type t && allowedTypes.Contains(t))
|
||||||
AddSuggestion(t);
|
AddSuggestion(t);
|
||||||
|
|
||||||
foreach (var entry in allowedTypes)
|
foreach (var entry in allowedTypes)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user