mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-22 16:42:38 +08:00
Compare commits
114 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 |
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"]
|
||||
path = lib/Il2CppAssemblyUnhollower
|
||||
url = https://github.com/knah/Il2CppAssemblyUnhollower
|
||||
[submodule "lib/HarmonyX"]
|
||||
path = lib/HarmonyX
|
||||
url = https://github.com/BepInEx/HarmonyX
|
||||
[submodule "lib/mcs-unity"]
|
||||
path = lib/mcs-unity
|
||||
url = https://github.com/sinai-dev/mcs-unity
|
||||
|
114
README.md
114
README.md
@ -3,44 +3,45 @@
|
||||
</p>
|
||||
|
||||
<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 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>
|
||||
|
||||
## Releases [](../../releases/latest) [](../../releases) [](../../releases/latest)
|
||||
# Releases [](../../releases)
|
||||
|
||||
| Mod Loader | IL2CPP | Mono |
|
||||
| ----------- | ------ | ---- |
|
||||
| [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) |
|
||||
[](../../releases/latest) [](https://github.com/sinai-dev/UnityExplorer/actions) [](../../releases/latest)
|
||||
|
||||
### Known issues
|
||||
* 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.
|
||||
## BepInEx
|
||||
|
||||
## 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.
|
||||
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.
|
||||
<i>Note: BepInEx 6 is obtainable via [BepisBuilds](https://builds.bepis.io/projects/bepinex_be)</i>
|
||||
|
||||
### 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).
|
||||
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.
|
||||
| Release | IL2CPP | Mono |
|
||||
| ------- | ------ | ---- |
|
||||
| ML 0.4.0 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.Mono.zip) |
|
||||
| ML 0.3.0 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Mono.zip) |
|
||||
|
||||
### 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).
|
||||
|
||||
@ -49,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();`
|
||||
4. Optionally subscribe to the `ExplorerStandalone.OnLog` event to handle logging if you wish
|
||||
|
||||
## Features
|
||||
# Features
|
||||
|
||||
<p align="center">
|
||||
<a href="https://raw.githubusercontent.com/sinai-dev/UnityExplorer/master/img/preview.png">
|
||||
@ -59,48 +60,61 @@ The standalone release can be used with any injector or loader of your choice, b
|
||||
|
||||
### 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 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
|
||||
|
||||
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.
|
||||
|
||||
In the Reflection Inspectors, automatic updating is not enabled by default, and you must press Apply for any changes you make to take effect.
|
||||
* 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.
|
||||
* <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
|
||||
|
||||
The C# Console uses the `Mono.CSharp.Evaluator` to define temporary classes or run immediate REPL code.
|
||||
|
||||
See the "Help" dropdown in the C# console menu for more detailed information.
|
||||
* The C# Console uses the `Mono.CSharp.Evaluator` to define temporary classes or run immediate REPL code.
|
||||
* You can execute a script automatically on startup by naming it `startup.cs` and placing it in the `UnityExplorer\Scripts\` folder (this folder will be created where you placed the DLL file).
|
||||
* See the "Help" dropdown in the C# console menu for more detailed information.
|
||||
|
||||
### Mouse-Inspect
|
||||
|
||||
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>UI</b>: uses GraphicRaycasters to find UI objects
|
||||
* 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>UI</b>: uses GraphicRaycasters to find UI objects
|
||||
|
||||
### 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:
|
||||
* BepInEx: `BepInEx\config\com.sinai.unityexplorer.cfg`
|
||||
* MelonLoader: `UserData\MelonPreferences.cfg`
|
||||
* Standalone `{DLL_location}\UnityExplorer\config.ini`
|
||||
# Building
|
||||
|
||||
## Building
|
||||
If you fork the repository on GitHub you can build using the [dotnet workflow](https://github.com/sinai-dev/UnityExplorer/blob/master/.github/workflows/dotnet.yml):
|
||||
|
||||
0. Click on the Actions tab and enable workflows in your repository
|
||||
1. Click on the "Build UnityExplorer" workflow, then click "Run Workflow" and run it manually, or make a new commit to trigger the workflow.
|
||||
2. Take the artifact from the completed run.
|
||||
|
||||
For Visual Studio:
|
||||
|
||||
0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
|
||||
1. Open the `src\UnityExplorer.sln` project in 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.
|
||||
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
|
||||
# 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.
|
||||
* [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.
@ -3,10 +3,11 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.UI.CSConsole.Lexers;
|
||||
using UnityExplorer.CSConsole.Lexers;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
public class CSAutoCompleter : ISuggestionProvider
|
||||
{
|
||||
@ -22,7 +23,6 @@ namespace UnityExplorer.UI.CSConsole
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(this);
|
||||
}
|
||||
|
||||
// Delimiters for completions, notably does not include '.'
|
||||
private readonly HashSet<char> delimiters = new HashSet<char>
|
||||
{
|
||||
'{', '}', ',', ';', '<', '>', '(', ')', '[', ']', '=', '|', '&', '?'
|
||||
@ -41,7 +41,7 @@ namespace UnityExplorer.UI.CSConsole
|
||||
suggestions.Clear();
|
||||
|
||||
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,
|
||||
// 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)
|
||||
while (start > 0)
|
||||
while (startIdx > 0)
|
||||
{
|
||||
start--;
|
||||
char c = InputField.Text[start];
|
||||
if (delimiters.Contains(c))
|
||||
startIdx--;
|
||||
char c = InputField.Text[startIdx];
|
||||
if (delimiters.Contains(c) || char.IsWhiteSpace(c))
|
||||
{
|
||||
start++;
|
||||
startIdx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
string input = InputField.Text.Substring(start, caret - start + 1);
|
||||
string input = InputField.Text.Substring(startIdx, caret - startIdx + 1);
|
||||
|
||||
// Get MCS completions
|
||||
|
@ -1,18 +1,21 @@
|
||||
using System;
|
||||
using Mono.CSharp;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.CSConsole;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.CSConsole;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
public static class ConsoleController
|
||||
{
|
||||
@ -34,6 +37,8 @@ namespace UnityExplorer.UI.CSConsole
|
||||
public static bool EnableAutoIndent { get; private set; } = true;
|
||||
public static bool EnableSuggestions { get; private set; } = true;
|
||||
|
||||
internal static string ScriptsFolder => Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Scripts");
|
||||
|
||||
internal static readonly string[] DefaultUsing = new string[]
|
||||
{
|
||||
"System",
|
||||
@ -49,6 +54,7 @@ namespace UnityExplorer.UI.CSConsole
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
// Make sure console is supported on this platform
|
||||
try
|
||||
{
|
||||
ResetConsole(false);
|
||||
@ -61,19 +67,41 @@ namespace UnityExplorer.UI.CSConsole
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup console
|
||||
Lexer = new LexerBuilder();
|
||||
Completer = new CSAutoCompleter();
|
||||
|
||||
SetupHelpInteraction();
|
||||
|
||||
Panel.OnInputChanged += OnInputChanged;
|
||||
Panel.InputScroll.OnScroll += OnInputScrolled;
|
||||
Panel.InputScroller.OnScroll += OnInputScrolled;
|
||||
Panel.OnCompileClicked += Evaluate;
|
||||
Panel.OnResetClicked += ResetConsole;
|
||||
Panel.OnHelpDropdownChanged += HelpSelected;
|
||||
Panel.OnAutoIndentToggled += OnToggleAutoIndent;
|
||||
Panel.OnCtrlRToggled += OnToggleCtrlRShortcut;
|
||||
Panel.OnSuggestionsToggled += OnToggleSuggestions;
|
||||
Panel.OnPanelResized += OnInputScrolled;
|
||||
|
||||
// Run startup script
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(ScriptsFolder))
|
||||
Directory.CreateDirectory(ScriptsFolder);
|
||||
|
||||
var startupPath = Path.Combine(ScriptsFolder, "startup.cs");
|
||||
if (File.Exists(startupPath))
|
||||
{
|
||||
ExplorerCore.Log($"Executing startup script from '{startupPath}'...");
|
||||
var text = File.ReadAllText(startupPath);
|
||||
Input.Text = text;
|
||||
Evaluate();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception executing startup script: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -149,15 +177,16 @@ namespace UnityExplorer.UI.CSConsole
|
||||
|
||||
try
|
||||
{
|
||||
// Try to "Compile" the code (tries to interpret it as REPL)
|
||||
var evaluation = Evaluator.Compile(input);
|
||||
if (evaluation != null)
|
||||
// Compile the code. If it returned a CompiledMethod, it is REPL.
|
||||
CompiledMethod repl = Evaluator.Compile(input);
|
||||
|
||||
if (repl != null)
|
||||
{
|
||||
// Valid REPL, we have a delegate to the evaluation.
|
||||
try
|
||||
{
|
||||
object ret = null;
|
||||
evaluation.Invoke(ref ret);
|
||||
repl.Invoke(ref ret);
|
||||
var result = ret?.ToString();
|
||||
if (!string.IsNullOrEmpty(result))
|
||||
ExplorerCore.Log($"Invoked REPL, result: {ret}");
|
||||
@ -171,9 +200,7 @@ namespace UnityExplorer.UI.CSConsole
|
||||
}
|
||||
else
|
||||
{
|
||||
// The input was not recognized as an evaluation. Compile the code.
|
||||
|
||||
Evaluator.Run(input);
|
||||
// The compiled code was not REPL, so it was a using directive or it defined classes.
|
||||
|
||||
string output = ScriptEvaluator._textWriter.ToString();
|
||||
var outputSplit = output.Split('\n');
|
||||
@ -230,23 +257,32 @@ namespace UnityExplorer.UI.CSConsole
|
||||
previousInput = value;
|
||||
|
||||
if (EnableSuggestions && AutoCompleteModal.CheckEnter(Completer))
|
||||
{
|
||||
OnAutocompleteEnter();
|
||||
}
|
||||
else if (!settingCaretCoroutine)
|
||||
{
|
||||
if (EnableSuggestions)
|
||||
Completer.CheckAutocompletes();
|
||||
|
||||
if (!settingCaretCoroutine)
|
||||
{
|
||||
if (EnableAutoIndent)
|
||||
DoAutoIndent();
|
||||
}
|
||||
|
||||
HighlightVisibleInput();
|
||||
var inStringOrComment = HighlightVisibleInput();
|
||||
|
||||
if (!settingCaretCoroutine)
|
||||
{
|
||||
if (EnableSuggestions)
|
||||
{
|
||||
if (inStringOrComment)
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(Completer);
|
||||
else
|
||||
Completer.CheckAutocompletes();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateCaret(out _);
|
||||
}
|
||||
|
||||
private static float timeOfLastCtrlR;
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
if (SRENotSupported)
|
||||
@ -254,22 +290,24 @@ namespace UnityExplorer.UI.CSConsole
|
||||
|
||||
UpdateCaret(out bool caretMoved);
|
||||
|
||||
if (!settingCaretCoroutine && EnableSuggestions && AutoCompleteModal.CheckEscape(Completer))
|
||||
if (!settingCaretCoroutine && EnableSuggestions)
|
||||
{
|
||||
if (AutoCompleteModal.CheckEscape(Completer))
|
||||
{
|
||||
OnAutocompleteEscaped();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!settingCaretCoroutine && EnableSuggestions && caretMoved)
|
||||
{
|
||||
if (caretMoved)
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(Completer);
|
||||
//Completer.CheckAutocompletes();
|
||||
}
|
||||
|
||||
if (EnableCtrlRShortcut
|
||||
&& (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);
|
||||
}
|
||||
}
|
||||
@ -305,7 +343,7 @@ namespace UnityExplorer.UI.CSConsole
|
||||
var charBot = charTop - CSCONSOLE_LINEHEIGHT;
|
||||
|
||||
var viewportMin = Input.Rect.rect.height - Input.Rect.anchoredPosition.y - (Input.Rect.rect.height * 0.5f);
|
||||
var viewportMax = viewportMin - Panel.InputScroll.ViewportRect.rect.height;
|
||||
var viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
|
||||
|
||||
float diff = 0f;
|
||||
if (charTop > viewportMin)
|
||||
@ -325,18 +363,31 @@ namespace UnityExplorer.UI.CSConsole
|
||||
{
|
||||
settingCaretCoroutine = 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;
|
||||
color.a = 0f;
|
||||
Input.Component.selectionColor = color;
|
||||
EventSystem.current.SetSelectedGameObject(null, null);
|
||||
try { EventSystem.current.SetSelectedGameObject(null, null); } catch { }
|
||||
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();
|
||||
yield return null;
|
||||
|
||||
@ -351,25 +402,29 @@ namespace UnityExplorer.UI.CSConsole
|
||||
settingCaretCoroutine = false;
|
||||
}
|
||||
|
||||
|
||||
#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;
|
||||
int endIdx = Input.Text.Length - 1;
|
||||
int topLine = 0;
|
||||
if (string.IsNullOrEmpty(Input.Text))
|
||||
{
|
||||
Panel.HighlightText.text = "";
|
||||
Panel.LineNumberText.text = "1";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate visible text if necessary
|
||||
if (Input.Rect.rect.height > Panel.InputScroll.ViewportRect.rect.height)
|
||||
{
|
||||
topLine = -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.InputScroll.ViewportRect.rect.height;
|
||||
var viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
|
||||
|
||||
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
|
||||
{
|
||||
@ -385,14 +440,53 @@ namespace UnityExplorer.UI.CSConsole
|
||||
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)
|
||||
int startIdx = Input.TextGenerator.lines[topLine].startCharIdx;
|
||||
int endIdx = (bottomLine >= Input.TextGenerator.lineCount - 1)
|
||||
? Input.Text.Length - 1
|
||||
: (Input.TextGenerator.lines[bottomLine + 1].startCharIdx - 1);
|
||||
}
|
||||
|
||||
|
||||
// Highlight the visible text with the LexerBuilder
|
||||
Panel.HighlightText.text = Lexer.BuildHighlightedString(Input.Text, startIdx, endIdx, topLine);
|
||||
|
||||
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
|
||||
@ -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!
|
||||
|
||||
// It is recommended to use the Log panel (or a console log window) while using this tool.
|
||||
// Use the Help dropdown to see detailed examples of how to use the console.</color>";
|
||||
// Use the Help dropdown to see detailed examples of how to use the console.
|
||||
|
||||
// To execute a script automatically on startup, put the script at 'UnityExplorer\Scripts\startup.cs'</color>";
|
||||
|
||||
internal const string HELP_USINGS = @"// You can add a using directive to any namespace, but you must compile for it to take effect.
|
||||
// It will remain in effect until you Reset the console.
|
@ -5,14 +5,16 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.CSConsole.Lexers;
|
||||
using UnityExplorer.CSConsole.Lexers;
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
public struct MatchInfo
|
||||
{
|
||||
public int startIndex;
|
||||
public int endIndex;
|
||||
public bool isStringOrComment;
|
||||
public bool matchToEndOfLine;
|
||||
public string htmlColorTag;
|
||||
}
|
||||
|
||||
@ -82,8 +84,10 @@ namespace UnityExplorer.UI.CSConsole
|
||||
/// <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>
|
||||
/// <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)
|
||||
return input;
|
||||
|
||||
@ -105,14 +109,28 @@ namespace UnityExplorer.UI.CSConsole
|
||||
|
||||
// append the highlighted match
|
||||
sb.Append(match.htmlColorTag);
|
||||
|
||||
for (int i = match.startIndex; i <= match.endIndex && i <= currentEndIdx; i++)
|
||||
sb.Append(input[i]);
|
||||
|
||||
sb.Append(SignatureHighlighter.CLOSE_COLOR);
|
||||
|
||||
// update the last unhighlighted start index
|
||||
lastUnhighlighted = match.endIndex + 1;
|
||||
|
||||
int matchEndIdx = match.endIndex;
|
||||
if (match.matchToEndOfLine)
|
||||
{
|
||||
while (input.Length - 1 >= matchEndIdx)
|
||||
{
|
||||
if (IsNewLine(input[matchEndIdx]))
|
||||
break;
|
||||
matchEndIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
// check caretIdx to determine inStringOrComment state
|
||||
if (caretIdx >= match.startIndex && (caretIdx <= matchEndIdx || (caretIdx >= input.Length && matchEndIdx >= input.Length - 1)))
|
||||
caretInStringOrComment = match.isStringOrComment;
|
||||
|
||||
}
|
||||
|
||||
// Append trailing unhighlighted input
|
||||
@ -150,6 +168,7 @@ namespace UnityExplorer.UI.CSConsole
|
||||
startIndex = startIndex,
|
||||
endIndex = CommittedIndex,
|
||||
htmlColorTag = lexer.ColorTag,
|
||||
isStringOrComment = lexer is StringLexer || lexer is CommentLexer,
|
||||
};
|
||||
break;
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public class CommentLexer : Lexer
|
||||
{
|
@ -2,7 +2,7 @@
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public class KeywordLexer : Lexer
|
||||
{
|
||||
@ -41,6 +41,10 @@ namespace UnityExplorer.UI.CSConsole.Lexers
|
||||
while (!lexer.EndOfInput && char.IsLetter(lexer.PeekNext()))
|
||||
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 (!lexer.EndOfInput)
|
@ -1,8 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public abstract class Lexer
|
||||
{
|
@ -1,6 +1,6 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public class NumberLexer : Lexer
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public class StringLexer : Lexer
|
||||
{
|
@ -3,7 +3,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public class SymbolLexer : Lexer
|
||||
{
|
||||
@ -11,7 +11,7 @@ namespace UnityExplorer.UI.CSConsole.Lexers
|
||||
protected override Color HighlightColor => new Color(0.6f, 0.6f, 0.6f);
|
||||
|
||||
// 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);
|
||||
|
@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using Mono.CSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Mono.CSharp;
|
||||
|
||||
// Thanks to ManlyMarco for this
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
public class ScriptEvaluator : Evaluator, IDisposable
|
||||
{
|
@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using Mono.CSharp;
|
||||
using Mono.CSharp;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
namespace UnityExplorer.UI.CSConsole
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
public class ScriptInteraction : InteractiveBase
|
||||
{
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
public class CacheConfigEntry : CacheObjectBase
|
||||
{
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.Inspectors;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
public class CacheField : CacheMember
|
||||
{
|
@ -2,11 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.UI.IValues;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
public class CacheKeyValuePair : CacheObjectBase
|
||||
{
|
@ -2,10 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.UI.IValues;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
public class CacheListEntry : CacheObjectBase
|
||||
{
|
@ -5,12 +5,12 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
public abstract class CacheMember : CacheObjectBase
|
||||
{
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.Inspectors;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
public class CacheMethod : CacheMember
|
||||
{
|
@ -7,12 +7,12 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.UI.IValues;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
public enum ValueState
|
||||
{
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.Inspectors;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
public class CacheProperty : CacheMember
|
||||
{
|
||||
@ -28,10 +28,11 @@ namespace UnityExplorer.UI.CacheObject
|
||||
{
|
||||
try
|
||||
{
|
||||
object ret;
|
||||
if (HasArguments)
|
||||
return PropertyInfo.GetValue(DeclaringInstance, this.Evaluator.TryParseArguments());
|
||||
|
||||
var ret = PropertyInfo.GetValue(DeclaringInstance, null);
|
||||
ret = PropertyInfo.GetValue(DeclaringInstance, this.Evaluator.TryParseArguments());
|
||||
else
|
||||
ret = PropertyInfo.GetValue(DeclaringInstance, null);
|
||||
HadException = false;
|
||||
LastException = null;
|
||||
return ret;
|
@ -3,10 +3,10 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
public interface ICacheObjectController
|
||||
{
|
@ -4,9 +4,10 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.UI.IValues
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
public class InteractiveColor : InteractiveValue
|
||||
{
|
@ -5,14 +5,14 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.IValues
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
public class InteractiveDictionary : InteractiveValue, ICellPoolDataSource<CacheKeyValuePairCell>, ICacheObjectController
|
||||
{
|
@ -5,9 +5,10 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.UI.IValues
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
public class InteractiveEnum : InteractiveValue
|
||||
{
|
@ -5,14 +5,14 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.IValues
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
public class InteractiveList : InteractiveValue, ICellPoolDataSource<CacheListEntryCell>, ICacheObjectController
|
||||
{
|
@ -6,10 +6,11 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.UI.IValues
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
public class InteractiveString : InteractiveValue
|
||||
{
|
@ -4,10 +4,11 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.IValues
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
public abstract class InteractiveValue : IPooledObject
|
||||
{
|
@ -5,10 +5,10 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.UI.IValues
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
public class InteractiveValueStruct : InteractiveValue
|
||||
{
|
@ -4,8 +4,9 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject.Views
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
public class ConfigEntryCell : CacheObjectCell
|
||||
{
|
@ -4,11 +4,12 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.UI.IValues;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject.Views
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
public class CacheKeyValuePairCell : CacheObjectCell
|
||||
{
|
@ -4,9 +4,9 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.IValues;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject.Views
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
public class CacheListEntryCell : CacheObjectCell
|
||||
{
|
@ -4,9 +4,10 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject.Views
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
public class CacheMemberCell : CacheObjectCell
|
||||
{
|
@ -4,13 +4,12 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.UI.IValues;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject.Views
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
public abstract class CacheObjectCell : ICell
|
||||
{
|
@ -5,11 +5,11 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.CacheObject.Views
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
public class EvaluateWidget : IPooledObject
|
||||
{
|
@ -21,6 +21,7 @@ namespace UnityExplorer.Core.Config
|
||||
public static ConfigElement<bool> Force_Unlock_Mouse;
|
||||
public static ConfigElement<KeyCode> Force_Unlock_Toggle;
|
||||
public static ConfigElement<bool> Aggressive_Mouse_Unlock;
|
||||
public static ConfigElement<bool> Disable_EventSystem_Override;
|
||||
public static ConfigElement<string> Default_Output_Path;
|
||||
public static ConfigElement<bool> Log_Unity_Debug;
|
||||
public static ConfigElement<bool> Hide_On_Startup;
|
||||
@ -93,7 +94,11 @@ namespace UnityExplorer.Core.Config
|
||||
KeyCode.None);
|
||||
|
||||
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);
|
||||
|
||||
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.",
|
||||
1f);
|
||||
|
||||
Reflection_Signature_Blacklist = new ConfigElement<string>("Reflection Signature Blacklist",
|
||||
"Use this to blacklist certain member signatures if they are known to cause a crash or other issues." +
|
||||
"\r\nSeperate signatures with a semicolon ';'.",
|
||||
"DEFAULT");
|
||||
Reflection_Signature_Blacklist = new ConfigElement<string>("Member Signature Blacklist",
|
||||
"Use this to blacklist certain member signatures if they are known to cause a crash or other issues.\r\n" +
|
||||
"Seperate signatures with a semicolon ';'.\r\n" +
|
||||
"For example, to blacklist Camera.main, you would add 'Camera.main;'",
|
||||
"");
|
||||
|
||||
// Internal configs (panel save data)
|
||||
|
||||
|
@ -87,9 +87,6 @@ namespace UnityExplorer.Core.Config
|
||||
foreach (var entry in ConfigManager.InternalConfigs)
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -32,17 +32,33 @@ namespace UnityExplorer
|
||||
public ExplorerBehaviour(IntPtr ptr) : base(ptr) { }
|
||||
#endif
|
||||
|
||||
private static bool onPostRenderFailed;
|
||||
|
||||
internal void Awake()
|
||||
{
|
||||
try
|
||||
{
|
||||
#if CPP
|
||||
Camera.onPostRender = Camera.onPostRender == null
|
||||
? 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
|
||||
Camera.onPostRender += OnPostRender;
|
||||
#endif
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception adding onPostRender listener: {ex.ReflectionExToString()}\r\nFalling back to LateUpdate!");
|
||||
onPostRenderFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
@ -54,7 +70,13 @@ namespace UnityExplorer
|
||||
ExplorerCore.FixedUpdate();
|
||||
}
|
||||
|
||||
internal static void OnPostRender(Camera camera)
|
||||
internal void LateUpdate()
|
||||
{
|
||||
if (onPostRenderFailed)
|
||||
OnPostRender(null);
|
||||
}
|
||||
|
||||
internal static void OnPostRender(Camera _)
|
||||
{
|
||||
ExplorerCore.OnPostRender();
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityExplorer.Core.Input;
|
||||
using BF = System.Reflection.BindingFlags;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.UI;
|
||||
using System.Collections;
|
||||
using HarmonyLib;
|
||||
using BF = System.Reflection.BindingFlags;
|
||||
|
||||
|
||||
namespace UnityExplorer.Core.Input
|
||||
{
|
||||
@ -37,12 +37,15 @@ namespace UnityExplorer.Core.Input
|
||||
lastVisibleState = Cursor.visible;
|
||||
|
||||
SetupPatches();
|
||||
|
||||
UpdateCursorControl();
|
||||
|
||||
// Hook up config values
|
||||
|
||||
// Force Unlock Mouse
|
||||
Unlock = ConfigManager.Force_Unlock_Mouse.Value;
|
||||
ConfigManager.Force_Unlock_Mouse.OnValueChanged += (bool val) => { Unlock = val; };
|
||||
|
||||
// Aggressive Mouse Unlock
|
||||
if (ConfigManager.Aggressive_Mouse_Unlock.Value)
|
||||
SetupAggressiveUnlock();
|
||||
}
|
||||
@ -59,13 +62,13 @@ namespace UnityExplorer.Core.Input
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame();
|
||||
private static WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame();
|
||||
|
||||
private static IEnumerator AggressiveUnlockCoroutine()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
yield return _waitForEndOfFrame;
|
||||
yield return _waitForEndOfFrame ?? (_waitForEndOfFrame = new WaitForEndOfFrame());
|
||||
|
||||
if (UIManager.ShowMenu)
|
||||
UpdateCursorControl();
|
||||
@ -83,7 +86,7 @@ namespace UnityExplorer.Core.Input
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
Cursor.visible = true;
|
||||
|
||||
if (UIManager.EventSys)
|
||||
if (!ConfigManager.Disable_EventSystem_Override.Value && UIManager.EventSys)
|
||||
SetEventSystem();
|
||||
}
|
||||
else
|
||||
@ -91,7 +94,7 @@ namespace UnityExplorer.Core.Input
|
||||
Cursor.lockState = lastLockMode;
|
||||
Cursor.visible = lastVisibleState;
|
||||
|
||||
if (UIManager.EventSys)
|
||||
if (!ConfigManager.Disable_EventSystem_Override.Value && UIManager.EventSys)
|
||||
ReleaseEventSystem();
|
||||
}
|
||||
|
||||
@ -160,28 +163,21 @@ namespace UnityExplorer.Core.Input
|
||||
|
||||
public static void Prefix_EventSystem_set_current(ref EventSystem value)
|
||||
{
|
||||
if (!UIManager.EventSys)
|
||||
{
|
||||
if (value)
|
||||
if (!settingEventSystem && value)
|
||||
{
|
||||
lastEventSystem = value;
|
||||
lastInputModule = value.currentInputModule;
|
||||
}
|
||||
|
||||
if (!UIManager.EventSys)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!settingEventSystem && value != UIManager.EventSys)
|
||||
{
|
||||
lastEventSystem = value;
|
||||
lastInputModule = value?.currentInputModule;
|
||||
|
||||
if (ShouldActuallyUnlock)
|
||||
if (!settingEventSystem && ShouldActuallyUnlock && !ConfigManager.Disable_EventSystem_Override.Value)
|
||||
{
|
||||
value = UIManager.EventSys;
|
||||
value.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true.
|
||||
// Also keep track of when anything else tries to set Cursor state, this will be the
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace UnityExplorer.Core.Input
|
||||
|
@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityExplorer.UI;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityExplorer.Core.Input
|
||||
{
|
||||
|
@ -99,8 +99,10 @@ namespace UnityExplorer
|
||||
|
||||
public static Exception GetInnerMostException(this Exception e)
|
||||
{
|
||||
while (e.InnerException != null)
|
||||
while (e != null)
|
||||
{
|
||||
if (e.InnerException == null)
|
||||
break;
|
||||
#if CPP
|
||||
if (e.InnerException is System.Runtime.CompilerServices.RuntimeWrappedException)
|
||||
break;
|
||||
|
@ -16,6 +16,7 @@ using CppType = Il2CppSystem.Type;
|
||||
using BF = System.Reflection.BindingFlags;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnhollowerBaseLib.Attributes;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
@ -25,13 +26,18 @@ namespace UnityExplorer
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
float start = Time.realtimeSinceStartup;
|
||||
TryLoadGameModules();
|
||||
ExplorerCore.Log($"Loaded Unhollowed modules in {Time.realtimeSinceStartup - start} seconds");
|
||||
|
||||
start = Time.realtimeSinceStartup;
|
||||
BuildDeobfuscationCache();
|
||||
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
|
||||
[DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
@ -44,23 +50,23 @@ namespace UnityExplorer
|
||||
|
||||
public static bool Il2CppTypeNotNull(Type type, out IntPtr il2cppPtr)
|
||||
{
|
||||
if (cppClassPointers.TryGetValue(type.AssemblyQualifiedName, out il2cppPtr))
|
||||
return il2cppPtr != IntPtr.Zero;
|
||||
|
||||
if (!cppClassPointers.TryGetValue(type.AssemblyQualifiedName, out il2cppPtr))
|
||||
{
|
||||
il2cppPtr = (IntPtr)typeof(Il2CppClassPointerStore<>)
|
||||
.MakeGenericType(new Type[] { type })
|
||||
.GetField("NativeClassPtr", BF.Public | BF.Static)
|
||||
.GetValue(null);
|
||||
|
||||
cppClassPointers.Add(type.AssemblyQualifiedName, il2cppPtr);
|
||||
}
|
||||
|
||||
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, string> reverseDeobCache = new Dictionary<string, string>();
|
||||
@ -72,9 +78,6 @@ namespace UnityExplorer
|
||||
foreach (var type in asm.TryGetTypes())
|
||||
TryCacheDeobfuscatedType(type);
|
||||
}
|
||||
|
||||
if (DeobfuscatedTypes.Count > 0)
|
||||
ExplorerCore.Log($"Built IL2CPP deobfuscation cache, initial count: {DeobfuscatedTypes.Count}");
|
||||
}
|
||||
|
||||
private static void TryCacheDeobfuscatedType(Type type)
|
||||
@ -108,7 +111,7 @@ namespace UnityExplorer
|
||||
return theString;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
// Get type by name
|
||||
@ -121,7 +124,7 @@ namespace UnityExplorer
|
||||
return base.Internal_GetTypeByName(fullName);
|
||||
}
|
||||
|
||||
#region Get actual type
|
||||
#region Get actual type
|
||||
|
||||
internal override Type Internal_GetActualType(object obj)
|
||||
{
|
||||
@ -129,7 +132,6 @@ namespace UnityExplorer
|
||||
return null;
|
||||
|
||||
var type = obj.GetType();
|
||||
|
||||
try
|
||||
{
|
||||
if (IsString(obj))
|
||||
@ -180,10 +182,10 @@ namespace UnityExplorer
|
||||
return monoType;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
#region Casting
|
||||
#region Casting
|
||||
|
||||
private static readonly Dictionary<string, IntPtr> cppClassPointers = new Dictionary<string, IntPtr>();
|
||||
|
||||
@ -213,7 +215,7 @@ namespace UnityExplorer
|
||||
// from other structs to il2cpp object
|
||||
else if (typeof(Il2CppSystem.Object).IsAssignableFrom(castTo))
|
||||
{
|
||||
return BoxIl2CppObject(obj);
|
||||
return BoxIl2CppObject(obj).TryCast(castTo);
|
||||
}
|
||||
else
|
||||
return obj;
|
||||
@ -237,11 +239,11 @@ namespace UnityExplorer
|
||||
else if (castTo == typeof(string))
|
||||
return UnboxString(obj);
|
||||
|
||||
// Casting from il2cpp object to il2cpp object...
|
||||
|
||||
if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr))
|
||||
return obj;
|
||||
|
||||
// Casting from il2cpp object to il2cpp object...
|
||||
|
||||
IntPtr castFromPtr = il2cpp_object_get_class(cppObj.Pointer);
|
||||
|
||||
if (!il2cpp_class_is_assignable_from(castToPtr, castFromPtr))
|
||||
@ -275,10 +277,10 @@ namespace UnityExplorer
|
||||
// return il2cpp_class_is_assignable_from(thisTypePtr, fromTypePtr);
|
||||
//}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
#region Boxing and unboxing ValueTypes
|
||||
#region Boxing and unboxing ValueTypes
|
||||
|
||||
// cached il2cpp unbox methods
|
||||
internal static readonly Dictionary<string, MethodInfo> unboxMethods = new Dictionary<string, MethodInfo>();
|
||||
@ -292,7 +294,27 @@ namespace UnityExplorer
|
||||
try
|
||||
{
|
||||
if (toType.IsEnum)
|
||||
{
|
||||
// Check for nullable enums
|
||||
var type = cppObj.GetType();
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Il2CppSystem.Nullable<>))
|
||||
{
|
||||
var nullable = cppObj.TryCast(type);
|
||||
var nullableHasValueProperty = type.GetProperty("HasValue");
|
||||
if ((bool)nullableHasValueProperty.GetValue(nullable, null))
|
||||
{
|
||||
// nullable has a value.
|
||||
var nullableValueProperty = type.GetProperty("Value");
|
||||
return Enum.Parse(toType, nullableValueProperty.GetValue(nullable, null).ToString());
|
||||
}
|
||||
// nullable and no current value.
|
||||
return cppObj;
|
||||
}
|
||||
|
||||
return Enum.Parse(toType, cppObj.ToString());
|
||||
}
|
||||
|
||||
// Not enum, unbox with Il2CppObjectBase.Unbox
|
||||
|
||||
var name = toType.AssemblyQualifiedName;
|
||||
|
||||
@ -381,10 +403,10 @@ namespace UnityExplorer
|
||||
return cppStruct;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
#region String boxing/unboxing
|
||||
#region String boxing/unboxing
|
||||
|
||||
private const string IL2CPP_STRING_FULLNAME = "Il2CppSystem.String";
|
||||
private const string STRING_FULLNAME = "System.String";
|
||||
@ -425,10 +447,10 @@ namespace UnityExplorer
|
||||
return s;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
#region Singleton finder
|
||||
#region Singleton finder
|
||||
|
||||
internal override void Internal_FindSingleton(string[] possibleNames, Type type, BF flags, List<object> instances)
|
||||
{
|
||||
@ -450,16 +472,16 @@ namespace UnityExplorer
|
||||
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", "unhollowed")
|
||||
Path.Combine(BepInEx.Paths.BepInExRootPath, "unhollowed")
|
||||
#else
|
||||
Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Modules")
|
||||
#endif
|
||||
@ -513,9 +535,9 @@ namespace UnityExplorer
|
||||
#endregion
|
||||
|
||||
|
||||
#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,
|
||||
// even from doing "GetParameters()" on the MemberInfo.
|
||||
@ -662,10 +684,10 @@ namespace UnityExplorer
|
||||
"UnityEngine.XR.InputDevice.SendHapticImpulse",
|
||||
};
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
#region IL2CPP IEnumerable and IDictionary
|
||||
#region IL2CPP IEnumerable and IDictionary
|
||||
|
||||
protected override bool Internal_TryGetEntryType(Type enumerableType, out Type type)
|
||||
{
|
||||
@ -782,7 +804,9 @@ namespace UnityExplorer
|
||||
|
||||
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
|
||||
try
|
||||
@ -868,7 +892,9 @@ namespace UnityExplorer
|
||||
var cacheKey = keys.GetType().AssemblyQualifiedName;
|
||||
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
|
||||
try
|
||||
|
@ -4,15 +4,14 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using BF = System.Reflection.BindingFlags;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using BF = System.Reflection.BindingFlags;
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
|
||||
public class ReflectionUtility
|
||||
{
|
||||
public const BF FLAGS = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
|
||||
@ -43,7 +42,7 @@ namespace UnityExplorer
|
||||
public static Action<Type> OnTypeLoaded;
|
||||
|
||||
/// <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>();
|
||||
private static readonly HashSet<string> uniqueNamespaces = new HashSet<string>();
|
||||
@ -66,10 +65,14 @@ namespace UnityExplorer
|
||||
|
||||
private static void SetupTypeCache()
|
||||
{
|
||||
float start = Time.realtimeSinceStartup;
|
||||
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
CacheTypes(asm);
|
||||
|
||||
AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoaded;
|
||||
|
||||
ExplorerCore.Log($"Cached AppDomain assemblies in {Time.realtimeSinceStartup - start} seconds");
|
||||
}
|
||||
|
||||
private static void AssemblyLoaded(object sender, AssemblyLoadEventArgs args)
|
||||
@ -84,6 +87,7 @@ namespace UnityExplorer
|
||||
{
|
||||
foreach (var type in asm.TryGetTypes())
|
||||
{
|
||||
// Cache namespace if there is one
|
||||
if (!string.IsNullOrEmpty(type.Namespace) && !uniqueNamespaces.Contains(type.Namespace))
|
||||
{
|
||||
uniqueNamespaces.Add(type.Namespace);
|
||||
@ -97,16 +101,16 @@ namespace UnityExplorer
|
||||
AllNamespaces.Insert(i, type.Namespace);
|
||||
}
|
||||
|
||||
// Cache the type. Overwrite type if one exists with the full name
|
||||
if (AllTypes.ContainsKey(type.FullName))
|
||||
AllTypes[type.FullName] = type;
|
||||
else
|
||||
{
|
||||
AllTypes.Add(type.FullName, type);
|
||||
//allTypeNames.Add(type.FullName);
|
||||
}
|
||||
|
||||
// Invoke listener
|
||||
OnTypeLoaded?.Invoke(type);
|
||||
|
||||
// Check type inheritance cache, add this to any lists it should be in
|
||||
foreach (var key in typeInheritance.Keys)
|
||||
{
|
||||
try
|
||||
@ -151,13 +155,6 @@ namespace UnityExplorer
|
||||
internal virtual string Internal_ProcessTypeInString(string theString, Type type)
|
||||
=> theString;
|
||||
|
||||
//// Force loading modules
|
||||
//public static bool LoadModule(string moduleName)
|
||||
// => Instance.Internal_LoadModule(moduleName);
|
||||
//
|
||||
//internal virtual bool Internal_LoadModule(string moduleName)
|
||||
// => false;
|
||||
|
||||
// Singleton finder
|
||||
|
||||
public static void FindSingleton(string[] possibleNames, Type type, BindingFlags flags, List<object> instances)
|
||||
@ -222,7 +219,7 @@ namespace UnityExplorer
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
#region Type and Generic Parameter implementation cache
|
||||
@ -357,7 +354,7 @@ namespace UnityExplorer
|
||||
return genericParameterInheritance[key];
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
|
||||
#region Internal MemberInfo Cache
|
||||
@ -434,20 +431,17 @@ namespace UnityExplorer
|
||||
|
||||
#region Reflection Blacklist
|
||||
|
||||
public virtual string DefaultReflectionBlacklist => string.Empty;
|
||||
public virtual string[] DefaultReflectionBlacklist => new string[0];
|
||||
|
||||
public static void LoadBlacklistString(string blacklist)
|
||||
{
|
||||
if (string.Equals(blacklist, "DEFAULT", StringComparison.InvariantCultureIgnoreCase))
|
||||
try
|
||||
{
|
||||
blacklist = Instance.DefaultReflectionBlacklist;
|
||||
ConfigManager.Reflection_Signature_Blacklist.Value = blacklist;
|
||||
ConfigManager.Handler.SaveConfig();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(blacklist))
|
||||
if (string.IsNullOrEmpty(blacklist) && !Instance.DefaultReflectionBlacklist.Any())
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var sigs = blacklist.Split(';');
|
||||
foreach (var sig in sigs)
|
||||
{
|
||||
@ -457,9 +451,25 @@ namespace UnityExplorer
|
||||
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)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception setting up reflection blacklist: {ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsBlacklisted(MemberInfo member)
|
||||
{
|
||||
|
@ -43,9 +43,9 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||
ExplorerCore.LogUnity(condition, type);
|
||||
}
|
||||
|
||||
public override void StartCoroutine(IEnumerator routine)
|
||||
public override void Update()
|
||||
{
|
||||
Il2CppCoroutine.Start(routine);
|
||||
Il2CppCoroutine.Process();
|
||||
}
|
||||
|
||||
internal override void ProcessOnPostRender()
|
||||
@ -53,9 +53,14 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
||||
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)
|
||||
|
@ -2,11 +2,11 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.UI.IValues;
|
||||
using System.Reflection;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
#if CPP
|
||||
using UnhollowerRuntimeLib;
|
||||
using UnhollowerBaseLib;
|
||||
@ -16,7 +16,7 @@ namespace UnityExplorer.Tests
|
||||
{
|
||||
public class TestIndexer : IList<int>
|
||||
{
|
||||
private readonly List<int> list = new List<int>() { 1,2,3,4,5 };
|
||||
private readonly List<int> list = new List<int>() { 1, 2, 3, 4, 5 };
|
||||
|
||||
public int Count => list.Count;
|
||||
public bool IsReadOnly => false;
|
||||
|
@ -13,7 +13,6 @@ namespace UnityExplorer
|
||||
public static class ToStringUtility
|
||||
{
|
||||
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 nullUnknown = nullString + " (?)";
|
||||
@ -132,23 +131,13 @@ namespace UnityExplorer
|
||||
|
||||
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))
|
||||
{
|
||||
try
|
||||
{
|
||||
var formatMethod = type.GetMethod("ToString", ArgumentUtility.ParseArgs);
|
||||
formatMethod.Invoke(value, new object[] { ParseUtility.NUMBER_FORMAT });
|
||||
toStringFormattedMethods.Add(type.AssemblyQualifiedName, formatMethod);
|
||||
toStringMethods.Add(type.AssemblyQualifiedName, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
var toStringMethod = type.GetMethod("ToString", ArgumentUtility.EmptyTypes);
|
||||
toStringMethods.Add(type.AssemblyQualifiedName, toStringMethod);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke the ToString method on the object
|
||||
|
||||
@ -157,9 +146,6 @@ namespace UnityExplorer
|
||||
string toString;
|
||||
try
|
||||
{
|
||||
if (toStringFormattedMethods.TryGetValue(type.AssemblyQualifiedName, out MethodInfo formatMethod))
|
||||
toString = (string)formatMethod.Invoke(value, new object[] { ParseUtility.NUMBER_FORMAT });
|
||||
else
|
||||
toString = (string)toStringMethods[type.AssemblyQualifiedName].Invoke(value, ArgumentUtility.EmptyArgs);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -2,9 +2,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
// Project-wide namespace for accessibility
|
||||
@ -107,5 +109,16 @@ namespace UnityExplorer
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
private static PropertyInfo onEndEdit;
|
||||
|
||||
public static UnityEvent<string> GetOnEndEdit(this InputField _this)
|
||||
{
|
||||
if (onEndEdit == null)
|
||||
onEndEdit = typeof(InputField).GetProperty("onEndEdit")
|
||||
?? throw new Exception("Could not get InputField.onEndEdit property!");
|
||||
|
||||
return onEndEdit.GetValue(_this, null).TryCast<UnityEvent<string>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,8 @@ using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.Tests;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.ObjectExplorer;
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer
|
||||
@ -19,7 +20,7 @@ namespace UnityExplorer
|
||||
public static class ExplorerCore
|
||||
{
|
||||
public const string NAME = "UnityExplorer";
|
||||
public const string VERSION = "4.0.3";
|
||||
public const string VERSION = "4.1.8";
|
||||
public const string AUTHOR = "Sinai";
|
||||
public const string GUID = "com.sinai.unityexplorer";
|
||||
|
||||
@ -102,7 +103,7 @@ namespace UnityExplorer
|
||||
RuntimeProvider.Instance.ProcessOnPostRender();
|
||||
}
|
||||
|
||||
#region LOGGING
|
||||
#region LOGGING
|
||||
|
||||
public static void Log(object message)
|
||||
=> 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">
|
||||
|
||||
<Target Name="ILRepacker" AfterTargets="Build">
|
||||
<!-- Actual merged assemblies -->
|
||||
<ItemGroup>
|
||||
<InputAssemblies Include="$(OutputPath)$(AssemblyName).dll" />
|
||||
<InputAssemblies Include="..\lib\mcs-unity\mcs\bin\Release\mcs.dll" />
|
||||
<InputAssemblies Include="packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- MonoMod for MelonLoader 0.3.0 -->
|
||||
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
|
||||
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.dll" />
|
||||
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Mdb.dll" />
|
||||
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Pdb.dll" />
|
||||
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Rocks.dll" />
|
||||
<InputAssemblies Include="packages\MonoMod.RuntimeDetour.20.1.1.4\lib\net35\MonoMod.RuntimeDetour.dll" />
|
||||
<InputAssemblies Include="packages\MonoMod.Utils.20.1.1.4\lib\net35\MonoMod.Utils.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Required references for ILRepack -->
|
||||
<ItemGroup>
|
||||
<ReferenceFolders Include="..\lib\" />
|
||||
<ReferenceFolders Include="..\lib\HarmonyX\Harmony\bin\Release\net35\" />
|
||||
<ReferenceFolders Include="packages\HarmonyX.2.4.2\lib\net35\" />
|
||||
<ReferenceFolders Include="..\lib\BepInEx.6.IL2CPP\" />
|
||||
<ReferenceFolders Include="..\lib\BepInEx.6.Mono\" />
|
||||
<ReferenceFolders Include="..\lib\BepInEx.5\" />
|
||||
<ReferenceFolders Include="..\lib\MelonLoader\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ILRepack
|
||||
Parallel="true"
|
||||
Internalize="true"
|
||||
@ -22,7 +35,8 @@
|
||||
LibraryPath="@(ReferenceFolders)"
|
||||
InputAssemblies="@(InputAssemblies)"
|
||||
TargetKind="Dll"
|
||||
OutputFile="$(OutputPath)$(AssemblyName).dll" />
|
||||
OutputFile="$(OutputPath)$(AssemblyName).dll"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
</Project>
|
@ -6,13 +6,13 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public class GameObjectInspector : InspectorBase
|
||||
{
|
||||
@ -64,7 +64,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
addCompInput.Text = "";
|
||||
|
||||
TransformTree.Clear();
|
||||
ComponentList.Clear();
|
||||
UpdateComponents();
|
||||
}
|
||||
|
||||
public override void CloseInspector()
|
||||
@ -113,6 +113,9 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
private IEnumerable<GameObject> GetTransformEntries()
|
||||
{
|
||||
if (!GOTarget)
|
||||
return Enumerable.Empty<GameObject>();
|
||||
|
||||
cachedChildren.Clear();
|
||||
for (int i = 0; i < GOTarget.transform.childCount; i++)
|
||||
cachedChildren.Add(GOTarget.transform.GetChild(i).gameObject);
|
||||
@ -125,41 +128,59 @@ namespace UnityExplorer.UI.Inspectors
|
||||
private readonly List<bool> behaviourEnabledStates = new List<bool>();
|
||||
|
||||
// ComponentList.GetRootEntriesMethod
|
||||
private List<Component> GetComponentEntries() => componentEntries;
|
||||
private List<Component> GetComponentEntries() => GOTarget ? componentEntries : Enumerable.Empty<Component>().ToList();
|
||||
|
||||
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.
|
||||
var comps = GOTarget.GetComponents<Component>();
|
||||
var behaviours = GOTarget.GetComponents<Behaviour>();
|
||||
|
||||
bool needRefresh = false;
|
||||
if (comps.Length != componentEntries.Count || behaviours.Length != behaviourEntries.Count)
|
||||
{
|
||||
needRefresh = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
int count = 0;
|
||||
foreach (var comp in comps)
|
||||
{
|
||||
if (!comp)
|
||||
continue;
|
||||
count++;
|
||||
if (!compInstanceIDs.Contains(comp.GetInstanceID()))
|
||||
{
|
||||
needRefresh = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!needRefresh)
|
||||
{
|
||||
for (int i = 0; i < behaviours.Length; i++)
|
||||
if (count != componentEntries.Count)
|
||||
needRefresh = true;
|
||||
else
|
||||
{
|
||||
var behaviour = behaviours[i];
|
||||
if (behaviour.enabled != behaviourEnabledStates[i])
|
||||
count = 0;
|
||||
foreach (var behaviour in behaviours)
|
||||
{
|
||||
if (!behaviour)
|
||||
continue;
|
||||
if (count >= behaviourEnabledStates.Count || behaviour.enabled != behaviourEnabledStates[count])
|
||||
{
|
||||
needRefresh = true;
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
if (!needRefresh && count != behaviourEntries.Count)
|
||||
needRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,9 +189,9 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
componentEntries.Clear();
|
||||
compInstanceIDs.Clear();
|
||||
|
||||
foreach (var comp in comps)
|
||||
{
|
||||
if (!comp) continue;
|
||||
componentEntries.Add(comp);
|
||||
compInstanceIDs.Add(comp.GetInstanceID());
|
||||
}
|
||||
@ -179,6 +200,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
behaviourEnabledStates.Clear();
|
||||
foreach (var behaviour in behaviours)
|
||||
{
|
||||
if (!behaviour) continue;
|
||||
behaviourEntries.Add(behaviour);
|
||||
behaviourEnabledStates.Add(behaviour.enabled);
|
||||
}
|
||||
@ -198,7 +220,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
private void OnAddComponentClicked(string input)
|
||||
{
|
||||
if (ReflectionUtility.AllTypes.TryGetValue(input, out Type type))
|
||||
if (ReflectionUtility.GetTypeByName(input) is Type type)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -221,8 +243,8 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
public override GameObject CreateContent(GameObject parent)
|
||||
{
|
||||
UIRoot = UIFactory.CreateVerticalGroup(Pool<GameObjectInspector>.Instance.InactiveHolder,
|
||||
"GameObjectInspector", true, false, true, true, 5, new Vector4(4, 4, 4, 4), new Color(0.065f, 0.065f, 0.065f));
|
||||
UIRoot = UIFactory.CreateVerticalGroup(parent, "GameObjectInspector", true, false, true, true, 5,
|
||||
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,
|
||||
new Color(0.065f, 0.065f, 0.065f));
|
@ -4,9 +4,10 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public class ComponentCell : ButtonCell
|
||||
{
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public class ComponentList : ButtonListHandler<Component, ComponentCell>
|
||||
{
|
||||
@ -21,7 +21,8 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
this.currentEntries.Clear();
|
||||
RefreshData();
|
||||
ScrollPool.Refresh(true, true);
|
||||
}
|
||||
|
||||
private bool CheckShouldDisplay(Component _, string __) => true;
|
@ -5,8 +5,9 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public class GameObjectControls
|
||||
{
|
||||
@ -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)
|
||||
{
|
||||
GOTarget.layer = value;
|
||||
@ -462,7 +469,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
//UIFactory.SetLayoutElement(pathApplyBtn.Component.gameObject, minHeight: 25, minWidth: 120);
|
||||
//pathApplyBtn.OnClick += () => { OnPathEndEdit(PathInput.Text); };
|
||||
|
||||
PathInput.Component.onEndEdit.AddListener((string val) => { OnPathEndEdit(val); });
|
||||
PathInput.Component.GetOnEndEdit().AddListener((string val) => { OnPathEndEdit(val); });
|
||||
|
||||
// Title and update row
|
||||
|
||||
@ -478,7 +485,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
NameInput = UIFactory.CreateInputField(titleRow, "NameInput", "untitled");
|
||||
UIFactory.SetLayoutElement(NameInput.Component.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999);
|
||||
NameInput.Component.textComponent.fontSize = 15;
|
||||
NameInput.Component.onEndEdit.AddListener((string val) => { OnNameEndEdit(val); });
|
||||
NameInput.Component.GetOnEndEdit().AddListener((string val) => { OnNameEndEdit(val); });
|
||||
|
||||
// second row (toggles, instanceID, tag, buttons)
|
||||
|
||||
@ -515,7 +522,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
TagInput = UIFactory.CreateInputField(secondRow, "TagInput", "none");
|
||||
UIFactory.SetLayoutElement(TagInput.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
|
||||
TagInput.Component.textComponent.color = Color.white;
|
||||
TagInput.Component.onEndEdit.AddListener((string val) => { OnTagEndEdit(val); });
|
||||
TagInput.Component.GetOnEndEdit().AddListener((string val) => { OnTagEndEdit(val); });
|
||||
|
||||
// Instantiate
|
||||
var instantiateBtn = UIFactory.CreateButton(secondRow, "InstantiateBtn", "Instantiate", new Color(0.2f, 0.2f, 0.2f));
|
||||
@ -533,6 +540,12 @@ namespace UnityExplorer.UI.Inspectors
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default);
|
||||
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
|
||||
var sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey);
|
||||
UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||
@ -547,7 +560,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||
|
||||
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;
|
||||
if (layerToNames == null)
|
||||
GetLayerNames();
|
||||
@ -632,7 +645,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
var inputField = UIFactory.CreateInputField(rowObj, "InputField", "...");
|
||||
UIFactory.SetLayoutElement(inputField.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
|
||||
|
||||
inputField.Component.onEndEdit.AddListener((string value) => { OnTransformInputEndEdit(type, value); });
|
||||
inputField.Component.GetOnEndEdit().AddListener((string value) => { OnTransformInputEndEdit(type, value); });
|
||||
|
||||
var control = new TransformControl(type, inputField);
|
||||
|
@ -11,7 +11,7 @@ using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public enum MouseInspectMode
|
||||
{
|
||||
@ -64,12 +64,15 @@ namespace UnityExplorer.UI.Inspectors
|
||||
internal static Camera MainCamera;
|
||||
internal static GraphicRaycaster[] graphicRaycasters;
|
||||
|
||||
|
||||
public void StartInspect(MouseInspectMode mode)
|
||||
{
|
||||
MainCamera = Camera.main;
|
||||
if (!MainCamera)
|
||||
|
||||
if (!MainCamera && mode == MouseInspectMode.World)
|
||||
{
|
||||
ExplorerCore.LogWarning("No MainCamera found! Cannot inspect world!");
|
||||
return;
|
||||
}
|
||||
|
||||
PanelDragger.ForceEnd();
|
||||
|
||||
@ -94,8 +97,14 @@ namespace UnityExplorer.UI.Inspectors
|
||||
public void StopInspect()
|
||||
{
|
||||
Inspecting = false;
|
||||
|
||||
UIManager.NavBarRect.gameObject.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);
|
||||
|
||||
if (Mode == MouseInspectMode.UI)
|
@ -4,10 +4,11 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public abstract class InspectorBase : IPooledObject
|
||||
{
|
@ -5,9 +5,9 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer
|
@ -4,10 +4,11 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public class InspectorTab : IPooledObject
|
||||
{
|
@ -10,14 +10,13 @@ using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
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 enabledButtonColor = new Color(0.2f, 0.27f, 0.2f);
|
||||
|
||||
private readonly Dictionary<BindingFlags, ButtonRef> scopeFilterButtons = new Dictionary<BindingFlags, ButtonRef>();
|
||||
private readonly List<Toggle> memberTypeToggles = new List<Toggle>();
|
||||
private InputFieldRef filterInputField;
|
||||
@ -75,7 +75,6 @@ namespace UnityExplorer.UI.Inspectors
|
||||
private IEnumerator InitCoroutine()
|
||||
{
|
||||
yield return null;
|
||||
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(InspectorPanel.Instance.ContentRect);
|
||||
}
|
||||
|
||||
@ -309,11 +308,8 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
private void CalculateLayouts()
|
||||
{
|
||||
// Calculate sizes
|
||||
LeftGroupWidth = (int)Math.Max(200, (0.4f * InspectorManager.PanelWidth) - 5);// Math.Min(450f, 0.4f * InspectorManager.PanelWidth - 5));
|
||||
LeftGroupWidth = (int)Math.Max(200, (0.4f * InspectorManager.PanelWidth) - 5);
|
||||
RightGroupWidth = (int)Math.Max(200, InspectorManager.PanelWidth - LeftGroupWidth - 65);
|
||||
|
||||
//memberTitleLayout.minWidth = LeftGroupWidth;
|
||||
}
|
||||
|
||||
private void SetCellLayout(CacheObjectCell cell)
|
||||
@ -344,7 +340,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
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));
|
||||
UIFactory.SetLayoutElement(mainContentHolder, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
@ -354,7 +350,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
// 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));
|
||||
UIFactory.SetLayoutElement(memberBorder, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
@ -482,7 +478,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
private void SetUnityTargets()
|
||||
{
|
||||
if (!typeof(UnityEngine.Object).IsAssignableFrom(TargetType))
|
||||
if (StaticOnly || !typeof(UnityEngine.Object).IsAssignableFrom(TargetType))
|
||||
{
|
||||
unityObjectRow.SetActive(false);
|
||||
textureViewer.SetActive(false);
|
||||
@ -619,12 +615,15 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
// Actual texture viewer
|
||||
|
||||
var imageObj = UIFactory.CreateUIObject("TextureViewerImage", textureViewer);
|
||||
textureImage = imageObj.AddComponent<Image>();
|
||||
textureImageLayout = textureImage.gameObject.AddComponent<LayoutElement>();
|
||||
var imageViewport = UIFactory.CreateVerticalGroup(textureViewer, "Viewport", false, false, true, true);
|
||||
imageViewport.GetComponent<Image>().color = Color.white;
|
||||
imageViewport.AddComponent<Mask>().showMaskGraphic = false;
|
||||
|
||||
var imageObj = UIFactory.CreateUIObject("Image", imageViewport);
|
||||
var fitter = imageObj.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
textureImage = imageObj.AddComponent<Image>();
|
||||
textureImageLayout = UIFactory.SetLayoutElement(imageObj, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
textureViewer.SetActive(false);
|
||||
}
|
@ -21,11 +21,7 @@ namespace UnityExplorer.Loader.BIE
|
||||
|
||||
public override void RegisterConfigElement<T>(ConfigElement<T> config)
|
||||
{
|
||||
object[] tags = null;
|
||||
if (config.IsInternal)
|
||||
tags = new[] { "Advanced" };
|
||||
|
||||
var entry = Config.Bind(CTG_NAME, config.Name, config.Value, new ConfigDescription(config.Description, null, tags));
|
||||
var entry = Config.Bind(CTG_NAME, config.Name, config.Value, config.Description);
|
||||
|
||||
entry.SettingChanged += (object o, EventArgs e) =>
|
||||
{
|
||||
|
@ -7,12 +7,12 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Loader.BIE;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.Loader.BIE;
|
||||
#if CPP
|
||||
using BepInEx.IL2CPP;
|
||||
using UnhollowerRuntimeLib;
|
||||
@ -46,7 +46,6 @@ namespace UnityExplorer
|
||||
private static readonly Harmony s_harmony = new Harmony(ExplorerCore.GUID);
|
||||
|
||||
public string ExplorerFolder => Path.Combine(Paths.PluginPath, ExplorerCore.NAME);
|
||||
public string ConfigFolder => Path.Combine(Paths.ConfigPath, ExplorerCore.NAME);
|
||||
|
||||
public Action<object> OnLogMessage => LogSource.LogMessage;
|
||||
public Action<object> OnLogWarning => LogSource.LogWarning;
|
||||
|
@ -10,7 +10,6 @@ namespace UnityExplorer
|
||||
{
|
||||
string ExplorerFolder { get; }
|
||||
|
||||
string ConfigFolder { get; }
|
||||
ConfigHandler ConfigHandler { get; }
|
||||
|
||||
Action<object> OnLogMessage { get; }
|
||||
|
@ -9,11 +9,15 @@ using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.Loader.ML;
|
||||
#if ML_LEGACY
|
||||
using Harmony;
|
||||
#else
|
||||
using HarmonyLib;
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
|
||||
#endif
|
||||
|
||||
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
|
||||
[assembly: MelonGame(null, null)]
|
||||
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
|
||||
[assembly: MelonColor(ConsoleColor.DarkCyan)]
|
||||
|
||||
namespace UnityExplorer
|
||||
@ -23,7 +27,6 @@ namespace UnityExplorer
|
||||
public static ExplorerMelonMod Instance;
|
||||
|
||||
public string ExplorerFolder => Path.Combine("Mods", ExplorerCore.NAME);
|
||||
public string ConfigFolder => ExplorerFolder;
|
||||
|
||||
public ConfigHandler ConfigHandler => _configHandler;
|
||||
public MelonLoaderConfigHandler _configHandler;
|
||||
@ -67,7 +70,11 @@ namespace UnityExplorer
|
||||
try
|
||||
{
|
||||
var prop = type.GetProperty(property);
|
||||
#if ML_LEGACY
|
||||
this.Harmony.Patch(prop.GetSetMethod(), prefix: prefix);
|
||||
#else
|
||||
HarmonyInstance.Patch(prop.GetSetMethod(), prefix: prefix);
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -1,4 +1,7 @@
|
||||
#if ML
|
||||
|
||||
#if !ML_LEGACY // ML 0.3.1+ config handler
|
||||
|
||||
using MelonLoader;
|
||||
using System;
|
||||
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
|
@ -76,8 +76,6 @@ namespace UnityExplorer
|
||||
}
|
||||
private static string s_explorerFolder;
|
||||
|
||||
public string ConfigFolder => ExplorerFolder;
|
||||
|
||||
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.OnLogError => (object log) => { OnLog?.Invoke(log?.ToString() ?? "", LogType.Error); };
|
||||
|
@ -13,11 +13,11 @@ namespace UnityExplorer.Loader.STANDALONE
|
||||
public class StandaloneConfigHandler : ConfigHandler
|
||||
{
|
||||
internal static IniDataParser _parser;
|
||||
internal static string INI_PATH;
|
||||
internal static string CONFIG_PATH;
|
||||
|
||||
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.Configuration.CommentString = "#";
|
||||
}
|
||||
@ -49,10 +49,10 @@ namespace UnityExplorer.Loader.STANDALONE
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(INI_PATH))
|
||||
if (!File.Exists(CONFIG_PATH))
|
||||
return false;
|
||||
|
||||
string ini = File.ReadAllText(INI_PATH);
|
||||
string ini = File.ReadAllText(CONFIG_PATH);
|
||||
|
||||
var data = _parser.Parse(ini);
|
||||
|
||||
@ -97,10 +97,10 @@ namespace UnityExplorer.Loader.STANDALONE
|
||||
foreach (var entry in ConfigManager.ConfigElements)
|
||||
sec.AddKey(entry.Key, entry.Value.BoxedValue.ToString());
|
||||
|
||||
if (!Directory.Exists(ExplorerCore.Loader.ConfigFolder))
|
||||
Directory.CreateDirectory(ExplorerCore.Loader.ConfigFolder);
|
||||
if (!Directory.Exists(ExplorerCore.Loader.ExplorerFolder))
|
||||
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 UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.ObjectExplorer
|
||||
namespace UnityExplorer.ObjectExplorer
|
||||
{
|
||||
public class ObjectSearch : UIModel
|
||||
{
|
||||
@ -55,8 +53,8 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
if (m_context == SearchContext.Singleton)
|
||||
currentResults = SearchProvider.SingletonSearch(nameInputField.Text);
|
||||
else if (m_context == SearchContext.StaticClass)
|
||||
currentResults = SearchProvider.StaticClassSearch(nameInputField.Text);
|
||||
else if (m_context == SearchContext.Class)
|
||||
currentResults = SearchProvider.ClassSearch(nameInputField.Text);
|
||||
else
|
||||
{
|
||||
string compType = "";
|
||||
@ -79,7 +77,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
lastCheckedTypeInput = desiredTypeInput;
|
||||
|
||||
//var type = ReflectionUtility.GetTypeByName(desiredTypeInput);
|
||||
if (ReflectionUtility.AllTypes.TryGetValue(desiredTypeInput, out var cachedType))
|
||||
if (ReflectionUtility.GetTypeByName(desiredTypeInput) is Type cachedType)
|
||||
{
|
||||
var type = cachedType;
|
||||
lastTypeCanHaveGO = typeof(Component).IsAssignableFrom(type) || type == typeof(GameObject);
|
||||
@ -132,8 +130,11 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
if (!cachedCellTexts.ContainsKey(index))
|
||||
{
|
||||
string text;
|
||||
if (m_context == SearchContext.StaticClass)
|
||||
text = SignatureHighlighter.Parse(currentResults[index] as Type, true);
|
||||
if (m_context == SearchContext.Class)
|
||||
{
|
||||
var type = currentResults[index] as Type;
|
||||
text = $"{SignatureHighlighter.Parse(type, true)} <color=grey><i>({type.Assembly.GetName().Name})</i></color>";
|
||||
}
|
||||
else
|
||||
text = ToStringUtility.ToStringWithType(currentResults[index], currentResults[index]?.GetActualType());
|
||||
|
||||
@ -145,7 +146,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
private void OnCellClicked(int dataIndex)
|
||||
{
|
||||
if (m_context == SearchContext.StaticClass)
|
||||
if (m_context == SearchContext.Class)
|
||||
InspectorManager.Inspect(currentResults[dataIndex] as Type);
|
||||
else
|
||||
InspectorManager.Inspect(currentResults[dataIndex]);
|
@ -8,11 +8,12 @@ using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.ObjectExplorer
|
||||
namespace UnityExplorer.ObjectExplorer
|
||||
{
|
||||
public class SceneExplorer : UIModel
|
||||
{
|
||||
@ -39,7 +40,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
private GameObject refreshRow;
|
||||
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;
|
||||
|
||||
@ -58,6 +59,26 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
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)
|
||||
{
|
||||
if (value < 0 || SceneHandler.LoadedScenes.Count <= value)
|
||||
@ -71,12 +92,12 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
private void SceneHandler_OnInspectedSceneChanged(Scene scene)
|
||||
{
|
||||
if (!sceneToDropdownOption.ContainsKey(scene.handle))
|
||||
if (!sceneToDropdownOption.ContainsKey(scene))
|
||||
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);
|
||||
if (sceneDropdown.value != idx)
|
||||
sceneDropdown.value = idx;
|
||||
@ -114,7 +135,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
var option = new Dropdown.OptionData(name);
|
||||
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))
|
||||
{
|
||||
Tree.displayedObjects.Clear();
|
||||
Tree.cachedTransforms.Clear();
|
||||
}
|
||||
|
||||
Tree.CurrentFilter = input;
|
@ -6,7 +6,7 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace UnityExplorer.Core
|
||||
namespace UnityExplorer.ObjectExplorer
|
||||
{
|
||||
public static class SceneHandler
|
||||
{
|
||||
@ -15,16 +15,16 @@ namespace UnityExplorer.Core
|
||||
/// </summary>
|
||||
public static Scene? SelectedScene
|
||||
{
|
||||
get => m_selectedScene;
|
||||
get => selectedScene;
|
||||
internal set
|
||||
{
|
||||
if (m_selectedScene != null && m_selectedScene?.handle == value?.handle)
|
||||
if (selectedScene != null && selectedScene == value)
|
||||
return;
|
||||
m_selectedScene = value;
|
||||
OnInspectedSceneChanged?.Invoke((Scene)m_selectedScene);
|
||||
selectedScene = value;
|
||||
OnInspectedSceneChanged?.Invoke((Scene)selectedScene);
|
||||
}
|
||||
}
|
||||
private static Scene? m_selectedScene;
|
||||
private static Scene? selectedScene;
|
||||
|
||||
/// <summary>
|
||||
/// The GameObjects in the currently inspected scene.
|
||||
@ -37,6 +37,7 @@ namespace UnityExplorer.Core
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<Scene> LoadedScenes => new ReadOnlyCollection<Scene>(allLoadedScenes);
|
||||
private static readonly List<Scene> allLoadedScenes = new List<Scene>();
|
||||
private static HashSet<Scene> previousLoadedScenes;
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
|
||||
/// <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>
|
||||
public static int LoadedSceneCount => SceneManager.sceneCount + 2;
|
||||
|
||||
@ -82,25 +83,7 @@ namespace UnityExplorer.Core
|
||||
}
|
||||
private static GameObject dontDestroyObject;
|
||||
|
||||
public static bool InspectingAssetScene => SelectedScene == AssetScene;
|
||||
|
||||
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;
|
||||
public static bool InspectingAssetScene => SelectedScene.HasValue && SelectedScene.Value == default;
|
||||
|
||||
internal static void Init()
|
||||
{
|
||||
@ -122,46 +105,40 @@ namespace UnityExplorer.Core
|
||||
catch (Exception ex)
|
||||
{
|
||||
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()
|
||||
{
|
||||
int curHandle = SelectedScene?.handle ?? -1;
|
||||
// DontDestroyOnLoad always exists, so default to true if our curHandle is that handle.
|
||||
// otherwise we will check while iterating.
|
||||
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));
|
||||
// check if the loaded scenes changed. always confirm DontDestroy / HideAndDontSave
|
||||
int confirmedCount = 2;
|
||||
bool inspectedExists = SelectedScene == DontDestroyScene || (SelectedScene.HasValue && SelectedScene.Value == default);
|
||||
|
||||
allLoadedScenes.Clear();
|
||||
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
Scene scene = SceneManager.GetSceneAt(i);
|
||||
if (scene == default || scene.handle == -1 || !scene.isLoaded)
|
||||
if (scene == default || !scene.isLoaded)
|
||||
continue;
|
||||
|
||||
// If no changes yet, ensure the previous list contained this handle.
|
||||
if (!anyChange && !previousHandles.Contains(scene.handle))
|
||||
anyChange = true;
|
||||
// If no changes yet, ensure the previous list contained the scene
|
||||
if (previousLoadedScenes != null && previousLoadedScenes.Contains(scene))
|
||||
confirmedCount++;
|
||||
|
||||
// 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;
|
||||
|
||||
allLoadedScenes.Add(scene);
|
||||
}
|
||||
|
||||
// Always add the DontDestroyOnLoad scene and the "none" scene.
|
||||
bool anyChange = confirmedCount != allLoadedScenes.Count;
|
||||
|
||||
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.
|
||||
if (!inspectedExists)
|
||||
@ -181,14 +158,14 @@ namespace UnityExplorer.Core
|
||||
else
|
||||
{
|
||||
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GameObject));
|
||||
var list = new List<GameObject>();
|
||||
var objects = new List<GameObject>();
|
||||
foreach (var obj in allObjects)
|
||||
{
|
||||
var go = obj.TryCast<GameObject>();
|
||||
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.Runtime;
|
||||
|
||||
namespace UnityExplorer.UI.ObjectExplorer
|
||||
namespace UnityExplorer.ObjectExplorer
|
||||
{
|
||||
public enum SearchContext
|
||||
{
|
||||
UnityObject,
|
||||
// GameObject,
|
||||
Singleton,
|
||||
StaticClass
|
||||
Class
|
||||
}
|
||||
|
||||
public enum ChildFilter
|
||||
@ -45,9 +44,9 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
case SceneFilter.DontDestroyOnLoad:
|
||||
return scene == SceneHandler.DontDestroyScene;
|
||||
case SceneFilter.HideAndDontSave:
|
||||
return scene == SceneHandler.AssetScene;
|
||||
return scene == default;
|
||||
case SceneFilter.ActivelyLoaded:
|
||||
return scene != SceneHandler.DontDestroyScene && scene != SceneHandler.AssetScene;
|
||||
return scene != SceneHandler.DontDestroyScene && scene != default;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -58,25 +57,13 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
{
|
||||
var results = new List<object>();
|
||||
|
||||
Type searchType;
|
||||
switch (context)
|
||||
{
|
||||
//case SearchContext.GameObject:
|
||||
// searchType = typeof(GameObject);
|
||||
// break;
|
||||
|
||||
case SearchContext.UnityObject:
|
||||
default:
|
||||
|
||||
Type searchType = null;
|
||||
if (!string.IsNullOrEmpty(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!");
|
||||
}
|
||||
@ -84,13 +71,8 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
ExplorerCore.LogWarning($"Could not find any type by name '{customTypeInput}'!");
|
||||
}
|
||||
|
||||
searchType = typeof(UnityEngine.Object);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (searchType == null)
|
||||
return results;
|
||||
searchType = typeof(UnityEngine.Object);
|
||||
|
||||
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(searchType);
|
||||
|
||||
@ -100,7 +82,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
if (!string.IsNullOrEmpty(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)
|
||||
{
|
||||
@ -108,13 +90,21 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
if (!string.IsNullOrEmpty(nameFilter) && !obj.name.ContainsIgnoreCase(nameFilter))
|
||||
continue;
|
||||
|
||||
if (canGetGameObject)
|
||||
{
|
||||
var go = searchType == typeof(GameObject)
|
||||
? obj.TryCast<GameObject>()
|
||||
: obj.TryCast<Component>().gameObject;
|
||||
GameObject go = null;
|
||||
var type = obj.GetActualType();
|
||||
|
||||
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
|
||||
if (sceneFilter != SceneFilter.Any)
|
||||
@ -143,7 +133,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
return results;
|
||||
}
|
||||
|
||||
internal static List<object> StaticClassSearch(string input)
|
||||
internal static List<object> ClassSearch(string input)
|
||||
{
|
||||
var list = new List<object>();
|
||||
|
||||
@ -153,11 +143,10 @@ namespace UnityExplorer.UI.ObjectExplorer
|
||||
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
foreach (var type in asm.TryGetTypes().Where(it => it.IsSealed && it.IsAbstract))
|
||||
foreach (var type in asm.TryGetTypes())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ContainsIgnoreCase(nameFilter))
|
||||
continue;
|
||||
|
||||
list.Add(type);
|
||||
}
|
||||
}
|
Binary file not shown.
@ -16,8 +16,11 @@ namespace UnityExplorer.UI
|
||||
{
|
||||
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);
|
||||
entry.OnValueChanged?.Invoke(entry.Component.text);
|
||||
}
|
||||
@ -47,8 +50,8 @@ namespace UnityExplorer.UI
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -6,8 +7,8 @@ using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.UI.CSConsole;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.CSConsole;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
@ -18,10 +19,11 @@ namespace UnityExplorer.UI.Panels
|
||||
public override int MinWidth => 750;
|
||||
public override int MinHeight => 300;
|
||||
|
||||
public InputFieldScroller InputScroll { get; private set; }
|
||||
public InputFieldRef Input => InputScroll.InputField;
|
||||
public InputFieldScroller InputScroller { get; private set; }
|
||||
public InputFieldRef Input => InputScroller.InputField;
|
||||
public Text InputText { get; private set; }
|
||||
public Text HighlightText { get; private set; }
|
||||
public Text LineNumberText { get; private set; }
|
||||
|
||||
public Dropdown HelpDropdown { get; private set; }
|
||||
|
||||
@ -33,6 +35,7 @@ namespace UnityExplorer.UI.Panels
|
||||
public Action<bool> OnCtrlRToggled;
|
||||
public Action<bool> OnSuggestionsToggled;
|
||||
public Action<bool> OnAutoIndentToggled;
|
||||
public Action OnPanelResized;
|
||||
|
||||
private void InvokeOnValueChanged(string value)
|
||||
{
|
||||
@ -60,6 +63,11 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
// UI Construction
|
||||
|
||||
public override void OnFinishResize(RectTransform panel)
|
||||
{
|
||||
OnPanelResized?.Invoke();
|
||||
}
|
||||
|
||||
protected internal override void DoSetDefaultPosAndAnchors()
|
||||
{
|
||||
Rect.localPosition = Vector2.zero;
|
||||
@ -121,19 +129,53 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
// Console Input
|
||||
|
||||
var inputArea = UIFactory.CreateUIObject("InputGroup", content);
|
||||
UIFactory.SetLayoutElement(inputArea, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(inputArea, false, true, true, true);
|
||||
inputArea.AddComponent<Image>().color = Color.white;
|
||||
inputArea.AddComponent<Mask>().showMaskGraphic = false;
|
||||
|
||||
// line numbers
|
||||
|
||||
var linesHolder = UIFactory.CreateUIObject("LinesHolder", inputArea);
|
||||
var linesRect = linesHolder.GetComponent<RectTransform>();
|
||||
linesRect.pivot = new Vector2(0, 1);
|
||||
linesRect.anchorMin = new Vector2(0, 0);
|
||||
linesRect.anchorMax = new Vector2(0, 1);
|
||||
linesRect.sizeDelta = new Vector2(0, 305000);
|
||||
linesRect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, 0, 50);
|
||||
linesHolder.AddComponent<Image>().color = new Color(0.05f, 0.05f, 0.05f);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(linesHolder, true, true, true, true);
|
||||
|
||||
LineNumberText = UIFactory.CreateLabel(linesHolder, "LineNumbers", "1", TextAnchor.UpperCenter, Color.grey, fontSize: 16);
|
||||
LineNumberText.font = UIManager.ConsoleFont;
|
||||
|
||||
// input field
|
||||
|
||||
int fontSize = 16;
|
||||
|
||||
var inputObj = UIFactory.CreateScrollInputField(this.content, "ConsoleInput", ConsoleController.STARTUP_TEXT, out var inputScroller, fontSize);
|
||||
InputScroll = inputScroller;
|
||||
var inputObj = UIFactory.CreateScrollInputField(inputArea, "ConsoleInput", ConsoleController.STARTUP_TEXT,
|
||||
out var inputScroller, fontSize);
|
||||
InputScroller = inputScroller;
|
||||
ConsoleController.defaultInputFieldAlpha = Input.Component.selectionColor.a;
|
||||
Input.OnValueChanged += InvokeOnValueChanged;
|
||||
|
||||
// move line number text with input field
|
||||
linesRect.transform.SetParent(inputObj.transform.Find("Viewport"), false);
|
||||
inputScroller.Slider.Scrollbar.onValueChanged.AddListener((float val) => { SetLinesPosition(); });
|
||||
inputScroller.Slider.Slider.onValueChanged.AddListener((float val) => { SetLinesPosition(); });
|
||||
void SetLinesPosition()
|
||||
{
|
||||
linesRect.anchoredPosition = new Vector2(linesRect.anchoredPosition.x, inputScroller.ContentRect.anchoredPosition.y);
|
||||
//SetInputLayout();
|
||||
}
|
||||
|
||||
InputText = Input.Component.textComponent;
|
||||
InputText.supportRichText = false;
|
||||
Input.PlaceholderText.fontSize = fontSize;
|
||||
InputText.color = Color.clear;
|
||||
Input.Component.customCaretColor = true;
|
||||
Input.Component.caretColor = Color.white;
|
||||
Input.PlaceholderText.fontSize = fontSize;
|
||||
|
||||
// Lexer highlight text overlay
|
||||
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", InputText.gameObject);
|
||||
@ -154,7 +196,19 @@ namespace UnityExplorer.UI.Panels
|
||||
Input.PlaceholderText.font = UIManager.ConsoleFont;
|
||||
HighlightText.font = UIManager.ConsoleFont;
|
||||
|
||||
RuntimeProvider.Instance.StartCoroutine(DelayedLayoutSetup());
|
||||
}
|
||||
|
||||
private IEnumerator DelayedLayoutSetup()
|
||||
{
|
||||
yield return null;
|
||||
SetInputLayout();
|
||||
}
|
||||
|
||||
public void SetInputLayout()
|
||||
{
|
||||
Input.Rect.offsetMin = new Vector2(52, Input.Rect.offsetMin.y);
|
||||
Input.Rect.offsetMax = new Vector2(2, Input.Rect.offsetMax.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.Inspectors;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
|
@ -11,8 +11,7 @@ using UnityEngine.UI;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.ObjectExplorer;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.ObjectExplorer;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
|
@ -5,8 +5,8 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.UI.CacheObject;
|
||||
using UnityExplorer.UI.CacheObject.Views;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Input;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using UnityExplorer.UI.Models;
|
||||
using System.Linq;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
@ -23,6 +23,7 @@ namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
s_resizeCursorObj.SetActive(false);
|
||||
wasAnyDragging = false;
|
||||
Resizing = false;
|
||||
|
||||
foreach (var instance in Instances)
|
||||
{
|
||||
|
@ -8,7 +8,6 @@ using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
@ -155,14 +154,13 @@ namespace UnityExplorer.UI.Panels
|
||||
// Prevent panel going oustide screen bounds
|
||||
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));
|
||||
|
||||
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();
|
||||
@ -226,7 +224,7 @@ namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
// create navbar button
|
||||
|
||||
NavButton = UIFactory.CreateButton(UIManager.NavbarButtonHolder, $"Button_{PanelType}", Name);
|
||||
NavButton = UIFactory.CreateButton(UIManager.NavbarTabButtonHolder, $"Button_{PanelType}", Name);
|
||||
var navBtn = NavButton.Component.gameObject;
|
||||
navBtn.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navBtn, false, true, true, true, 0, 0, 0, 5, 5, TextAnchor.MiddleCenter);
|
||||
|
@ -4,9 +4,16 @@ using System.Linq;
|
||||
using System.Text;
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// Each generic implementation has its own pool, business logic is here
|
||||
public class Pool<T> : Pool where T : IPooledObject
|
||||
{
|
||||
public static Pool<T> GetPool() => (Pool<T>)GetPool(typeof(T));
|
@ -5,7 +5,6 @@ using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI
|
||||
@ -410,56 +409,49 @@ namespace UnityExplorer.UI
|
||||
/// <summary>
|
||||
/// Create a Toggle control.
|
||||
/// </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 bgObj = CreateUIObject("Background", toggleObj);
|
||||
GameObject checkObj = CreateUIObject("Checkmark", bgObj);
|
||||
GameObject labelObj = CreateUIObject("Label", toggleObj);
|
||||
|
||||
SetLayoutGroup<HorizontalLayoutGroup>(toggleObj, false, false, true, true, 5, 0,0,0,0, childAlignment: TextAnchor.MiddleLeft);
|
||||
toggle = toggleObj.AddComponent<Toggle>();
|
||||
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.
|
||||
Toggle toggleComp = toggle;
|
||||
toggle.onValueChanged.AddListener(Deselect);
|
||||
void Deselect(bool _)
|
||||
{
|
||||
toggleComp.OnDeselect(null);
|
||||
}
|
||||
// Check mark background
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
// Label
|
||||
|
||||
GameObject labelObj = CreateUIObject("Label", toggleObj);
|
||||
text = labelObj.AddComponent<Text>();
|
||||
text.text = "Toggle";
|
||||
text.text = "";
|
||||
text.alignment = TextAnchor.MiddleLeft;
|
||||
SetDefaultTextValues(text);
|
||||
|
||||
SetLayoutElement(labelObj, minWidth: 0, flexibleWidth: 0, minHeight: checkHeight, flexibleHeight: 0);
|
||||
|
||||
// References
|
||||
|
||||
toggle.graphic = checkImage;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -730,7 +722,7 @@ namespace UnityExplorer.UI
|
||||
|
||||
var sliderContainer = CreateVerticalGroup(mainObj, "SliderContainer",
|
||||
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>();
|
||||
|
||||
CreateSliderScrollbar(sliderContainer, out Slider slider);
|
||||
|
@ -8,11 +8,10 @@ using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.UI.CSConsole;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.CSConsole;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
@ -56,9 +55,15 @@ namespace UnityExplorer.UI
|
||||
internal static Shader BackupShader { get; private set; }
|
||||
|
||||
public static RectTransform NavBarRect;
|
||||
public static GameObject NavbarButtonHolder;
|
||||
public static GameObject NavbarTabButtonHolder;
|
||||
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
|
||||
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);
|
||||
@ -81,6 +86,105 @@ namespace UnityExplorer.UI
|
||||
}
|
||||
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
|
||||
|
||||
public static UIPanel GetPanel(Panels panel)
|
||||
@ -121,40 +225,31 @@ namespace UnityExplorer.UI
|
||||
SetPanelActive(panel, value);
|
||||
}
|
||||
|
||||
// Main UI Update loop
|
||||
// navbar
|
||||
|
||||
private static int lastScreenWidth;
|
||||
private static int lastScreenHeight;
|
||||
|
||||
public static void Update()
|
||||
public static void SetNavBarAnchor()
|
||||
{
|
||||
if (!CanvasRoot || Initializing)
|
||||
return;
|
||||
|
||||
if (InspectUnderMouse.Inspecting)
|
||||
switch (NavbarAnchor)
|
||||
{
|
||||
InspectUnderMouse.Instance.UpdateInspect();
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (InputManager.GetKeyDown(ConfigManager.Master_Toggle.Value))
|
||||
ShowMenu = !ShowMenu;
|
||||
// listeners
|
||||
|
||||
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();
|
||||
|
||||
if (Screen.width != lastScreenWidth || Screen.height != lastScreenHeight)
|
||||
private static void OnScreenDimensionsChanged()
|
||||
{
|
||||
lastScreenWidth = Screen.width;
|
||||
lastScreenHeight = Screen.height;
|
||||
@ -166,46 +261,53 @@ namespace UnityExplorer.UI
|
||||
panel.Value.Dragger.OnEndResize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialization and UI Construction
|
||||
|
||||
internal static void InitUI()
|
||||
private static void OnCloseButtonClicked()
|
||||
{
|
||||
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;
|
||||
ShowMenu = false;
|
||||
}
|
||||
|
||||
private static void Master_Toggle_OnValueChanged(KeyCode val)
|
||||
{
|
||||
closeBtn.ButtonText.text = val.ToString();
|
||||
}
|
||||
|
||||
private static void OnTimeInputEndEdit(string val)
|
||||
{
|
||||
if (pauseButtonPausing)
|
||||
return;
|
||||
|
||||
if (float.TryParse(val, out float f))
|
||||
{
|
||||
Time.timeScale = f;
|
||||
lastTimeScale = f;
|
||||
}
|
||||
|
||||
timeInput.Text = Time.timeScale.ToString("F2");
|
||||
}
|
||||
|
||||
private static void OnPauseButtonClicked()
|
||||
{
|
||||
pauseButtonPausing = !pauseButtonPausing;
|
||||
|
||||
Time.timeScale = pauseButtonPausing ? 0f : lastTimeScale;
|
||||
|
||||
OnPauseButtonToggled();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
CanvasRoot = new GameObject("ExplorerCanvas");
|
||||
@ -240,30 +342,10 @@ namespace UnityExplorer.UI
|
||||
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()
|
||||
{
|
||||
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);
|
||||
NavBarRect = navbarPanel.GetComponent<RectTransform>();
|
||||
NavBarRect.pivot = new Vector2(0.5f, 1f);
|
||||
@ -279,14 +361,28 @@ namespace UnityExplorer.UI
|
||||
// UnityExplorer title
|
||||
|
||||
string titleTxt = $"{ExplorerCore.NAME} <i><color=grey>{ExplorerCore.VERSION}</color></i>";
|
||||
var title = UIFactory.CreateLabel(navbarPanel, "Title", titleTxt, TextAnchor.MiddleLeft, default, true, 18);
|
||||
UIFactory.SetLayoutElement(title.gameObject, minWidth: 180, flexibleWidth: 0);
|
||||
var title = UIFactory.CreateLabel(navbarPanel, "Title", titleTxt, TextAnchor.MiddleLeft, default, true, 17);
|
||||
UIFactory.SetLayoutElement(title.gameObject, minWidth: 170, flexibleWidth: 0);
|
||||
|
||||
// Navbar
|
||||
// panel tabs
|
||||
|
||||
NavbarButtonHolder = UIFactory.CreateUIObject("NavButtonHolder", navbarPanel);
|
||||
UIFactory.SetLayoutElement(NavbarButtonHolder, flexibleHeight: 999, flexibleWidth: 999);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(NavbarButtonHolder, false, true, true, true, 4, 2, 2, 2, 2);
|
||||
NavbarTabButtonHolder = UIFactory.CreateUIObject("NavTabButtonHolder", navbarPanel);
|
||||
UIFactory.SetLayoutElement(NavbarTabButtonHolder, minHeight: 25, flexibleHeight: 999, flexibleWidth: 999);
|
||||
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
|
||||
|
||||
@ -299,14 +395,13 @@ namespace UnityExplorer.UI
|
||||
|
||||
// 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);
|
||||
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));
|
||||
|
||||
ConfigManager.Master_Toggle.OnValueChanged += (KeyCode val) => { closeBtn.ButtonText.text = val.ToString(); };
|
||||
|
||||
closeBtn.OnClick += () => { ShowMenu = false; };
|
||||
ConfigManager.Master_Toggle.OnValueChanged += Master_Toggle_OnValueChanged;
|
||||
closeBtn.OnClick += OnCloseButtonClicked;
|
||||
}
|
||||
|
||||
#region UI AssetBundle
|
||||
|
@ -7,7 +7,6 @@ using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
@ -170,7 +169,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
|
||||
// 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 List<Suggestion> GetEntries() => Suggestions;
|
||||
|
@ -9,7 +9,6 @@ using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
{
|
||||
@ -88,7 +87,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
foreach (var entry in allowedTypes)
|
||||
|
@ -10,7 +10,7 @@ using UnityExplorer.Core;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Utility
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public class AutoSliderScrollbar : UIBehaviourModel
|
||||
{
|
||||
|
@ -4,7 +4,6 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
|
@ -4,9 +4,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
|
@ -4,12 +4,12 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Utility
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
// To fix an issue with Input Fields and allow them to go inside a ScrollRect nicely.
|
||||
|
||||
@ -80,12 +80,12 @@ namespace UnityExplorer.UI.Utility
|
||||
|
||||
if (ContentRect.rect.height < desiredHeight)
|
||||
{
|
||||
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
|
||||
ContentRect.sizeDelta = new Vector2(ContentRect.sizeDelta.x, desiredHeight);
|
||||
this.Slider.UpdateSliderHandle();
|
||||
}
|
||||
else if (ContentRect.rect.height > desiredHeight)
|
||||
{
|
||||
ContentRect.sizeDelta = new Vector2(0, desiredHeight);
|
||||
ContentRect.sizeDelta = new Vector2(ContentRect.sizeDelta.x, desiredHeight);
|
||||
this.Slider.UpdateSliderHandle();
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,6 @@ using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public class DataViewInfo
|
||||
{
|
||||
public int dataIndex;
|
||||
public float height, startPosition;
|
||||
public int normalizedSpread;
|
||||
|
||||
public static implicit operator float(DataViewInfo it) => it.height;
|
||||
}
|
||||
|
||||
public class DataHeightCache<T> where T : ICell
|
||||
{
|
||||
private ScrollPool<T> ScrollPool { get; }
|
||||
@ -53,14 +44,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
/// <summary>Get the first range (division of DefaultHeight) which the position appears in.</summary>
|
||||
private int GetRangeFloorOfPosition(float position) => (int)Math.Floor((decimal)position / (decimal)DefaultHeight);
|
||||
|
||||
/// <summary>Get the data index at the specified position of the total height cache.</summary>
|
||||
public int GetFirstDataIndexAtPosition(float desiredHeight) => GetFirstDataIndexAtPosition(desiredHeight, out _);
|
||||
|
||||
/// <summary>Get the data index and DataViewInfo at the specified position of the total height cache.</summary>
|
||||
public int GetFirstDataIndexAtPosition(float desiredHeight, out DataViewInfo cache)
|
||||
public int GetFirstDataIndexAtPosition(float desiredHeight)
|
||||
{
|
||||
cache = default;
|
||||
|
||||
if (!heightCache.Any())
|
||||
return 0;
|
||||
|
||||
@ -72,23 +57,21 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (rangeIndex >= rangeCache.Count)
|
||||
{
|
||||
int idx = ScrollPool.DataSource.ItemCount - 1;
|
||||
cache = heightCache[idx];
|
||||
return idx;
|
||||
}
|
||||
|
||||
int dataIndex = rangeCache[rangeIndex];
|
||||
cache = heightCache[dataIndex];
|
||||
var cache = heightCache[dataIndex];
|
||||
|
||||
// if the DataViewInfo is outdated, need to rebuild
|
||||
int expectedMin = GetRangeCeilingOfPosition(cache.startPosition);
|
||||
int expectedMax = expectedMin + cache.normalizedSpread - 1;
|
||||
if (rangeIndex < expectedMin || rangeIndex > expectedMax)
|
||||
{
|
||||
RecalculateStartPositions(Math.Max(dataIndex, expectedMax));
|
||||
RecalculateStartPositions(ScrollPool.DataSource.ItemCount - 1);
|
||||
|
||||
rangeIndex = GetRangeFloorOfPosition(desiredHeight);
|
||||
dataIndex = rangeCache[rangeIndex];
|
||||
cache = heightCache[dataIndex];
|
||||
}
|
||||
|
||||
return dataIndex;
|
||||
@ -116,17 +99,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
/// <summary>Append a data index to the cache with the provided height value.</summary>
|
||||
public void Add(float value)
|
||||
{
|
||||
value = (float)Math.Floor(value);
|
||||
value = Math.Max(DefaultHeight, value);
|
||||
|
||||
int spread = GetRangeSpread(totalHeight, value);
|
||||
|
||||
heightCache.Add(new DataViewInfo()
|
||||
{
|
||||
height = value,
|
||||
startPosition = TotalHeight,
|
||||
normalizedSpread = spread,
|
||||
});
|
||||
heightCache.Add(new DataViewInfo(heightCache.Count, value, totalHeight, spread));
|
||||
|
||||
int dataIdx = heightCache.Count - 1;
|
||||
for (int i = 0; i < spread; i++)
|
||||
@ -141,8 +118,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (!heightCache.Any())
|
||||
return;
|
||||
|
||||
var val = heightCache[heightCache.Count - 1];
|
||||
totalHeight -= val;
|
||||
totalHeight -= heightCache[heightCache.Count - 1];
|
||||
heightCache.RemoveAt(heightCache.Count - 1);
|
||||
|
||||
int idx = heightCache.Count;
|
||||
@ -195,28 +171,31 @@ namespace UnityExplorer.UI.Widgets
|
||||
int spread = GetRangeSpread(cache.startPosition, height);
|
||||
|
||||
// If the previous item in the range cache is not the previous data index, there is a gap.
|
||||
if (dataIndex > 0 && rangeCache[rangeIndex - 1] != (dataIndex - 1))
|
||||
if (rangeCache[rangeIndex] != dataIndex)
|
||||
{
|
||||
// Recalculate start positions up to this index. The gap could be anywhere before here.
|
||||
RecalculateStartPositions(dataIndex + 1);
|
||||
RecalculateStartPositions(ScrollPool.DataSource.ItemCount - 1);
|
||||
// Get the range index and spread again after rebuilding
|
||||
rangeIndex = GetRangeCeilingOfPosition(cache.startPosition);
|
||||
spread = GetRangeSpread(cache.startPosition, height);
|
||||
}
|
||||
|
||||
if (rangeCache.Count <= rangeIndex || rangeCache[rangeIndex] != dataIndex)
|
||||
throw new Exception("ScrollPool data height cache is corrupt or invalid, rebuild failed!");
|
||||
if (rangeCache[rangeIndex] != dataIndex)
|
||||
throw new IndexOutOfRangeException($"Trying to set dataIndex {dataIndex} at rangeIndex {rangeIndex}, but cache is corrupt or invalid!");
|
||||
|
||||
if (spread != cache.normalizedSpread)
|
||||
{
|
||||
int spreadDiff = spread - cache.normalizedSpread;
|
||||
cache.normalizedSpread = spread;
|
||||
|
||||
SetSpread(dataIndex, rangeIndex, spreadDiff);
|
||||
}
|
||||
UpdateSpread(dataIndex, rangeIndex, spreadDiff);
|
||||
}
|
||||
|
||||
private void SetSpread(int dataIndex, int rangeIndex, int spreadDiff)
|
||||
// set the struct back to the array
|
||||
heightCache[dataIndex] = cache;
|
||||
}
|
||||
|
||||
private void UpdateSpread(int dataIndex, int rangeIndex, int spreadDiff)
|
||||
{
|
||||
if (spreadDiff > 0)
|
||||
{
|
||||
@ -233,8 +212,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
rangeCache.RemoveAt(rangeIndex);
|
||||
spreadDiff++;
|
||||
}
|
||||
//for (int i = 0; i < -spreadDiff; i++)
|
||||
// rangeCache.RemoveAt(rangeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,38 +220,60 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (heightCache.Count <= 1)
|
||||
return;
|
||||
|
||||
DataViewInfo cache;
|
||||
DataViewInfo prev = null;
|
||||
for (int i = 0; i <= toIndex && i < heightCache.Count; i++)
|
||||
{
|
||||
cache = heightCache[i];
|
||||
rangeCache.Clear();
|
||||
|
||||
if (prev != null)
|
||||
DataViewInfo cache;
|
||||
DataViewInfo prev = DataViewInfo.None;
|
||||
for (int idx = 0; idx <= toIndex && idx < heightCache.Count; idx++)
|
||||
{
|
||||
cache = heightCache[idx];
|
||||
|
||||
if (!prev.Equals(DataViewInfo.None))
|
||||
cache.startPosition = prev.startPosition + prev.height;
|
||||
else
|
||||
cache.startPosition = 0;
|
||||
|
||||
var origSpread = cache.normalizedSpread;
|
||||
cache.normalizedSpread = GetRangeSpread(cache.startPosition, cache.height);
|
||||
if (cache.normalizedSpread != origSpread)
|
||||
SetSpread(i, GetRangeCeilingOfPosition(cache.startPosition), cache.normalizedSpread - origSpread);
|
||||
for (int i = 0; i < cache.normalizedSpread; i++)
|
||||
rangeCache.Add(cache.dataIndex);
|
||||
|
||||
heightCache[idx] = cache;
|
||||
|
||||
prev = cache;
|
||||
}
|
||||
}
|
||||
|
||||
//private void HardRebuildRanges()
|
||||
//{
|
||||
// var tempList = new List<float>();
|
||||
// for (int i = 0; i < heightCache.Count; i++)
|
||||
// tempList.Add(heightCache[i]);
|
||||
//
|
||||
// heightCache.Clear();
|
||||
// rangeCache.Clear();
|
||||
// totalHeight = 0;
|
||||
//
|
||||
// for (int i = 0; i < tempList.Count; i++)
|
||||
// SetIndex(i, tempList[i]);
|
||||
//}
|
||||
public struct DataViewInfo
|
||||
{
|
||||
// static
|
||||
public static DataViewInfo None => s_default;
|
||||
private static DataViewInfo s_default = default;
|
||||
|
||||
public static implicit operator float(DataViewInfo it) => it.height;
|
||||
|
||||
public DataViewInfo(int index, float height, float startPos, int spread)
|
||||
{
|
||||
this.dataIndex = index;
|
||||
this.height = height;
|
||||
this.startPosition = startPos;
|
||||
this.normalizedSpread = spread;
|
||||
}
|
||||
|
||||
// instance
|
||||
public int dataIndex, normalizedSpread;
|
||||
public float height, startPosition;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
var other = (DataViewInfo)obj;
|
||||
|
||||
return this.dataIndex == other.dataIndex
|
||||
&& this.height == other.height
|
||||
&& this.startPosition == other.startPosition
|
||||
&& this.normalizedSpread == other.normalizedSpread;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
|
@ -7,7 +7,6 @@ using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
@ -20,7 +19,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
/// <summary>
|
||||
/// An object-pooled ScrollRect, attempts to support content of any size and provide a scrollbar for it.
|
||||
/// </summary>
|
||||
public class ScrollPool<T> : UIBehaviourModel where T : ICell
|
||||
public class ScrollPool<T> : UIBehaviourModel, IEnumerable<CellInfo> where T : ICell
|
||||
{
|
||||
public ScrollPool(ScrollRect scrollRect)
|
||||
{
|
||||
@ -138,9 +137,42 @@ namespace UnityExplorer.UI.Widgets
|
||||
RefreshCells(setCellData, true);
|
||||
}
|
||||
|
||||
// Initialize
|
||||
public void JumpToIndex(int index, Action<T> onJumped)
|
||||
{
|
||||
RefreshCells(true, true);
|
||||
|
||||
//private bool Initialized;
|
||||
// Slide to the normalized position of the index
|
||||
var cache = HeightCache[index];
|
||||
float normalized = (cache.startPosition + (cache.height * 0.5f)) / HeightCache.TotalHeight;
|
||||
|
||||
RuntimeProvider.Instance.StartCoroutine(ForceDelayedJump(index, normalized, onJumped));
|
||||
}
|
||||
|
||||
private IEnumerator ForceDelayedJump(int dataIndex, float normalizedPos, Action<T> onJumped)
|
||||
{
|
||||
// Yielding two frames seems necessary in case the Explorer tab had not been opened before the jump.
|
||||
yield return null;
|
||||
yield return null;
|
||||
slider.value = normalizedPos;
|
||||
|
||||
// Get the cell containing the data index and invoke the onJumped listener for it
|
||||
foreach (var cellInfo in this)
|
||||
{
|
||||
if (cellInfo.dataIndex == dataIndex)
|
||||
{
|
||||
onJumped?.Invoke(CellPool[cellInfo.cellIndex]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IEnumerable
|
||||
|
||||
public IEnumerator<CellInfo> GetEnumerator() => EnumerateCellPool();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => EnumerateCellPool();
|
||||
|
||||
// Initialize
|
||||
|
||||
/// <summary>Should be called only once, when the scroll pool is created.</summary>
|
||||
public void Initialize(ICellPoolDataSource<T> dataSource, Action onHeightChangedListener = null)
|
||||
@ -161,13 +193,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
RuntimeProvider.Instance.StartCoroutine(InitCoroutine(onHeightChangedListener));
|
||||
}
|
||||
|
||||
private readonly WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
|
||||
|
||||
private IEnumerator InitCoroutine(Action onHeightChangedListener)
|
||||
{
|
||||
ScrollRect.content.anchoredPosition = Vector2.zero;
|
||||
//yield return null;
|
||||
yield return waitForEndOfFrame;
|
||||
yield return null;
|
||||
yield return null;
|
||||
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||
|
||||
@ -178,9 +208,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
// create initial cell pool and set cells
|
||||
CreateCellPool();
|
||||
|
||||
var enumerator = GetPoolEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
SetCell(CellPool[enumerator.Current.cellIndex], enumerator.Current.dataIndex);
|
||||
foreach (var cell in this)
|
||||
SetCell(CellPool[cell.cellIndex], cell.dataIndex);
|
||||
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||
prevContentHeight = Content.rect.height;
|
||||
@ -217,18 +246,18 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
// Cell pool
|
||||
|
||||
private CellInfo _cellInfo = new CellInfo();
|
||||
private CellInfo _current;
|
||||
|
||||
public IEnumerator<CellInfo> GetPoolEnumerator()
|
||||
private IEnumerator<CellInfo> EnumerateCellPool()
|
||||
{
|
||||
int cellIdx = topPoolIndex;
|
||||
int dataIndex = TopDataIndex;
|
||||
int iterated = 0;
|
||||
while (iterated < CellPool.Count)
|
||||
{
|
||||
_cellInfo.cellIndex = cellIdx;
|
||||
_cellInfo.dataIndex = dataIndex;
|
||||
yield return _cellInfo;
|
||||
_current.cellIndex = cellIdx;
|
||||
_current.dataIndex = dataIndex;
|
||||
yield return _current;
|
||||
|
||||
cellIdx++;
|
||||
if (cellIdx >= CellPool.Count)
|
||||
@ -368,16 +397,13 @@ namespace UnityExplorer.UI.Widgets
|
||||
CheckDataSourceCountChange(out bool jumpToBottom);
|
||||
|
||||
// update date height cache, and set cells if 'andReload'
|
||||
var enumerator = GetPoolEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
foreach (var cellInfo in this)
|
||||
{
|
||||
var curr = enumerator.Current;
|
||||
var cell = CellPool[curr.cellIndex];
|
||||
|
||||
var cell = CellPool[cellInfo.cellIndex];
|
||||
if (andReloadFromDataSource)
|
||||
SetCell(cell, curr.dataIndex);
|
||||
SetCell(cell, cellInfo.dataIndex);
|
||||
else
|
||||
HeightCache.SetIndex(curr.dataIndex, cell.Rect.rect.height);
|
||||
HeightCache.SetIndex(cellInfo.dataIndex, cell.Rect.rect.height);
|
||||
}
|
||||
|
||||
// force check recycles
|
||||
@ -405,12 +431,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
private void RefreshCellHeightsFast()
|
||||
{
|
||||
var enumerator = GetPoolEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
var curr = enumerator.Current;
|
||||
HeightCache.SetIndex(curr.dataIndex, CellPool[curr.cellIndex].Rect.rect.height);
|
||||
}
|
||||
foreach (var cellInfo in this)
|
||||
HeightCache.SetIndex(cellInfo.dataIndex, CellPool[cellInfo.cellIndex].Rect.rect.height);
|
||||
}
|
||||
|
||||
private void SetCell(T cachedCell, int dataIndex)
|
||||
@ -619,12 +641,10 @@ namespace UnityExplorer.UI.Widgets
|
||||
else
|
||||
{
|
||||
bottomDataIndex = desiredBottomIndex;
|
||||
var enumerator = GetPoolEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
foreach (var info in this)
|
||||
{
|
||||
var curr = enumerator.Current;
|
||||
var cell = CellPool[curr.cellIndex];
|
||||
SetCell(cell, curr.dataIndex);
|
||||
var cell = CellPool[info.cellIndex];
|
||||
SetCell(cell, info.dataIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
@ -17,6 +17,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
private bool m_enabled;
|
||||
|
||||
public Action<CachedTransform> OnExpandToggled;
|
||||
public Action<CachedTransform> OnEnableToggled;
|
||||
public Action<GameObject> OnGameObjectClicked;
|
||||
|
||||
public CachedTransform cachedTransform;
|
||||
@ -27,15 +28,20 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
public ButtonRef ExpandButton;
|
||||
public ButtonRef NameButton;
|
||||
public Toggle EnabledToggle;
|
||||
|
||||
public LayoutElement spacer;
|
||||
|
||||
public void OnMainButtonClicked()
|
||||
public void Enable()
|
||||
{
|
||||
if (cachedTransform.Value)
|
||||
OnGameObjectClicked?.Invoke(cachedTransform.Value.gameObject);
|
||||
else
|
||||
ExplorerCore.LogWarning("The object was destroyed!");
|
||||
m_enabled = true;
|
||||
UIRoot.SetActive(true);
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
m_enabled = false;
|
||||
UIRoot.SetActive(false);
|
||||
}
|
||||
|
||||
public void ConfigureCell(CachedTransform cached, int cellIndex)
|
||||
@ -59,6 +65,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
NameButton.ButtonText.text = cached.Value.name;
|
||||
NameButton.ButtonText.color = cached.Value.gameObject.activeSelf ? Color.white : Color.grey;
|
||||
|
||||
EnabledToggle.Set(cached.Value.gameObject.activeSelf, false);
|
||||
|
||||
int childCount = cached.Value.childCount;
|
||||
if (childCount > 0)
|
||||
{
|
||||
@ -82,16 +90,12 @@ namespace UnityExplorer.UI.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
public void OnMainButtonClicked()
|
||||
{
|
||||
m_enabled = false;
|
||||
UIRoot.SetActive(false);
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
m_enabled = true;
|
||||
UIRoot.SetActive(true);
|
||||
if (cachedTransform.Value)
|
||||
OnGameObjectClicked?.Invoke(cachedTransform.Value.gameObject);
|
||||
else
|
||||
ExplorerCore.LogWarning("The object was destroyed!");
|
||||
}
|
||||
|
||||
public void OnExpandClicked()
|
||||
@ -99,10 +103,15 @@ namespace UnityExplorer.UI.Widgets
|
||||
OnExpandToggled?.Invoke(cachedTransform);
|
||||
}
|
||||
|
||||
private void OnEnableClicked(bool value)
|
||||
{
|
||||
OnEnableToggled?.Invoke(cachedTransform);
|
||||
}
|
||||
|
||||
public GameObject CreateContent(GameObject parent)
|
||||
{
|
||||
UIRoot = UIFactory.CreateUIObject("TransformCell", parent);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(UIRoot, true, true, true, true, 2, childAlignment: TextAnchor.MiddleCenter);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(UIRoot, false, false, true, true, 2, childAlignment: TextAnchor.MiddleCenter);
|
||||
Rect = UIRoot.GetComponent<RectTransform>();
|
||||
Rect.anchorMin = new Vector2(0, 1);
|
||||
Rect.anchorMax = new Vector2(0, 1);
|
||||
@ -114,9 +123,19 @@ namespace UnityExplorer.UI.Widgets
|
||||
UIFactory.SetLayoutElement(spacerObj, minWidth: 0, flexibleWidth: 0, minHeight: 0, flexibleHeight: 0);
|
||||
this.spacer = spacerObj.GetComponent<LayoutElement>();
|
||||
|
||||
// Expand arrow
|
||||
|
||||
ExpandButton = UIFactory.CreateButton(this.UIRoot, "ExpandButton", "►");
|
||||
UIFactory.SetLayoutElement(ExpandButton.Component.gameObject, minWidth: 15, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
|
||||
|
||||
// Enabled toggle
|
||||
|
||||
var toggleObj = UIFactory.CreateToggle(UIRoot, "BehaviourToggle", out EnabledToggle, out var behavText, default, 17, 17);
|
||||
UIFactory.SetLayoutElement(toggleObj, minHeight: 17, flexibleHeight: 0, minWidth: 17);
|
||||
EnabledToggle.onValueChanged.AddListener(OnEnableClicked);
|
||||
|
||||
// Name button
|
||||
|
||||
NameButton = UIFactory.CreateButton(this.UIRoot, "NameButton", "Name", null);
|
||||
UIFactory.SetLayoutElement(NameButton.Component.gameObject, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0);
|
||||
var nameLabel = NameButton.Component.GetComponentInChildren<Text>();
|
||||
|
@ -6,8 +6,6 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
@ -22,13 +20,17 @@ namespace UnityExplorer.UI.Widgets
|
||||
/// Key: UnityEngine.Transform instance ID<br/>
|
||||
/// Value: CachedTransform
|
||||
/// </summary>
|
||||
internal readonly OrderedDictionary displayedObjects = new OrderedDictionary();
|
||||
internal readonly OrderedDictionary cachedTransforms = new OrderedDictionary();
|
||||
|
||||
// for keeping track of which actual transforms are expanded or not, outside of the cache data.
|
||||
private readonly HashSet<int> expandedInstanceIDs = new HashSet<int>();
|
||||
private readonly HashSet<int> autoExpandedIDs = new HashSet<int>();
|
||||
|
||||
public int ItemCount => displayedObjects.Count;
|
||||
private readonly HashSet<int> visited = new HashSet<int>();
|
||||
private bool needRefresh;
|
||||
private int displayIndex;
|
||||
|
||||
public int ItemCount => cachedTransforms.Count;
|
||||
|
||||
public bool Filtering => !string.IsNullOrEmpty(currentFilter);
|
||||
private bool wasFiltering;
|
||||
@ -50,6 +52,44 @@ namespace UnityExplorer.UI.Widgets
|
||||
}
|
||||
private string currentFilter;
|
||||
|
||||
public TransformTree(ScrollPool<TransformCell> scrollPool, Func<IEnumerable<GameObject>> getRootEntriesMethod)
|
||||
{
|
||||
ScrollPool = scrollPool;
|
||||
GetRootEntriesMethod = getRootEntriesMethod;
|
||||
}
|
||||
|
||||
public void OnCellBorrowed(TransformCell cell)
|
||||
{
|
||||
cell.OnExpandToggled += OnCellExpandToggled;
|
||||
cell.OnGameObjectClicked += OnGameObjectClicked;
|
||||
cell.OnEnableToggled += OnCellEnableToggled;
|
||||
}
|
||||
|
||||
private void OnGameObjectClicked(GameObject obj)
|
||||
{
|
||||
if (OnClickOverrideHandler != null)
|
||||
OnClickOverrideHandler.Invoke(obj);
|
||||
else
|
||||
InspectorManager.Inspect(obj);
|
||||
}
|
||||
|
||||
public void OnCellExpandToggled(CachedTransform cache)
|
||||
{
|
||||
var instanceID = cache.InstanceID;
|
||||
if (expandedInstanceIDs.Contains(instanceID))
|
||||
expandedInstanceIDs.Remove(instanceID);
|
||||
else
|
||||
expandedInstanceIDs.Add(instanceID);
|
||||
|
||||
RefreshData(true);
|
||||
}
|
||||
|
||||
public void OnCellEnableToggled(CachedTransform cache)
|
||||
{
|
||||
cache.Value.gameObject.SetActive(!cache.Value.gameObject.activeSelf);
|
||||
|
||||
RefreshData(true);
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
@ -58,29 +98,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
this.displayedObjects.Clear();
|
||||
this.cachedTransforms.Clear();
|
||||
displayIndex = 0;
|
||||
autoExpandedIDs.Clear();
|
||||
expandedInstanceIDs.Clear();
|
||||
}
|
||||
|
||||
|
||||
public void OnGameObjectClicked(GameObject obj)
|
||||
{
|
||||
if (OnClickOverrideHandler != null)
|
||||
{
|
||||
OnClickOverrideHandler.Invoke(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
InspectorManager.Inspect(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public TransformTree(ScrollPool<TransformCell> scrollPool, Func<IEnumerable<GameObject>> getRootEntriesMethod)
|
||||
{
|
||||
ScrollPool = scrollPool;
|
||||
GetRootEntriesMethod = getRootEntriesMethod;
|
||||
this.ScrollPool.Refresh(true, true);
|
||||
}
|
||||
|
||||
public bool IsCellExpanded(int instanceID)
|
||||
@ -89,6 +111,53 @@ namespace UnityExplorer.UI.Widgets
|
||||
: expandedInstanceIDs.Contains(instanceID);
|
||||
}
|
||||
|
||||
public void JumpAndExpandToTransform(Transform transform)
|
||||
{
|
||||
// make sure all parents of the object are expanded
|
||||
var parent = transform.parent;
|
||||
while (parent)
|
||||
{
|
||||
int pid = parent.GetInstanceID();
|
||||
if (!expandedInstanceIDs.Contains(pid))
|
||||
expandedInstanceIDs.Add(pid);
|
||||
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
// Refresh cached transforms (no UI rebuild yet)
|
||||
RefreshData(false);
|
||||
|
||||
int transformID = transform.GetInstanceID();
|
||||
|
||||
// find the index of our transform in the list and jump to it
|
||||
int idx;
|
||||
for (idx = 0; idx < cachedTransforms.Count; idx++)
|
||||
{
|
||||
var cache = (CachedTransform)cachedTransforms[idx];
|
||||
if (cache.InstanceID == transformID)
|
||||
break;
|
||||
}
|
||||
|
||||
ScrollPool.JumpToIndex(idx, OnCellJumpedTo);
|
||||
}
|
||||
|
||||
private void OnCellJumpedTo(TransformCell cell)
|
||||
{
|
||||
RuntimeProvider.Instance.StartCoroutine(HighlightCellCoroutine(cell));
|
||||
}
|
||||
|
||||
private IEnumerator HighlightCellCoroutine(TransformCell cell)
|
||||
{
|
||||
var button = cell.NameButton.Component;
|
||||
button.StartColorTween(new Color(0.2f, 0.3f, 0.2f), false);
|
||||
|
||||
float start = Time.realtimeSinceStartup;
|
||||
while (Time.realtimeSinceStartup - start < 1.5f)
|
||||
yield return null;
|
||||
|
||||
button.OnDeselect(null);
|
||||
}
|
||||
|
||||
public void Rebuild()
|
||||
{
|
||||
autoExpandedIDs.Clear();
|
||||
@ -97,10 +166,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
RefreshData(true, true);
|
||||
}
|
||||
|
||||
private readonly HashSet<int> visited = new HashSet<int>();
|
||||
private bool needRefresh;
|
||||
private int displayIndex;
|
||||
|
||||
public void RefreshData(bool andReload = false, bool jumpToTop = false)
|
||||
{
|
||||
visited.Clear();
|
||||
@ -114,12 +179,12 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (obj) Traverse(obj.transform);
|
||||
|
||||
// Prune displayed transforms that we didnt visit in that traverse
|
||||
for (int i = displayedObjects.Count - 1; i >= 0; i--)
|
||||
for (int i = cachedTransforms.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var obj = (CachedTransform)displayedObjects[i];
|
||||
var obj = (CachedTransform)cachedTransforms[i];
|
||||
if (!visited.Contains(obj.InstanceID))
|
||||
{
|
||||
displayedObjects.Remove(obj.InstanceID);
|
||||
cachedTransforms.Remove(obj.InstanceID);
|
||||
needRefresh = true;
|
||||
}
|
||||
}
|
||||
@ -159,9 +224,9 @@ namespace UnityExplorer.UI.Widgets
|
||||
visited.Add(instanceID);
|
||||
|
||||
CachedTransform cached;
|
||||
if (displayedObjects.Contains(instanceID))
|
||||
if (cachedTransforms.Contains(instanceID))
|
||||
{
|
||||
cached = (CachedTransform)displayedObjects[(object)instanceID];
|
||||
cached = (CachedTransform)cachedTransforms[(object)instanceID];
|
||||
if (cached.Update(transform, depth))
|
||||
needRefresh = true;
|
||||
}
|
||||
@ -169,10 +234,10 @@ namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
needRefresh = true;
|
||||
cached = new CachedTransform(this, transform, depth, parent);
|
||||
if (displayedObjects.Count <= displayIndex)
|
||||
displayedObjects.Add(instanceID, cached);
|
||||
if (cachedTransforms.Count <= displayIndex)
|
||||
cachedTransforms.Add(instanceID, cached);
|
||||
else
|
||||
displayedObjects.Insert(displayIndex, instanceID, cached);
|
||||
cachedTransforms.Insert(displayIndex, instanceID, cached);
|
||||
}
|
||||
|
||||
displayIndex++;
|
||||
@ -201,9 +266,9 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
public void SetCell(TransformCell cell, int index)
|
||||
{
|
||||
if (index < displayedObjects.Count)
|
||||
if (index < cachedTransforms.Count)
|
||||
{
|
||||
cell.ConfigureCell((CachedTransform)displayedObjects[index], index);
|
||||
cell.ConfigureCell((CachedTransform)cachedTransforms[index], index);
|
||||
if (Filtering)
|
||||
{
|
||||
if (cell.cachedTransform.Name.ContainsIgnoreCase(currentFilter))
|
||||
@ -215,27 +280,5 @@ namespace UnityExplorer.UI.Widgets
|
||||
else
|
||||
cell.Disable();
|
||||
}
|
||||
|
||||
public void ToggleExpandCell(CachedTransform cache)
|
||||
{
|
||||
var instanceID = cache.InstanceID;
|
||||
if (expandedInstanceIDs.Contains(instanceID))
|
||||
expandedInstanceIDs.Remove(instanceID);
|
||||
else
|
||||
expandedInstanceIDs.Add(instanceID);
|
||||
|
||||
RefreshData(true);
|
||||
}
|
||||
|
||||
public void OnCellBorrowed(TransformCell cell)
|
||||
{
|
||||
cell.OnExpandToggled += ToggleExpandCell;
|
||||
cell.OnGameObjectClicked += OnGameObjectClicked;
|
||||
}
|
||||
|
||||
//public void ReleaseCell(TransformCell cell)
|
||||
//{
|
||||
// cell.OnExpandToggled -= ToggleExpandCell;
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,24 @@
|
||||
<IsCpp>true</IsCpp>
|
||||
<IsStandalone>true</IsStandalone>
|
||||
</PropertyGroup>
|
||||
<!-- ML 0.3.0 CPP -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_MLLegacy_Cpp|AnyCPU'">
|
||||
<OutputPath>..\Release\UnityExplorer.MelonLoader_Legacy.Il2Cpp\</OutputPath>
|
||||
<DefineConstants>CPP,ML,ML_LEGACY</DefineConstants>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<AssemblyName>UnityExplorer.MLLEGACY.IL2CPP</AssemblyName>
|
||||
<IsCpp>true</IsCpp>
|
||||
<IsMelonLoaderLegacy>true</IsMelonLoaderLegacy>
|
||||
</PropertyGroup>
|
||||
<!-- ML 0.3.0 Mono -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_MLLegacy_Mono|AnyCPU'">
|
||||
<OutputPath>..\Release\UnityExplorer.MelonLoader_Legacy.Mono\</OutputPath>
|
||||
<DefineConstants>MONO,ML,ML_LEGACY</DefineConstants>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<AssemblyName>UnityExplorer.MLLEGACY.Mono</AssemblyName>
|
||||
<IsCpp>false</IsCpp>
|
||||
<IsMelonLoaderLegacy>true</IsMelonLoaderLegacy>
|
||||
</PropertyGroup>
|
||||
<!-- Global refs, Mono and Il2Cpp -->
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
@ -117,10 +135,17 @@
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<!-- MelonLoader Legacy refs -->
|
||||
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
|
||||
<Reference Include="MelonLoader">
|
||||
<HintPath>..\lib\MelonLoader_Legacy\MelonLoader.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<!-- BepInEx universal refs -->
|
||||
<ItemGroup Condition="'$(IsBepInEx)'=='true'">
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>..\lib\HarmonyX\Harmony\bin\Release\net35\0Harmony.dll</HintPath>
|
||||
<HintPath>packages\HarmonyX.2.4.2\lib\net35\0Harmony.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
@ -156,7 +181,7 @@
|
||||
<!-- Standalone refs -->
|
||||
<ItemGroup Condition="'$(IsStandalone)'=='true'">
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>..\lib\HarmonyX\Harmony\bin\Release\net35\0Harmony.dll</HintPath>
|
||||
<HintPath>packages\HarmonyX.2.4.2\lib\net35\0Harmony.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
@ -216,57 +241,56 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Core\Config\InternalConfigHandler.cs" />
|
||||
<Compile Include="UI\CacheObject\CacheConfigEntry.cs" />
|
||||
<Compile Include="UI\CacheObject\Views\CacheConfigCell.cs" />
|
||||
<Compile Include="UI\CSConsole\CSAutoCompleter.cs" />
|
||||
<Compile Include="UI\CSConsole\LexerBuilder.cs" />
|
||||
<Compile Include="UI\CSConsole\Lexers\CommentLexer.cs" />
|
||||
<Compile Include="UI\CSConsole\Lexers\KeywordLexer.cs" />
|
||||
<Compile Include="UI\CSConsole\Lexers\Lexer.cs" />
|
||||
<Compile Include="UI\CSConsole\Lexers\NumberLexer.cs" />
|
||||
<Compile Include="UI\CSConsole\Lexers\StringLexer.cs" />
|
||||
<Compile Include="UI\CSConsole\Lexers\SymbolLexer.cs" />
|
||||
<Compile Include="UI\CSConsole\ScriptEvaluator.cs" />
|
||||
<Compile Include="UI\CSConsole\ScriptInteraction.cs" />
|
||||
<Compile Include="CacheObject\CacheConfigEntry.cs" />
|
||||
<Compile Include="CacheObject\Views\CacheConfigCell.cs" />
|
||||
<Compile Include="CSConsole\CSAutoCompleter.cs" />
|
||||
<Compile Include="CSConsole\LexerBuilder.cs" />
|
||||
<Compile Include="CSConsole\Lexers\CommentLexer.cs" />
|
||||
<Compile Include="CSConsole\Lexers\KeywordLexer.cs" />
|
||||
<Compile Include="CSConsole\Lexers\Lexer.cs" />
|
||||
<Compile Include="CSConsole\Lexers\NumberLexer.cs" />
|
||||
<Compile Include="CSConsole\Lexers\StringLexer.cs" />
|
||||
<Compile Include="CSConsole\Lexers\SymbolLexer.cs" />
|
||||
<Compile Include="CSConsole\ScriptEvaluator.cs" />
|
||||
<Compile Include="CSConsole\ScriptInteraction.cs" />
|
||||
<Compile Include="Core\ExplorerBehaviour.cs" />
|
||||
<Compile Include="Core\Reflection\Extensions.cs" />
|
||||
<Compile Include="Core\Reflection\Il2CppReflection.cs" />
|
||||
<Compile Include="Core\Utility\ArgumentUtility.cs" />
|
||||
<Compile Include="Core\Utility\MiscUtility.cs" />
|
||||
<Compile Include="Core\Utility\ParseUtility.cs" />
|
||||
<Compile Include="UI\Inspectors\GameObjectWidgets\ComponentCell.cs" />
|
||||
<Compile Include="UI\Inspectors\GameObjectWidgets\ComponentList.cs" />
|
||||
<Compile Include="UI\Inspectors\GameObjectWidgets\GameObjectControls.cs" />
|
||||
<Compile Include="UI\Inspectors\InspectUnderMouse.cs" />
|
||||
<Compile Include="UI\CSConsole\ConsoleController.cs" />
|
||||
<Compile Include="UI\CacheObject\CacheField.cs" />
|
||||
<Compile Include="UI\CacheObject\CacheKeyValuePair.cs" />
|
||||
<Compile Include="UI\CacheObject\CacheListEntry.cs" />
|
||||
<Compile Include="UI\CacheObject\CacheMember.cs" />
|
||||
<Compile Include="UI\CacheObject\CacheMethod.cs" />
|
||||
<Compile Include="UI\CacheObject\CacheObjectBase.cs" />
|
||||
<Compile Include="UI\CacheObject\CacheProperty.cs" />
|
||||
<Compile Include="UI\CacheObject\Views\CacheKeyValuePairCell.cs" />
|
||||
<Compile Include="UI\CacheObject\Views\CacheListEntryCell.cs" />
|
||||
<Compile Include="UI\CacheObject\Views\CacheMemberCell.cs" />
|
||||
<Compile Include="UI\CacheObject\Views\CacheObjectCell.cs" />
|
||||
<Compile Include="UI\CacheObject\Views\EvaluateWidget.cs" />
|
||||
<Compile Include="UI\Inspectors\GameObjectInspector.cs" />
|
||||
<Compile Include="UI\CacheObject\ICacheObjectController.cs" />
|
||||
<Compile Include="UI\Inspectors\InspectorManager.cs" />
|
||||
<Compile Include="UI\Inspectors\InspectorTab.cs" />
|
||||
<Compile Include="UI\Inspectors\InspectorBase.cs" />
|
||||
<Compile Include="UI\IValues\InteractiveColor.cs" />
|
||||
<Compile Include="UI\IValues\InteractiveDictionary.cs" />
|
||||
<Compile Include="UI\IValues\InteractiveEnum.cs" />
|
||||
<Compile Include="UI\IValues\InteractiveList.cs" />
|
||||
<Compile Include="UI\IValues\InteractiveString.cs" />
|
||||
<Compile Include="UI\IValues\InteractiveValue.cs" />
|
||||
<Compile Include="UI\Inspectors\ReflectionInspector.cs" />
|
||||
<Compile Include="UI\IValues\InteractiveValueStruct.cs" />
|
||||
<Compile Include="Inspectors\GameObjectWidgets\ComponentCell.cs" />
|
||||
<Compile Include="Inspectors\GameObjectWidgets\ComponentList.cs" />
|
||||
<Compile Include="Inspectors\GameObjectWidgets\GameObjectControls.cs" />
|
||||
<Compile Include="Inspectors\InspectUnderMouse.cs" />
|
||||
<Compile Include="CSConsole\ConsoleController.cs" />
|
||||
<Compile Include="CacheObject\CacheField.cs" />
|
||||
<Compile Include="CacheObject\CacheKeyValuePair.cs" />
|
||||
<Compile Include="CacheObject\CacheListEntry.cs" />
|
||||
<Compile Include="CacheObject\CacheMember.cs" />
|
||||
<Compile Include="CacheObject\CacheMethod.cs" />
|
||||
<Compile Include="CacheObject\CacheObjectBase.cs" />
|
||||
<Compile Include="CacheObject\CacheProperty.cs" />
|
||||
<Compile Include="CacheObject\Views\CacheKeyValuePairCell.cs" />
|
||||
<Compile Include="CacheObject\Views\CacheListEntryCell.cs" />
|
||||
<Compile Include="CacheObject\Views\CacheMemberCell.cs" />
|
||||
<Compile Include="CacheObject\Views\CacheObjectCell.cs" />
|
||||
<Compile Include="CacheObject\Views\EvaluateWidget.cs" />
|
||||
<Compile Include="Inspectors\GameObjectInspector.cs" />
|
||||
<Compile Include="CacheObject\ICacheObjectController.cs" />
|
||||
<Compile Include="Inspectors\InspectorManager.cs" />
|
||||
<Compile Include="Inspectors\InspectorTab.cs" />
|
||||
<Compile Include="Inspectors\InspectorBase.cs" />
|
||||
<Compile Include="CacheObject\IValues\InteractiveColor.cs" />
|
||||
<Compile Include="CacheObject\IValues\InteractiveDictionary.cs" />
|
||||
<Compile Include="CacheObject\IValues\InteractiveEnum.cs" />
|
||||
<Compile Include="CacheObject\IValues\InteractiveList.cs" />
|
||||
<Compile Include="CacheObject\IValues\InteractiveString.cs" />
|
||||
<Compile Include="CacheObject\IValues\InteractiveValue.cs" />
|
||||
<Compile Include="Inspectors\ReflectionInspector.cs" />
|
||||
<Compile Include="CacheObject\IValues\InteractiveValueStruct.cs" />
|
||||
<Compile Include="UI\Models\InputFieldRef.cs" />
|
||||
<Compile Include="UI\ObjectPool\IPooledObject.cs" />
|
||||
<Compile Include="UI\ObjectPool\Pool.cs" />
|
||||
<Compile Include="UI\Pool.cs" />
|
||||
<Compile Include="UI\Panels\LogPanel.cs" />
|
||||
<Compile Include="UI\Panels\CSConsolePanel.cs" />
|
||||
<Compile Include="Core\Utility\IOUtility.cs" />
|
||||
@ -294,8 +318,8 @@
|
||||
<Compile Include="Core\Runtime\RuntimeContext.cs" />
|
||||
<Compile Include="Core\Runtime\RuntimeProvider.cs" />
|
||||
<Compile Include="Core\Runtime\TextureUtilProvider.cs" />
|
||||
<Compile Include="Core\SceneHandler.cs" />
|
||||
<Compile Include="UI\ObjectExplorer\SearchProvider.cs" />
|
||||
<Compile Include="ObjectExplorer\SceneHandler.cs" />
|
||||
<Compile Include="ObjectExplorer\SearchProvider.cs" />
|
||||
<Compile Include="Core\Tests\TestClass.cs" />
|
||||
<Compile Include="Core\Utility\UnityHelpers.cs" />
|
||||
<Compile Include="ExplorerCore.cs" />
|
||||
@ -320,8 +344,8 @@
|
||||
<Compile Include="UI\Widgets\AutoComplete\AutoCompleteModal.cs" />
|
||||
<Compile Include="UI\Widgets\AutoComplete\TypeCompleter.cs" />
|
||||
<Compile Include="UI\Models\ButtonRef.cs" />
|
||||
<Compile Include="UI\ObjectExplorer\ObjectSearch.cs" />
|
||||
<Compile Include="UI\ObjectExplorer\SceneExplorer.cs" />
|
||||
<Compile Include="ObjectExplorer\ObjectSearch.cs" />
|
||||
<Compile Include="ObjectExplorer\SceneExplorer.cs" />
|
||||
<Compile Include="UI\Widgets\ScrollPool\DataHeightCache.cs" />
|
||||
<Compile Include="UI\Widgets\ScrollPool\ICell.cs" />
|
||||
<Compile Include="UI\Widgets\ScrollPool\ICellPoolDataSource.cs" />
|
||||
@ -342,11 +366,11 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets" Condition="Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets')" />
|
||||
<Import Project="packages\ILRepack.Lib.MSBuild.Task.2.0.18.2\build\ILRepack.Lib.MSBuild.Task.targets" Condition="Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.2\build\ILRepack.Lib.MSBuild.Task.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets'))" />
|
||||
<Error Condition="!Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.2\build\ILRepack.Lib.MSBuild.Task.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\ILRepack.Lib.MSBuild.Task.2.0.18.2\build\ILRepack.Lib.MSBuild.Task.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user