mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2026-10-10 12:13:12 +08:00
Compare commits
108 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e1fb0e27b | |||
| 6b8a7d90c8 | |||
| 1b4657dead | |||
| 1af20ead9f | |||
| 706a18d1f6 | |||
| 81dd8bad0e | |||
| 97dffc81e1 | |||
| bf2b22e768 | |||
| d1fbbfa62d | |||
| 56a3cef245 | |||
| 61e7915a55 | |||
| 88e63c8d6a | |||
| 048e5980a0 | |||
| 3b851b6e08 | |||
| 4c029dad90 | |||
| 3d61011e59 | |||
| 5285239bc5 | |||
| 57d3a3f52e | |||
| c88182c831 | |||
| 02e0102041 | |||
| 6adecef785 | |||
| ff6c03e1f3 | |||
| 1aedc505b2 | |||
| dbe993a7c7 | |||
| 5a1676fb84 | |||
| a7a663aefa | |||
| 76c77fb082 | |||
| a25017df69 | |||
| a1fab0c4a7 | |||
| 4599747bfe | |||
| 3856e84c08 | |||
| 104288a912 | |||
| 41e8a5ae33 | |||
| ef4bc75d5e | |||
| 68b81c6b53 | |||
| bd86f09313 | |||
| b35d6f5787 | |||
| b97eada516 | |||
| 0a05848bef | |||
| 6e5610129a | |||
| acd30880a8 | |||
| f54ff89290 | |||
| 62d565777d | |||
| 870f82ab26 | |||
| 9370c5e0e6 | |||
| b8cf96438c | |||
| 7be7daf4d7 | |||
| 8f54415ae0 | |||
| aef4e11c01 | |||
| af7e32ec49 | |||
| 6f44a3376b | |||
| 3a6b573ac3 | |||
| cbe17927fb | |||
| 15f3f37948 | |||
| de6760e427 | |||
| 83edd1b9bb | |||
| 613be34e95 | |||
| 58c65b9b8b | |||
| 6fcf6a521c | |||
| 81a174f865 | |||
| b5e3cc2ea5 | |||
| 14f46ade6a | |||
| e92556805b | |||
| 8662742461 | |||
| 63393a9d66 | |||
| 13986f95c1 | |||
| b47bfa1e83 | |||
| 12c51248fe | |||
| 9b9cb54a79 | |||
| 6a28a93e3a | |||
| 32e718faeb | |||
| 4d46b74d54 | |||
| 7e5246cead | |||
| abf5267364 | |||
| 3afee7254c | |||
| 1643d4b7dd | |||
| cef8c12d20 | |||
| 5e07847356 | |||
| 2dc6e386df | |||
| ff882296fd | |||
| ecc33927ee | |||
| 6e91f2a792 | |||
| 97cb14d6fc | |||
| 8b861f7c77 | |||
| 9379e0f813 | |||
| bdda12a040 | |||
| 75bd654a94 | |||
| f174c7543a | |||
| 08f2c6035e | |||
| 475e24a66a | |||
| c62b93535d | |||
| 374d0b3bae | |||
| 1f87e89b97 | |||
| 495bc41a8d | |||
| 9cf62c3250 | |||
| 4c9b3115cd | |||
| ebdce70418 | |||
| 7c0b37440b | |||
| 0d8ab8bf14 | |||
| 5a3cad9be2 | |||
| 70d67f1dad | |||
| 469484d129 | |||
| c5e262d1c3 | |||
| 53c8dfcb6d | |||
| ae3ac21992 | |||
| 7765b64748 | |||
| a5023d03f4 | |||
| a5e6b65dee |
@@ -34,53 +34,59 @@ jobs:
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.BepInEx.IL2CPP.zip
|
||||
path: ./Release/UnityExplorer.BepInEx.IL2CPP.zip
|
||||
path: ./Release/UnityExplorer.BepInEx.IL2CPP/
|
||||
|
||||
# BepInEx IL2CPP CoreCLR
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.BepInEx.IL2CPP.CoreCLR.zip
|
||||
path: ./Release/UnityExplorer.BepInEx.IL2CPP.CoreCLR/
|
||||
|
||||
# BepInEx 5 Mono
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.BepInEx5.Mono.zip
|
||||
path: ./Release/UnityExplorer.BepInEx5.Mono.zip
|
||||
path: ./Release/UnityExplorer.BepInEx5.Mono/
|
||||
|
||||
# BepInEx 6 Mono
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.BepInEx6.Mono.zip
|
||||
path: ./Release/UnityExplorer.BepInEx6.Mono.zip
|
||||
path: ./Release/UnityExplorer.BepInEx6.Mono/
|
||||
|
||||
# Editor
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.Editor.zip
|
||||
path: ./Release/UnityExplorer.Editor.zip
|
||||
path: ./UnityEditorPackage/
|
||||
|
||||
# MelonLoader IL2CPP net6preview
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.MelonLoader.IL2CPP.net6preview.zip
|
||||
path: ./Release/UnityExplorer.MelonLoader.IL2CPP.net6preview.zip
|
||||
path: ./Release/UnityExplorer.MelonLoader.IL2CPP.net6preview/
|
||||
|
||||
# MelonLoader IL2CPP net472
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.MelonLoader.IL2CPP.zip
|
||||
path: ./Release/UnityExplorer.MelonLoader.IL2CPP.zip
|
||||
path: ./Release/UnityExplorer.MelonLoader.IL2CPP/
|
||||
|
||||
# MelonLoader Mono
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.MelonLoader.Mono.zip
|
||||
path: ./Release/UnityExplorer.MelonLoader.Mono.zip
|
||||
path: ./Release/UnityExplorer.MelonLoader.Mono/
|
||||
|
||||
# Standalone Il2Cpp
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.Standalone.IL2CPP.zip
|
||||
path: ./Release/UnityExplorer.Standalone.IL2CPP.zip
|
||||
path: ./Release/UnityExplorer.Standalone.IL2CPP/
|
||||
|
||||
# Standalone Mono
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: UnityExplorer.Standalone.Mono.zip
|
||||
path: ./Release/UnityExplorer.Standalone.Mono.zip
|
||||
path: ./Release/UnityExplorer.Standalone.Mono/
|
||||
|
||||
|
||||
@@ -18,11 +18,18 @@
|
||||
|
||||
⚡ Thunderstore releases: [BepInEx Mono](https://thunderstore.io/package/sinai-dev/UnityExplorer) | [BepInEx IL2CPP](https://gtfo.thunderstore.io/package/sinai-dev/UnityExplorer_IL2CPP) | [MelonLoader IL2CPP](https://boneworks.thunderstore.io/package/sinai-dev/UnityExplorer_IL2CPP_ML)
|
||||
|
||||
## Release schedule
|
||||
|
||||
Releases will be posted at most once per week, generally on weekends.
|
||||
|
||||
Nightly builds can be found [here](https://github.com/sinai-dev/UnityExplorer/actions).
|
||||
|
||||
## BepInEx
|
||||
|
||||
| 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 6.X (CoreCLR) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx.IL2CPP.CoreCLR.zip) | ✖ |
|
||||
| BIE 5.X | ✖️ n/a | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx5.Mono.zip) |
|
||||
|
||||
1. Unzip the release file into a folder
|
||||
@@ -32,10 +39,10 @@
|
||||
|
||||
## MelonLoader
|
||||
|
||||
| Release | IL2CPP | Mono |
|
||||
| ---------- | ------ | ---- |
|
||||
| ML 0.4/0.5 | ✅ [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.6 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.IL2CPP.net6preview.zip) | ✖️ |
|
||||
| Release | IL2CPP | Mono |
|
||||
| ------- | ------ | ---- |
|
||||
| ML 0.5 | ✅ [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.6 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader.IL2CPP.net6preview.zip) | ✖️ |
|
||||
|
||||
1. Unzip the release file into a folder
|
||||
2. Copy the DLL inside the `Mods` folder into your MelonLoader `Mods` folder
|
||||
@@ -84,6 +91,20 @@ If these fixes do not work, please create an issue in this repo and I'll do my b
|
||||
</a>
|
||||
</p>
|
||||
|
||||
### Inspector API
|
||||
|
||||
If you want to inspect an object or Type from outside the C# console, use the `InspectorManager` class:
|
||||
|
||||
**To inspect an object:**
|
||||
```csharp
|
||||
UnityExplorer.InspectorManager.Inspect(theObject);
|
||||
```
|
||||
|
||||
**To inspect a Type:**
|
||||
```cs
|
||||
UnityExplorer.InspectorManager.Inspect(typeof(SomeClass));
|
||||
```
|
||||
|
||||
### Object Explorer
|
||||
|
||||
* Use the <b>Scene Explorer</b> tab to traverse the active scenes, as well as the DontDestroyOnLoad and HideAndDontSave objects.
|
||||
@@ -104,7 +125,8 @@ The inspector is used to see detailed information on objects of any type and man
|
||||
* 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
|
||||
* For `Texture2D`, `Image`, `Sprite` and `Material` objects, there is a `View Texture` button at the top of the inspector which lets you view the Texture(s) and save them as a PNG file.
|
||||
* For `AudioClip` objects there is a `Show Player` button which opens an audio player widget. For clips which are loaded as `DecompressOnLoad`, there is also a button to save them to a `.wav` file.
|
||||
|
||||
### C# Console
|
||||
|
||||
@@ -115,7 +137,7 @@ The inspector is used to see detailed information on objects of any type and man
|
||||
### Hook Manager
|
||||
|
||||
* The Hooks panel allows you to hook methods at the click of a button for debugging purposes.
|
||||
* Simply enter any class (generic types not yet supported) and hook the methods you want from the menu.
|
||||
* Simply enter any class and hook the methods you want from the menu.
|
||||
* You can edit the source code of the generated hook with the "Edit Hook Source" button. Accepted method names are `Prefix` (which can return `bool` or `void`), `Postfix`, `Finalizer` (which can return `Exception` or `void`), and `Transpiler` (which must return `IEnumerable<HarmonyLib.CodeInstruction>`). You can define multiple patches if you wish.
|
||||
|
||||
### Mouse-Inspect
|
||||
@@ -124,6 +146,13 @@ The inspector is used to see detailed information on objects of any type and man
|
||||
* <b>World</b>: uses Physics.Raycast to look for Colliders
|
||||
* <b>UI</b>: uses GraphicRaycasters to find UI objects
|
||||
|
||||
### Freecam
|
||||
|
||||
* UnityExplorer provides a basic Free Camera which you can control with your keyboard and mouse.
|
||||
* Unlike all other features of UnityExplorer, you can still use Freecam while UnityExplorer's menu is hidden.
|
||||
* Supports using the game's main Camera or a separate custom Camera.
|
||||
* See the Freecam panel for further instructions and details.
|
||||
|
||||
### Clipboard
|
||||
|
||||
* The "Clipboard" panel allows you to see your current paste value, or clear it (resets it to `null`)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "com.sinai-dev.unityexplorer",
|
||||
"version": "4.7.0",
|
||||
"version": "4.7.12",
|
||||
"displayName": "UnityExplorer",
|
||||
"description": "An in-game UI for exploring, debugging and modifying Unity games.",
|
||||
"unity": "2017.1",
|
||||
|
||||
@@ -1,97 +1,155 @@
|
||||
# MelonLoader IL2CPP (net6)
|
||||
dotnet build src\UnityExplorer.sln -c Release_ML_Cpp_net6
|
||||
# (cleanup and move files)
|
||||
# ----------- MelonLoader IL2CPP (net6) -----------
|
||||
dotnet build src/UnityExplorer.sln -c Release_ML_Cpp_net6
|
||||
$Path = "Release\UnityExplorer.MelonLoader.IL2CPP.net6preview"
|
||||
Remove-Item $Path\UnityExplorer.ML.IL2CPP.net6preview.deps.json
|
||||
Remove-Item $Path\Tomlet.dll
|
||||
# ILRepack
|
||||
lib/ILRepack.exe /target:library /lib:lib/net6 /lib:lib/unhollowed /lib:$Path /internalize /out:$Path/UnityExplorer.ML.IL2CPP.net6preview.dll $Path/UnityExplorer.ML.IL2CPP.net6preview.dll $Path/mcs.dll
|
||||
# (cleanup and move files)
|
||||
Remove-Item $Path/UnityExplorer.ML.IL2CPP.net6preview.deps.json
|
||||
Remove-Item $Path/Tomlet.dll
|
||||
Remove-Item $Path/mcs.dll
|
||||
Remove-Item $Path/Iced.dll
|
||||
Remove-Item $Path/UnhollowerBaseLib.dll
|
||||
New-Item -Path "$Path" -Name "Mods" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path\UnityExplorer.ML.IL2CPP.net6preview.dll -Destination $Path\Mods -Force
|
||||
Move-Item -Path $Path/UnityExplorer.ML.IL2CPP.net6preview.dll -Destination $Path/Mods -Force
|
||||
New-Item -Path "$Path" -Name "UserLibs" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path\mcs.dll -Destination $Path\UserLibs -Force
|
||||
Move-Item -Path $Path\UniverseLib.IL2CPP.dll -Destination $Path\UserLibs -Force
|
||||
Move-Item -Path $Path/UniverseLib.IL2CPP.Unhollower.dll -Destination $Path/UserLibs -Force
|
||||
# (create zip archive)
|
||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.MelonLoader.IL2CPP.net6preview.zip -Force
|
||||
Remove-Item $Path/../UnityExplorer.MelonLoader.IL2CPP.net6preview.zip -ErrorAction SilentlyContinue
|
||||
7z a $Path/../UnityExplorer.MelonLoader.IL2CPP.net6preview.zip .\$Path\*
|
||||
|
||||
# MelonLoader IL2CPP (net472)
|
||||
dotnet build src\UnityExplorer.sln -c Release_ML_Cpp_net472
|
||||
# ----------- MelonLoader IL2CPP (net472) -----------
|
||||
dotnet build src/UnityExplorer.sln -c Release_ML_Cpp_net472
|
||||
$Path = "Release/UnityExplorer.MelonLoader.IL2CPP"
|
||||
# ILRepack
|
||||
lib/ILRepack.exe /target:library /lib:lib/net472 /lib:lib/net35 /lib:lib/unhollowed /lib:$Path /internalize /out:$Path/UnityExplorer.ML.IL2CPP.dll $Path/UnityExplorer.ML.IL2CPP.dll $Path/mcs.dll
|
||||
# (cleanup and move files)
|
||||
$Path = "Release\UnityExplorer.MelonLoader.IL2CPP"
|
||||
Remove-Item $Path\Tomlet.dll
|
||||
Remove-Item $Path/Tomlet.dll
|
||||
Remove-Item $Path/mcs.dll
|
||||
Remove-Item $Path/Iced.dll
|
||||
Remove-Item $Path/UnhollowerBaseLib.dll
|
||||
New-Item -Path "$Path" -Name "Mods" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path\UnityExplorer.ML.IL2CPP.dll -Destination $Path\Mods -Force
|
||||
Move-Item -Path $Path/UnityExplorer.ML.IL2CPP.dll -Destination $Path/Mods -Force
|
||||
New-Item -Path "$Path" -Name "UserLibs" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path\mcs.dll -Destination $Path\UserLibs -Force
|
||||
Move-Item -Path $Path\UniverseLib.IL2CPP.dll -Destination $Path\UserLibs -Force
|
||||
Move-Item -Path $Path/UniverseLib.IL2CPP.Unhollower.dll -Destination $Path/UserLibs -Force
|
||||
# (create zip archive)
|
||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.MelonLoader.IL2CPP.zip -Force
|
||||
Remove-Item $Path/../UnityExplorer.MelonLoader.IL2CPP.zip -ErrorAction SilentlyContinue
|
||||
7z a $Path/../UnityExplorer.MelonLoader.IL2CPP.zip .\$Path\*
|
||||
|
||||
# MelonLoader Mono
|
||||
dotnet build src\UnityExplorer.sln -c Release_ML_Mono
|
||||
# ----------- MelonLoader Mono -----------
|
||||
dotnet build src/UnityExplorer.sln -c Release_ML_Mono
|
||||
$Path = "Release/UnityExplorer.MelonLoader.Mono"
|
||||
# ILRepack
|
||||
lib/ILRepack.exe /target:library /lib:lib/net35 /lib:$Path /internalize /out:$Path/UnityExplorer.ML.Mono.dll $Path/UnityExplorer.ML.Mono.dll $Path/mcs.dll
|
||||
# (cleanup and move files)
|
||||
$Path = "Release\UnityExplorer.MelonLoader.Mono"
|
||||
Remove-Item $Path\Tomlet.dll
|
||||
Remove-Item $Path/Tomlet.dll
|
||||
Remove-Item $Path/mcs.dll
|
||||
New-Item -Path "$Path" -Name "Mods" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path\UnityExplorer.ML.Mono.dll -Destination $Path\Mods -Force
|
||||
Move-Item -Path $Path/UnityExplorer.ML.Mono.dll -Destination $Path/Mods -Force
|
||||
New-Item -Path "$Path" -Name "UserLibs" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path\mcs.dll -Destination $Path\UserLibs -Force
|
||||
Move-Item -Path $Path\UniverseLib.Mono.dll -Destination $Path\UserLibs -Force
|
||||
Move-Item -Path $Path/UniverseLib.Mono.dll -Destination $Path/UserLibs -Force
|
||||
# (create zip archive)
|
||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.MelonLoader.Mono.zip -Force
|
||||
Remove-Item $Path/../UnityExplorer.MelonLoader.Mono.zip -ErrorAction SilentlyContinue
|
||||
7z a $Path/../UnityExplorer.MelonLoader.Mono.zip .\$Path\*
|
||||
|
||||
# BepInEx IL2CPP
|
||||
dotnet build src\UnityExplorer.sln -c Release_BIE_Cpp
|
||||
# ----------- BepInEx IL2CPP -----------
|
||||
dotnet build src/UnityExplorer.sln -c Release_BIE_Cpp
|
||||
$Path = "Release/UnityExplorer.BepInEx.IL2CPP"
|
||||
# ILRepack
|
||||
lib/ILRepack.exe /target:library /lib:lib/net472 /lib:lib/unhollowed /lib:$Path /internalize /out:$Path/UnityExplorer.BIE.IL2CPP.dll $Path/UnityExplorer.BIE.IL2CPP.dll $Path/mcs.dll $Path/Tomlet.dll
|
||||
# (cleanup and move files)
|
||||
$Path = "Release\UnityExplorer.BepInEx.IL2CPP"
|
||||
Remove-Item $Path/Tomlet.dll
|
||||
Remove-Item $Path/mcs.dll
|
||||
Remove-Item $Path/Iced.dll
|
||||
Remove-Item $Path/UnhollowerBaseLib.dll
|
||||
New-Item -Path "$Path" -Name "plugins" -ItemType "directory" -Force
|
||||
New-Item -Path "$Path" -Name "plugins\sinai-dev-UnityExplorer" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path\UnityExplorer.BIE.IL2CPP.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path\mcs.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path\Tomlet.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path\UniverseLib.IL2CPP.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
New-Item -Path "$Path" -Name "plugins/sinai-dev-UnityExplorer" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path/UnityExplorer.BIE.IL2CPP.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path/UniverseLib.IL2CPP.Unhollower.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force
|
||||
# (create zip archive)
|
||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.BepInEx.IL2CPP.zip -Force
|
||||
Remove-Item $Path/../UnityExplorer.BepInEx.IL2CPP.zip -ErrorAction SilentlyContinue
|
||||
7z a $Path/../UnityExplorer.BepInEx.IL2CPP.zip .\$Path\*
|
||||
|
||||
# BepInEx 5 Mono
|
||||
dotnet build src\UnityExplorer.sln -c Release_BIE5_Mono
|
||||
# ----------- BepInEx IL2CPP CoreCLR -----------
|
||||
dotnet build src/UnityExplorer.sln -c Release_BIE_CoreCLR
|
||||
$Path = "Release/UnityExplorer.BepInEx.IL2CPP.CoreCLR"
|
||||
# ILRepack
|
||||
lib/ILRepack.exe /target:library /lib:lib/net472 /lib:lib/net6/ /lib:lib/interop/ /lib:$Path /internalize /out:$Path/UnityExplorer.BIE.IL2CPP.CoreCLR.dll $Path/UnityExplorer.BIE.IL2CPP.CoreCLR.dll $Path/mcs.dll $Path/Tomlet.dll
|
||||
# (cleanup and move files)
|
||||
$Path = "Release\UnityExplorer.BepInEx5.Mono"
|
||||
Remove-Item $Path/Tomlet.dll
|
||||
Remove-Item $Path/mcs.dll
|
||||
Remove-Item $Path/Iced.dll
|
||||
Remove-Item $Path/Il2CppInterop.Common.dll
|
||||
Remove-Item $Path/Il2CppInterop.Runtime.dll
|
||||
Remove-Item $Path/Microsoft.Extensions.Logging.Abstractions.dll
|
||||
Remove-Item $Path/UnityExplorer.BIE.IL2CPP.CoreCLR.deps.json
|
||||
New-Item -Path "$Path" -Name "plugins" -ItemType "directory" -Force
|
||||
New-Item -Path "$Path" -Name "plugins\sinai-dev-UnityExplorer" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path\UnityExplorer.BIE5.Mono.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path\mcs.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path\Tomlet.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path\UniverseLib.Mono.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
New-Item -Path "$Path" -Name "plugins/sinai-dev-UnityExplorer" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path/UnityExplorer.BIE.IL2CPP.CoreCLR.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path/UniverseLib.IL2CPP.Interop.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force
|
||||
# (create zip archive)
|
||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.BepInEx5.Mono.zip -Force
|
||||
Remove-Item $Path/../UnityExplorer.BepInEx.IL2CPP.CoreCLR.zip -ErrorAction SilentlyContinue
|
||||
7z a $Path/../UnityExplorer.BepInEx.IL2CPP.CoreCLR.zip .\$Path\*
|
||||
|
||||
# BepInEx 6 Mono
|
||||
dotnet build src\UnityExplorer.sln -c Release_BIE6_Mono
|
||||
# ----------- BepInEx 5 Mono -----------
|
||||
dotnet build src/UnityExplorer.sln -c Release_BIE5_Mono
|
||||
$Path = "Release/UnityExplorer.BepInEx5.Mono"
|
||||
# ILRepack
|
||||
lib/ILRepack.exe /target:library /lib:lib/net35 /lib:$Path /internalize /out:$Path/UnityExplorer.BIE5.Mono.dll $Path/UnityExplorer.BIE5.Mono.dll $Path/mcs.dll $Path/Tomlet.dll
|
||||
# (cleanup and move files)
|
||||
$Path = "Release\UnityExplorer.BepInEx6.Mono"
|
||||
Remove-Item $Path/Tomlet.dll
|
||||
Remove-Item $Path/mcs.dll
|
||||
New-Item -Path "$Path" -Name "plugins" -ItemType "directory" -Force
|
||||
New-Item -Path "$Path" -Name "plugins\sinai-dev-UnityExplorer" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path\UnityExplorer.BIE6.Mono.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path\mcs.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path\Tomlet.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path\UniverseLib.Mono.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
|
||||
New-Item -Path "$Path" -Name "plugins/sinai-dev-UnityExplorer" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path/UnityExplorer.BIE5.Mono.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path/UniverseLib.Mono.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force
|
||||
# (create zip archive)
|
||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.BepInEx6.Mono.zip -Force
|
||||
Remove-Item $Path/../UnityExplorer.BepInEx5.Mono.zip -ErrorAction SilentlyContinue
|
||||
7z a $Path/../UnityExplorer.BepInEx5.Mono.zip .\$Path\*
|
||||
|
||||
# Standalone Mono
|
||||
dotnet build src\UnityExplorer.sln -c Release_STANDALONE_Mono
|
||||
$Path = "Release\UnityExplorer.Standalone.Mono"
|
||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.Standalone.Mono.zip -Force
|
||||
# ----------- BepInEx 6 Mono -----------
|
||||
dotnet build src/UnityExplorer.sln -c Release_BIE6_Mono
|
||||
$Path = "Release/UnityExplorer.BepInEx6.Mono"
|
||||
# ILRepack
|
||||
lib/ILRepack.exe /target:library /lib:lib/net35 /lib:$Path /internalize /out:$Path/UnityExplorer.BIE6.Mono.dll $Path/UnityExplorer.BIE6.Mono.dll $Path/mcs.dll $Path/Tomlet.dll
|
||||
# (cleanup and move files)
|
||||
Remove-Item $Path/Tomlet.dll
|
||||
Remove-Item $Path/mcs.dll
|
||||
New-Item -Path "$Path" -Name "plugins" -ItemType "directory" -Force
|
||||
New-Item -Path "$Path" -Name "plugins/sinai-dev-UnityExplorer" -ItemType "directory" -Force
|
||||
Move-Item -Path $Path/UnityExplorer.BIE6.Mono.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force
|
||||
Move-Item -Path $Path/UniverseLib.Mono.dll -Destination $Path/plugins/sinai-dev-UnityExplorer -Force
|
||||
# (create zip archive)
|
||||
Remove-Item $Path/../UnityExplorer.BepInEx6.Mono.zip -ErrorAction SilentlyContinue
|
||||
7z a $Path/../UnityExplorer.BepInEx6.Mono.zip .\$Path\*
|
||||
|
||||
# Standalone IL2CPP
|
||||
dotnet build src\UnityExplorer.sln -c Release_STANDALONE_Cpp
|
||||
$Path = "Release\UnityExplorer.Standalone.IL2CPP"
|
||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.Standalone.IL2CPP.zip -Force
|
||||
# ----------- Standalone Mono -----------
|
||||
dotnet build src/UnityExplorer.sln -c Release_STANDALONE_Mono
|
||||
$Path = "Release/UnityExplorer.Standalone.Mono"
|
||||
# ILRepack
|
||||
lib/ILRepack.exe /target:library /lib:lib/net35 /lib:$Path /internalize /out:$Path/UnityExplorer.Standalone.Mono.dll $Path/UnityExplorer.Standalone.Mono.dll $Path/mcs.dll $Path/Tomlet.dll
|
||||
# (cleanup and move files)
|
||||
Remove-Item $Path/Tomlet.dll
|
||||
Remove-Item $Path/mcs.dll
|
||||
Remove-Item $Path/../UnityExplorer.Standalone.Mono.zip -ErrorAction SilentlyContinue
|
||||
7z a $Path/../UnityExplorer.Standalone.Mono.zip .\$Path\*
|
||||
|
||||
# Editor (mono)
|
||||
$Path1 = "Release\UnityExplorer.Standalone.Mono"
|
||||
$Path2 = "UnityEditorPackage\Runtime"
|
||||
Copy-Item $Path1\UnityExplorer.STANDALONE.Mono.dll -Destination $Path2
|
||||
Copy-Item $Path1\mcs.dll -Destination $Path2
|
||||
Copy-Item $Path1\Tomlet.dll -Destination $Path2
|
||||
Copy-Item $Path1\UniverseLib.Mono.dll -Destination $Path2
|
||||
Compress-Archive -Path UnityEditorPackage\* -CompressionLevel Fastest -DestinationPath Release\UnityExplorer.Editor.zip -Force
|
||||
# ----------- Standalone IL2CPP -----------
|
||||
dotnet build src/UnityExplorer.sln -c Release_STANDALONE_Cpp
|
||||
$Path = "Release/UnityExplorer.Standalone.IL2CPP"
|
||||
# ILRepack
|
||||
lib/ILRepack.exe /target:library /lib:lib/net472 /lib:lib/unhollowed /lib:$Path /internalize /out:$Path/UnityExplorer.Standalone.IL2CPP.dll $Path/UnityExplorer.Standalone.IL2CPP.dll $Path/mcs.dll $Path/Tomlet.dll
|
||||
# (cleanup and move files)
|
||||
Remove-Item $Path/Tomlet.dll
|
||||
Remove-Item $Path/mcs.dll
|
||||
Remove-Item $Path/Iced.dll
|
||||
Remove-Item $Path/UnhollowerBaseLib.dll
|
||||
Remove-Item $Path/../UnityExplorer.Standalone.IL2CPP.zip -ErrorAction SilentlyContinue
|
||||
7z a $Path/../UnityExplorer.Standalone.IL2CPP.zip .\$Path\*
|
||||
|
||||
# ----------- Editor (mono) -----------
|
||||
$Path1 = "Release/UnityExplorer.Standalone.Mono"
|
||||
$Path2 = "UnityEditorPackage/Runtime"
|
||||
Copy-Item $Path1/UnityExplorer.STANDALONE.Mono.dll -Destination $Path2
|
||||
Copy-Item $Path1/UniverseLib.Mono.dll -Destination $Path2
|
||||
Remove-Item Release/UnityExplorer.Editor.zip -ErrorAction SilentlyContinue
|
||||
7z a Release/UnityExplorer.Editor.zip .\UnityEditorPackage\*
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,13 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
using UnityExplorer.CSConsole.Lexers;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
|
||||
+147
-177
@@ -1,68 +1,61 @@
|
||||
using HarmonyLib;
|
||||
using Mono.CSharp;
|
||||
using System;
|
||||
using Mono.CSharp;
|
||||
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;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib;
|
||||
using UniverseLib.Input;
|
||||
using UniverseLib.Runtime;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
public static class ConsoleController
|
||||
{
|
||||
public static ScriptEvaluator Evaluator;
|
||||
public static LexerBuilder Lexer;
|
||||
public static CSAutoCompleter Completer;
|
||||
|
||||
private static HashSet<string> usingDirectives;
|
||||
private static StringBuilder evaluatorOutput;
|
||||
private static StringWriter evaluatorStringWriter;
|
||||
|
||||
public static CSConsolePanel Panel => UIManager.GetPanel<CSConsolePanel>(UIManager.Panels.CSConsole);
|
||||
public static InputFieldRef Input => Panel.Input;
|
||||
public static ScriptEvaluator Evaluator { get; private set; }
|
||||
public static LexerBuilder Lexer { get; private set; }
|
||||
public static CSAutoCompleter Completer { get; private set; }
|
||||
|
||||
public static bool SRENotSupported { get; private set; }
|
||||
public static int LastCaretPosition { get; private set; }
|
||||
internal static float defaultInputFieldAlpha;
|
||||
public static float DefaultInputFieldAlpha { get; set; }
|
||||
|
||||
// Todo save as config?
|
||||
public static bool EnableCtrlRShortcut { get; private set; } = true;
|
||||
public static bool EnableAutoIndent { get; private set; } = true;
|
||||
public static bool EnableSuggestions { get; private set; } = true;
|
||||
|
||||
internal static string ScriptsFolder => Path.Combine(ExplorerCore.ExplorerFolder, "Scripts");
|
||||
public static CSConsolePanel Panel => UIManager.GetPanel<CSConsolePanel>(UIManager.Panels.CSConsole);
|
||||
public static InputFieldRef Input => Panel.Input;
|
||||
|
||||
internal static readonly string[] DefaultUsing = new string[]
|
||||
public static string ScriptsFolder => Path.Combine(ExplorerCore.ExplorerFolder, "Scripts");
|
||||
|
||||
static HashSet<string> usingDirectives;
|
||||
static StringBuilder evaluatorOutput;
|
||||
static StringWriter evaluatorStringWriter;
|
||||
static float timeOfLastCtrlR;
|
||||
|
||||
static bool settingCaretCoroutine;
|
||||
static string previousInput;
|
||||
static int previousContentLength = 0;
|
||||
|
||||
static readonly string[] DefaultUsing = new string[]
|
||||
{
|
||||
"System",
|
||||
"System.Linq",
|
||||
"System.Text",
|
||||
"System.Collections",
|
||||
"System.Collections.Generic",
|
||||
"System.Reflection",
|
||||
"UnityEngine",
|
||||
"UniverseLib",
|
||||
#if CPP
|
||||
"UnhollowerBaseLib",
|
||||
"UnhollowerRuntimeLib",
|
||||
#endif
|
||||
};
|
||||
|
||||
const int CSCONSOLE_LINEHEIGHT = 18;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
InitEventSystemPropertyHandlers();
|
||||
|
||||
// Make sure console is supported on this platform
|
||||
try
|
||||
{
|
||||
ResetConsole(false);
|
||||
@@ -112,31 +105,10 @@ namespace UnityExplorer.CSConsole
|
||||
}
|
||||
}
|
||||
|
||||
#region UI Listeners and options
|
||||
|
||||
// TODO save
|
||||
|
||||
private static void OnToggleAutoIndent(bool value)
|
||||
{
|
||||
EnableAutoIndent = value;
|
||||
}
|
||||
|
||||
private static void OnToggleCtrlRShortcut(bool value)
|
||||
{
|
||||
EnableCtrlRShortcut = value;
|
||||
}
|
||||
|
||||
private static void OnToggleSuggestions(bool value)
|
||||
{
|
||||
EnableSuggestions = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Evaluating
|
||||
|
||||
private static void GenerateTextWriter()
|
||||
static void GenerateTextWriter()
|
||||
{
|
||||
evaluatorOutput = new StringBuilder();
|
||||
evaluatorStringWriter = new StringWriter(evaluatorOutput);
|
||||
@@ -248,16 +220,48 @@ namespace UnityExplorer.CSConsole
|
||||
#endregion
|
||||
|
||||
|
||||
// Updating and event listeners
|
||||
#region Update loop and event listeners
|
||||
|
||||
private static bool settingCaretCoroutine;
|
||||
public static void Update()
|
||||
{
|
||||
if (SRENotSupported)
|
||||
return;
|
||||
|
||||
private static void OnInputScrolled() => HighlightVisibleInput();
|
||||
if (!InputManager.GetKey(KeyCode.LeftControl) && !InputManager.GetKey(KeyCode.RightControl))
|
||||
{
|
||||
if (InputManager.GetKeyDown(KeyCode.Home))
|
||||
JumpToStartOrEndOfLine(true);
|
||||
else if (InputManager.GetKeyDown(KeyCode.End))
|
||||
JumpToStartOrEndOfLine(false);
|
||||
}
|
||||
|
||||
private static string previousInput;
|
||||
UpdateCaret(out bool caretMoved);
|
||||
|
||||
// Invoked at most once per frame
|
||||
private static void OnInputChanged(string value)
|
||||
if (!settingCaretCoroutine && EnableSuggestions)
|
||||
{
|
||||
if (AutoCompleteModal.CheckEscape(Completer))
|
||||
{
|
||||
OnAutocompleteEscaped();
|
||||
return;
|
||||
}
|
||||
|
||||
if (caretMoved)
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(Completer);
|
||||
}
|
||||
|
||||
if (EnableCtrlRShortcut
|
||||
&& (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
|
||||
&& InputManager.GetKeyDown(KeyCode.R)
|
||||
&& timeOfLastCtrlR.OccuredEarlierThanDefault())
|
||||
{
|
||||
timeOfLastCtrlR = Time.realtimeSinceStartup;
|
||||
Evaluate(Panel.Input.Text);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnInputScrolled() => HighlightVisibleInput(out _);
|
||||
|
||||
static void OnInputChanged(string value)
|
||||
{
|
||||
if (SRENotSupported)
|
||||
return;
|
||||
@@ -284,7 +288,7 @@ namespace UnityExplorer.CSConsole
|
||||
DoAutoIndent();
|
||||
}
|
||||
|
||||
bool inStringOrComment = HighlightVisibleInput();
|
||||
HighlightVisibleInput(out bool inStringOrComment);
|
||||
|
||||
if (!settingCaretCoroutine)
|
||||
{
|
||||
@@ -300,40 +304,27 @@ namespace UnityExplorer.CSConsole
|
||||
UpdateCaret(out _);
|
||||
}
|
||||
|
||||
private static float timeOfLastCtrlR;
|
||||
|
||||
public static void Update()
|
||||
static void OnToggleAutoIndent(bool value)
|
||||
{
|
||||
if (SRENotSupported)
|
||||
return;
|
||||
|
||||
UpdateCaret(out bool caretMoved);
|
||||
|
||||
if (!settingCaretCoroutine && EnableSuggestions)
|
||||
{
|
||||
if (AutoCompleteModal.CheckEscape(Completer))
|
||||
{
|
||||
OnAutocompleteEscaped();
|
||||
return;
|
||||
}
|
||||
|
||||
if (caretMoved)
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(Completer);
|
||||
}
|
||||
|
||||
if (EnableCtrlRShortcut
|
||||
&& (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
|
||||
&& InputManager.GetKeyDown(KeyCode.R)
|
||||
&& timeOfLastCtrlR.OccuredEarlierThanDefault())
|
||||
{
|
||||
timeOfLastCtrlR = Time.realtimeSinceStartup;
|
||||
Evaluate(Panel.Input.Text);
|
||||
}
|
||||
EnableAutoIndent = value;
|
||||
}
|
||||
|
||||
private const int CSCONSOLE_LINEHEIGHT = 18;
|
||||
static void OnToggleCtrlRShortcut(bool value)
|
||||
{
|
||||
EnableCtrlRShortcut = value;
|
||||
}
|
||||
|
||||
private static void UpdateCaret(out bool caretMoved)
|
||||
static void OnToggleSuggestions(bool value)
|
||||
{
|
||||
EnableSuggestions = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Caret position
|
||||
|
||||
static void UpdateCaret(out bool caretMoved)
|
||||
{
|
||||
int prevCaret = LastCaretPosition;
|
||||
caretMoved = false;
|
||||
@@ -378,112 +369,95 @@ namespace UnityExplorer.CSConsole
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetCaretPosition(int caretPosition)
|
||||
public static void SetCaretPosition(int caretPosition)
|
||||
{
|
||||
Input.Component.caretPosition = caretPosition;
|
||||
|
||||
// Fix to make sure we always really set the caret position.
|
||||
// Yields a frame and fixes text-selection issues.
|
||||
settingCaretCoroutine = true;
|
||||
Input.Component.readOnly = true;
|
||||
RuntimeHelper.StartCoroutine(SetCaretCoroutine(caretPosition));
|
||||
RuntimeHelper.StartCoroutine(DoSetCaretCoroutine(caretPosition));
|
||||
}
|
||||
|
||||
static void InitEventSystemPropertyHandlers()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (MemberInfo member in typeof(EventSystem).GetMembers(AccessTools.all))
|
||||
{
|
||||
if (member.Name == "m_CurrentSelected")
|
||||
{
|
||||
Type backingType;
|
||||
if (member.MemberType == MemberTypes.Property)
|
||||
backingType = (member as PropertyInfo).PropertyType;
|
||||
else
|
||||
backingType = (member as FieldInfo).FieldType;
|
||||
|
||||
usingEventSystemDictionaryMembers = ReflectionUtility.IsDictionary(backingType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception checking EventSystem property backing type: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
static bool usingEventSystemDictionaryMembers;
|
||||
|
||||
static readonly AmbiguousMemberHandler<EventSystem, GameObject> m_CurrentSelected_Handler_Normal
|
||||
= new(true, true, "m_CurrentSelected", "m_currentSelected");
|
||||
static readonly AmbiguousMemberHandler<EventSystem, Dictionary<int, GameObject>> m_CurrentSelected_Handler_Dictionary
|
||||
= new(true, true, "m_CurrentSelected", "m_currentSelected");
|
||||
|
||||
static readonly AmbiguousMemberHandler<EventSystem, bool> m_SelectionGuard_Handler_Normal
|
||||
= new(true, true, "m_SelectionGuard", "m_selectionGuard");
|
||||
static readonly AmbiguousMemberHandler<EventSystem, Dictionary<int, bool>> m_SelectionGuard_Handler_Dictionary
|
||||
= new(true, true, "m_SelectionGuard", "m_selectionGuard");
|
||||
|
||||
static void SetCurrentSelectedGameObject(EventSystem instance, GameObject value)
|
||||
{
|
||||
instance.SetSelectedGameObject(value);
|
||||
|
||||
if (usingEventSystemDictionaryMembers)
|
||||
m_CurrentSelected_Handler_Dictionary.GetValue(instance)[0] = value;
|
||||
else
|
||||
m_CurrentSelected_Handler_Normal.SetValue(instance, value);
|
||||
}
|
||||
|
||||
static void SetSelectionGuard(EventSystem instance, bool value)
|
||||
{
|
||||
if (usingEventSystemDictionaryMembers)
|
||||
m_SelectionGuard_Handler_Dictionary.GetValue(instance)[0] = value;
|
||||
else
|
||||
m_SelectionGuard_Handler_Normal.SetValue(instance, value);
|
||||
}
|
||||
|
||||
private static IEnumerator SetCaretCoroutine(int caretPosition)
|
||||
static IEnumerator DoSetCaretCoroutine(int caretPosition)
|
||||
{
|
||||
Color color = Input.Component.selectionColor;
|
||||
color.a = 0f;
|
||||
Input.Component.selectionColor = color;
|
||||
|
||||
try { SetCurrentSelectedGameObject(CursorUnlocker.CurrentEventSystem, null); }
|
||||
catch (Exception ex) { ExplorerCore.Log($"Failed removing selected object: {ex}"); }
|
||||
|
||||
yield return null; // ~~~~~~~ YIELD FRAME ~~~~~~~~~
|
||||
|
||||
try { SetSelectionGuard(CursorUnlocker.CurrentEventSystem, false); }
|
||||
catch (Exception ex) { ExplorerCore.Log($"Failed setting selection guard: {ex}"); }
|
||||
|
||||
try { SetCurrentSelectedGameObject(CursorUnlocker.CurrentEventSystem, Input.GameObject); }
|
||||
catch (Exception ex) { ExplorerCore.Log($"Failed setting selected gameobject: {ex}"); }
|
||||
|
||||
yield return null; // ~~~~~~~ YIELD FRAME ~~~~~~~~~
|
||||
|
||||
EventSystemHelper.SetSelectionGuard(false);
|
||||
Input.Component.Select();
|
||||
|
||||
yield return null; // ~~~~~~~ YIELD FRAME ~~~~~~~~~
|
||||
|
||||
Input.Component.caretPosition = caretPosition;
|
||||
Input.Component.selectionFocusPosition = caretPosition;
|
||||
LastCaretPosition = Input.Component.caretPosition;
|
||||
|
||||
color.a = defaultInputFieldAlpha;
|
||||
color.a = DefaultInputFieldAlpha;
|
||||
Input.Component.selectionColor = color;
|
||||
|
||||
Input.Component.readOnly = false;
|
||||
settingCaretCoroutine = false;
|
||||
}
|
||||
|
||||
// For Home and End keys
|
||||
static void JumpToStartOrEndOfLine(bool toStart)
|
||||
{
|
||||
// Determine the current and next line
|
||||
UILineInfo thisline = default;
|
||||
UILineInfo? nextLine = null;
|
||||
for (int i = 0; i < Input.Component.cachedInputTextGenerator.lineCount; i++)
|
||||
{
|
||||
UILineInfo line = Input.Component.cachedInputTextGenerator.lines[i];
|
||||
|
||||
if (line.startCharIdx > LastCaretPosition)
|
||||
{
|
||||
nextLine = line;
|
||||
break;
|
||||
}
|
||||
thisline = line;
|
||||
}
|
||||
|
||||
if (toStart)
|
||||
{
|
||||
// Determine where the indented text begins
|
||||
int endOfLine = nextLine == null ? Input.Text.Length : nextLine.Value.startCharIdx;
|
||||
int indentedStart = thisline.startCharIdx;
|
||||
while (indentedStart < endOfLine - 1 && char.IsWhiteSpace(Input.Text[indentedStart]))
|
||||
indentedStart++;
|
||||
|
||||
// Jump to either the true start or the non-whitespace position,
|
||||
// depending on which one we are not at.
|
||||
if (LastCaretPosition == indentedStart)
|
||||
SetCaretPosition(thisline.startCharIdx);
|
||||
else
|
||||
SetCaretPosition(indentedStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there is no next line, jump to the end of this line (+1, to the invisible next character position)
|
||||
if (nextLine == null)
|
||||
SetCaretPosition(Input.Text.Length);
|
||||
else // jump to the next line start index - 1, ie. end of this line
|
||||
SetCaretPosition(nextLine.Value.startCharIdx - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Lexer Highlighting
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if caret is inside string or comment, false otherwise
|
||||
/// </summary>
|
||||
private static bool HighlightVisibleInput()
|
||||
private static void HighlightVisibleInput(out bool inStringOrComment)
|
||||
{
|
||||
inStringOrComment = false;
|
||||
if (string.IsNullOrEmpty(Input.Text))
|
||||
{
|
||||
Panel.HighlightText.text = "";
|
||||
Panel.LineNumberText.text = "1";
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the visible lines
|
||||
@@ -518,7 +492,7 @@ namespace UnityExplorer.CSConsole
|
||||
|
||||
// Highlight the visible text with the LexerBuilder
|
||||
|
||||
Panel.HighlightText.text = Lexer.BuildHighlightedString(Input.Text, startIdx, endIdx, topLine, LastCaretPosition, out bool ret);
|
||||
Panel.HighlightText.text = Lexer.BuildHighlightedString(Input.Text, startIdx, endIdx, topLine, LastCaretPosition, out inStringOrComment);
|
||||
|
||||
// Set the line numbers
|
||||
|
||||
@@ -556,7 +530,7 @@ namespace UnityExplorer.CSConsole
|
||||
|
||||
Panel.LineNumberText.text = sb.ToString();
|
||||
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -596,13 +570,11 @@ namespace UnityExplorer.CSConsole
|
||||
|
||||
#region Auto indenting
|
||||
|
||||
private static int prevContentLen = 0;
|
||||
|
||||
private static void DoAutoIndent()
|
||||
{
|
||||
if (Input.Text.Length > prevContentLen)
|
||||
if (Input.Text.Length > previousContentLength)
|
||||
{
|
||||
int inc = Input.Text.Length - prevContentLen;
|
||||
int inc = Input.Text.Length - previousContentLength;
|
||||
|
||||
if (inc == 1)
|
||||
{
|
||||
@@ -621,7 +593,7 @@ namespace UnityExplorer.CSConsole
|
||||
}
|
||||
}
|
||||
|
||||
prevContentLen = Input.Text.Length;
|
||||
previousContentLength = Input.Text.Length;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -629,8 +601,6 @@ namespace UnityExplorer.CSConsole
|
||||
|
||||
#region "Help" interaction
|
||||
|
||||
private static bool SRENotSupported;
|
||||
|
||||
private static void DisableConsole(Exception ex)
|
||||
{
|
||||
SRENotSupported = true;
|
||||
@@ -704,7 +674,7 @@ Doorstop example:
|
||||
// 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.
|
||||
|
||||
// To execute a script automatically on startup, put the script at 'UnityExplorer\Scripts\startup.cs'</color>";
|
||||
// To execute a script automatically on startup, put the script at 'sinai-dev-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.
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
using UnityExplorer.CSConsole.Lexers;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
@@ -17,8 +14,6 @@ namespace UnityExplorer.CSConsole
|
||||
|
||||
public class LexerBuilder
|
||||
{
|
||||
#region Core and initialization
|
||||
|
||||
public const char WHITESPACE = ' ';
|
||||
public readonly HashSet<char> IndentOpenChars = new() { '{', '(' };
|
||||
public readonly HashSet<char> IndentCloseChars = new() { '}', ')' };
|
||||
@@ -50,8 +45,6 @@ namespace UnityExplorer.CSConsole
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>The last committed index for a match or no-match. Starts at -1 for a new parse.</summary>
|
||||
public int CommittedIndex { get; private set; }
|
||||
/// <summary>The index of the character we are currently parsing, at minimum it will be CommittedIndex + 1.</summary>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public class CommentLexer : Lexer
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using System.Text;
|
||||
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public abstract class Lexer
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public class NumberLexer : Lexer
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public class StringLexer : Lexer
|
||||
{
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
namespace UnityExplorer.CSConsole.Lexers
|
||||
{
|
||||
public class SymbolLexer : Lexer
|
||||
{
|
||||
@@ -32,13 +28,7 @@ namespace UnityExplorer.CSConsole.Lexers
|
||||
|
||||
if (IsSymbol(lexer.Current))
|
||||
{
|
||||
do
|
||||
{
|
||||
lexer.Commit();
|
||||
lexer.PeekNext();
|
||||
}
|
||||
while (IsSymbol(lexer.Current));
|
||||
|
||||
lexer.Commit();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using Mono.CSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using UnityExplorer.Config;
|
||||
|
||||
// Thanks to ManlyMarco for this
|
||||
|
||||
@@ -10,6 +7,9 @@ namespace UnityExplorer.CSConsole
|
||||
{
|
||||
public class ScriptEvaluator : Evaluator, IDisposable
|
||||
{
|
||||
internal TextWriter _textWriter;
|
||||
internal static StreamReportPrinter _reportPrinter;
|
||||
|
||||
private static readonly HashSet<string> StdLib = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
"mscorlib",
|
||||
@@ -18,9 +18,6 @@ namespace UnityExplorer.CSConsole
|
||||
"System.Xml"
|
||||
};
|
||||
|
||||
internal TextWriter _textWriter;
|
||||
internal static StreamReportPrinter _reportPrinter;
|
||||
|
||||
public ScriptEvaluator(TextWriter tw) : base(BuildContext(tw))
|
||||
{
|
||||
_textWriter = tw;
|
||||
@@ -48,8 +45,19 @@ namespace UnityExplorer.CSConsole
|
||||
private void Reference(Assembly asm)
|
||||
{
|
||||
string name = asm.GetName().Name;
|
||||
if (name == "completions")
|
||||
|
||||
if (name == "completions") // ignore assemblies generated by mcs' autocomplete.
|
||||
return;
|
||||
|
||||
foreach (string blacklisted in ConfigManager.CSConsole_Assembly_Blacklist.Value.Split(';'))
|
||||
{
|
||||
string bl = blacklisted;
|
||||
if (bl.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
||||
bl = blacklisted.Substring(0, bl.Length - 4);
|
||||
if (string.Equals(bl, name, StringComparison.OrdinalIgnoreCase))
|
||||
return;
|
||||
}
|
||||
|
||||
ReferenceAssembly(asm);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using HarmonyLib;
|
||||
using Mono.CSharp;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib;
|
||||
|
||||
namespace UnityExplorer.CSConsole
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UniverseLib.Utility;
|
||||
using UnityExplorer.Inspectors;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.Inspectors;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UniverseLib;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI.ObjectPool;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
@@ -29,8 +24,8 @@ namespace UnityExplorer.CacheObject
|
||||
this.Owner = inspector;
|
||||
this.NameLabelText = this switch
|
||||
{
|
||||
CacheMethod => SignatureHighlighter.HighlightMethod(member as MethodInfo),
|
||||
CacheConstructor => SignatureHighlighter.HighlightConstructor(member as ConstructorInfo),
|
||||
CacheMethod => SignatureHighlighter.ParseMethod(member as MethodInfo),
|
||||
CacheConstructor => SignatureHighlighter.ParseConstructor(member as ConstructorInfo),
|
||||
_ => SignatureHighlighter.Parse(member.DeclaringType, false, member),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.Runtime;
|
||||
using UniverseLib;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UniverseLib.Utility;
|
||||
using UnityExplorer.Inspectors;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.ObjectPool;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
@@ -28,28 +24,31 @@ namespace UnityExplorer.CacheObject
|
||||
public abstract class CacheObjectBase
|
||||
{
|
||||
public ICacheObjectController Owner { get; set; }
|
||||
|
||||
public CacheObjectCell CellView { get; internal set; }
|
||||
|
||||
public object Value { get; protected set; }
|
||||
public Type FallbackType { get; protected set; }
|
||||
public bool LastValueWasNull { get; private set; }
|
||||
|
||||
public ValueState State = ValueState.NotEvaluated;
|
||||
public Type LastValueType;
|
||||
public ValueState State { get; set; }
|
||||
public Exception LastException { get; protected set; }
|
||||
bool valueIsNull;
|
||||
Type currentValueType;
|
||||
|
||||
// InteractiveValues
|
||||
public InteractiveValue IValue { get; private set; }
|
||||
public Type CurrentIValueType { get; private set; }
|
||||
public bool SubContentShowWanted { get; private set; }
|
||||
|
||||
// UI
|
||||
public string NameLabelText { get; protected set; }
|
||||
public string NameLabelTextRaw { get; protected set; }
|
||||
public string ValueLabelText { get; protected set; }
|
||||
|
||||
// Abstract
|
||||
public abstract bool ShouldAutoEvaluate { get; }
|
||||
public abstract bool HasArguments { get; }
|
||||
public abstract bool CanWrite { get; }
|
||||
public Exception LastException { get; protected set; }
|
||||
|
||||
protected const string NOT_YET_EVAL = "<color=grey>Not yet evaluated</color>";
|
||||
|
||||
public virtual void SetFallbackType(Type fallbackType)
|
||||
{
|
||||
@@ -57,17 +56,6 @@ namespace UnityExplorer.CacheObject
|
||||
this.ValueLabelText = GetValueLabel();
|
||||
}
|
||||
|
||||
protected const string NOT_YET_EVAL = "<color=grey>Not yet evaluated</color>";
|
||||
|
||||
public virtual void ReleasePooledObjects()
|
||||
{
|
||||
if (this.IValue != null)
|
||||
ReleaseIValue();
|
||||
|
||||
if (this.CellView != null)
|
||||
UnlinkFromView();
|
||||
}
|
||||
|
||||
public virtual void SetView(CacheObjectCell cellView)
|
||||
{
|
||||
this.CellView = cellView;
|
||||
@@ -86,6 +74,15 @@ namespace UnityExplorer.CacheObject
|
||||
this.IValue.UIRoot.transform.SetParent(InactiveIValueHolder.transform, false);
|
||||
}
|
||||
|
||||
public virtual void ReleasePooledObjects()
|
||||
{
|
||||
if (this.IValue != null)
|
||||
ReleaseIValue();
|
||||
|
||||
if (this.CellView != null)
|
||||
UnlinkFromView();
|
||||
}
|
||||
|
||||
// Updating and applying values
|
||||
|
||||
// The only method which sets the CacheObjectBase.Value
|
||||
@@ -130,18 +127,18 @@ namespace UnityExplorer.CacheObject
|
||||
|
||||
if (LastException != null)
|
||||
{
|
||||
LastValueWasNull = true;
|
||||
LastValueType = FallbackType;
|
||||
valueIsNull = true;
|
||||
currentValueType = FallbackType;
|
||||
State = ValueState.Exception;
|
||||
}
|
||||
else if (Value.IsNullOrDestroyed())
|
||||
{
|
||||
LastValueWasNull = true;
|
||||
valueIsNull = true;
|
||||
State = GetStateForType(FallbackType);
|
||||
}
|
||||
else
|
||||
{
|
||||
LastValueWasNull = false;
|
||||
valueIsNull = false;
|
||||
State = GetStateForType(Value.GetActualType());
|
||||
}
|
||||
|
||||
@@ -163,10 +160,10 @@ namespace UnityExplorer.CacheObject
|
||||
|
||||
public ValueState GetStateForType(Type type)
|
||||
{
|
||||
if (LastValueType == type && (State != ValueState.Exception || LastException != null))
|
||||
if (currentValueType == type && (State != ValueState.Exception || LastException != null))
|
||||
return State;
|
||||
|
||||
LastValueType = type;
|
||||
currentValueType = type;
|
||||
if (type == typeof(bool))
|
||||
return ValueState.Boolean;
|
||||
else if (type.IsPrimitive || type == typeof(decimal))
|
||||
@@ -189,7 +186,7 @@ namespace UnityExplorer.CacheObject
|
||||
|
||||
protected string GetValueLabel()
|
||||
{
|
||||
string label = "";
|
||||
string label = string.Empty;
|
||||
|
||||
switch (State)
|
||||
{
|
||||
@@ -206,19 +203,19 @@ namespace UnityExplorer.CacheObject
|
||||
|
||||
// and valuestruct also doesnt want it if we can parse it
|
||||
case ValueState.ValueStruct:
|
||||
if (ParseUtility.CanParse(LastValueType))
|
||||
if (ParseUtility.CanParse(currentValueType))
|
||||
return null;
|
||||
break;
|
||||
|
||||
// string wants it trimmed to max 200 chars
|
||||
case ValueState.String:
|
||||
if (!LastValueWasNull)
|
||||
if (!valueIsNull)
|
||||
return $"\"{ToStringUtility.PruneString(Value as string, 200, 5)}\"";
|
||||
break;
|
||||
|
||||
// try to prefix the count of the collection for lists and dicts
|
||||
case ValueState.Collection:
|
||||
if (!LastValueWasNull)
|
||||
if (!valueIsNull)
|
||||
{
|
||||
if (Value is IList iList)
|
||||
label = $"[{iList.Count}] ";
|
||||
@@ -230,7 +227,7 @@ namespace UnityExplorer.CacheObject
|
||||
break;
|
||||
|
||||
case ValueState.Dictionary:
|
||||
if (!LastValueWasNull)
|
||||
if (!valueIsNull)
|
||||
{
|
||||
if (Value is IDictionary iDict)
|
||||
label = $"[{iDict.Count}] ";
|
||||
@@ -291,7 +288,7 @@ namespace UnityExplorer.CacheObject
|
||||
SetValueState(cell, new(false, typeLabelActive: true, inputActive: true, applyActive: CanWrite));
|
||||
break;
|
||||
case ValueState.String:
|
||||
if (LastValueWasNull)
|
||||
if (valueIsNull)
|
||||
SetValueState(cell, new(true, subContentButtonActive: true));
|
||||
else
|
||||
SetValueState(cell, new(true, false, SignatureHighlighter.StringOrange, subContentButtonActive: true));
|
||||
@@ -301,17 +298,17 @@ namespace UnityExplorer.CacheObject
|
||||
break;
|
||||
case ValueState.Color:
|
||||
case ValueState.ValueStruct:
|
||||
if (ParseUtility.CanParse(LastValueType))
|
||||
if (ParseUtility.CanParse(currentValueType))
|
||||
SetValueState(cell, new(false, false, null, true, false, true, CanWrite, true, true));
|
||||
else
|
||||
SetValueState(cell, new(true, inspectActive: true, subContentButtonActive: true));
|
||||
break;
|
||||
case ValueState.Collection:
|
||||
case ValueState.Dictionary:
|
||||
SetValueState(cell, new(true, inspectActive: !LastValueWasNull, subContentButtonActive: !LastValueWasNull));
|
||||
SetValueState(cell, new(true, inspectActive: !valueIsNull, subContentButtonActive: !valueIsNull));
|
||||
break;
|
||||
case ValueState.Unsupported:
|
||||
SetValueState(cell, new(true, inspectActive: !LastValueWasNull));
|
||||
SetValueState(cell, new(true, inspectActive: !valueIsNull));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -333,7 +330,7 @@ namespace UnityExplorer.CacheObject
|
||||
// Type label (for primitives)
|
||||
cell.TypeLabel.gameObject.SetActive(args.typeLabelActive);
|
||||
if (args.typeLabelActive)
|
||||
cell.TypeLabel.text = SignatureHighlighter.Parse(LastValueType, false);
|
||||
cell.TypeLabel.text = SignatureHighlighter.Parse(currentValueType, false);
|
||||
|
||||
// toggle for bools
|
||||
cell.Toggle.gameObject.SetActive(args.toggleActive);
|
||||
@@ -348,7 +345,7 @@ namespace UnityExplorer.CacheObject
|
||||
cell.InputField.UIRoot.SetActive(args.inputActive);
|
||||
if (args.inputActive)
|
||||
{
|
||||
cell.InputField.Text = ParseUtility.ToStringForInput(Value, LastValueType);
|
||||
cell.InputField.Text = ParseUtility.ToStringForInput(Value, currentValueType);
|
||||
cell.InputField.Component.readOnly = !CanWrite;
|
||||
}
|
||||
|
||||
@@ -357,12 +354,12 @@ namespace UnityExplorer.CacheObject
|
||||
|
||||
// Inspect button only if last value not null.
|
||||
if (cell.InspectButton != null)
|
||||
cell.InspectButton.Component.gameObject.SetActive(args.inspectActive && !LastValueWasNull);
|
||||
cell.InspectButton.Component.gameObject.SetActive(args.inspectActive && !valueIsNull);
|
||||
|
||||
// set subcontent button if needed, and for null strings and exceptions
|
||||
cell.SubContentButton.Component.gameObject.SetActive(
|
||||
args.subContentButtonActive
|
||||
&& (!LastValueWasNull || State == ValueState.String || State == ValueState.Exception));
|
||||
&& (!valueIsNull || State == ValueState.String || State == ValueState.Exception));
|
||||
}
|
||||
|
||||
// CacheObjectCell Apply
|
||||
@@ -373,7 +370,7 @@ namespace UnityExplorer.CacheObject
|
||||
SetUserValue(this.CellView.Toggle.isOn);
|
||||
else
|
||||
{
|
||||
if (ParseUtility.TryParse(CellView.InputField.Text, LastValueType, out object value, out Exception ex))
|
||||
if (ParseUtility.TryParse(CellView.InputField.Text, currentValueType, out object value, out Exception ex))
|
||||
{
|
||||
SetUserValue(value);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.Inspectors;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib;
|
||||
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections.Specialized;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Config;
|
||||
using UnityExplorer.Config;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UniverseLib.UI.ObjectPool;
|
||||
using UniverseLib.UI.ObjectPool;
|
||||
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
{
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.Utility;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace UnityExplorer.Config
|
||||
namespace UnityExplorer.Config
|
||||
{
|
||||
public class ConfigElement<T> : IConfigElement
|
||||
{
|
||||
|
||||
+54
-44
@@ -1,7 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
namespace UnityExplorer.Config
|
||||
{
|
||||
@@ -16,19 +13,20 @@ namespace UnityExplorer.Config
|
||||
|
||||
// Actual UE Settings
|
||||
public static ConfigElement<KeyCode> Master_Toggle;
|
||||
public static ConfigElement<int> Target_Display;
|
||||
public static ConfigElement<UIManager.VerticalAnchor> Main_Navbar_Anchor;
|
||||
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;
|
||||
public static ConfigElement<float> Startup_Delay_Time;
|
||||
public static ConfigElement<string> Reflection_Signature_Blacklist;
|
||||
public static ConfigElement<bool> Disable_EventSystem_Override;
|
||||
public static ConfigElement<int> Target_Display;
|
||||
public static ConfigElement<bool> Force_Unlock_Mouse;
|
||||
public static ConfigElement<KeyCode> Force_Unlock_Toggle;
|
||||
public static ConfigElement<string> Default_Output_Path;
|
||||
public static ConfigElement<string> DnSpy_Path;
|
||||
public static ConfigElement<bool> Log_Unity_Debug;
|
||||
public static ConfigElement<UIManager.VerticalAnchor> Main_Navbar_Anchor;
|
||||
public static ConfigElement<KeyCode> World_MouseInspect_Keybind;
|
||||
public static ConfigElement<KeyCode> UI_MouseInspect_Keybind;
|
||||
public static ConfigElement<string> CSConsole_Assembly_Blacklist;
|
||||
public static ConfigElement<string> Reflection_Signature_Blacklist;
|
||||
|
||||
// internal configs
|
||||
internal static InternalConfigHandler InternalHandler { get; private set; }
|
||||
@@ -54,7 +52,9 @@ namespace UnityExplorer.Config
|
||||
Handler.LoadConfig();
|
||||
InternalHandler.LoadConfig();
|
||||
|
||||
//InitConsoleCallback();
|
||||
#if STANDALONE
|
||||
Loader.Standalone.ExplorerEditorBehaviour.Instance?.LoadConfigs();
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void RegisterConfigElement<T>(ConfigElement<T> configElement)
|
||||
@@ -73,23 +73,53 @@ namespace UnityExplorer.Config
|
||||
|
||||
private static void CreateConfigElements()
|
||||
{
|
||||
Master_Toggle = new ConfigElement<KeyCode>("UnityExplorer Toggle",
|
||||
Master_Toggle = new("UnityExplorer Toggle",
|
||||
"The key to enable or disable UnityExplorer's menu and features.",
|
||||
KeyCode.F7);
|
||||
|
||||
Hide_On_Startup = new ConfigElement<bool>("Hide On Startup",
|
||||
Hide_On_Startup = new("Hide On Startup",
|
||||
"Should UnityExplorer be hidden on startup?",
|
||||
false);
|
||||
|
||||
Target_Display = new ConfigElement<int>("Target Display",
|
||||
Startup_Delay_Time = new("Startup Delay Time",
|
||||
"The delay on startup before the UI is created.",
|
||||
1f);
|
||||
|
||||
Target_Display = new("Target Display",
|
||||
"The monitor index for UnityExplorer to use, if you have multiple. 0 is the default display, 1 is secondary, etc. " +
|
||||
"Restart recommended when changing this setting. Make sure your extra monitors are the same resolution as your primary monitor.",
|
||||
0);
|
||||
|
||||
Main_Navbar_Anchor = new ConfigElement<UIManager.VerticalAnchor>("Main Navbar Anchor",
|
||||
Force_Unlock_Mouse = new("Force Unlock Mouse",
|
||||
"Force the Cursor to be unlocked (visible) when the UnityExplorer menu is open.",
|
||||
true);
|
||||
Force_Unlock_Mouse.OnValueChanged += (bool value) => UniverseLib.Config.ConfigManager.Force_Unlock_Mouse = value;
|
||||
|
||||
Force_Unlock_Toggle = new("Force Unlock Toggle Key",
|
||||
"The keybind to toggle the 'Force Unlock Mouse' setting. Only usable when UnityExplorer is open.",
|
||||
KeyCode.None);
|
||||
|
||||
Disable_EventSystem_Override = new("Disable EventSystem override",
|
||||
"If enabled, UnityExplorer will not override the EventSystem from the game.\n<b>May require restart to take effect.</b>",
|
||||
false);
|
||||
Disable_EventSystem_Override.OnValueChanged += (bool value) => UniverseLib.Config.ConfigManager.Disable_EventSystem_Override = value;
|
||||
|
||||
Default_Output_Path = new("Default Output Path",
|
||||
"The default output path when exporting things from UnityExplorer.",
|
||||
Path.Combine(ExplorerCore.ExplorerFolder, "Output"));
|
||||
|
||||
DnSpy_Path = new("dnSpy Path",
|
||||
"The full path to dnSpy.exe (64-bit).",
|
||||
@"C:/Program Files/dnspy/dnSpy.exe");
|
||||
|
||||
Main_Navbar_Anchor = new("Main Navbar Anchor",
|
||||
"The vertical anchor of the main UnityExplorer Navbar, in case you want to move it.",
|
||||
UIManager.VerticalAnchor.Top);
|
||||
|
||||
Log_Unity_Debug = new("Log Unity Debug",
|
||||
"Should UnityEngine.Debug.Log messages be printed to UnityExplorer's log?",
|
||||
false);
|
||||
|
||||
World_MouseInspect_Keybind = new("World Mouse-Inspect Keybind",
|
||||
"Optional keybind to being a World-mode Mouse Inspect.",
|
||||
KeyCode.None);
|
||||
@@ -98,33 +128,13 @@ namespace UnityExplorer.Config
|
||||
"Optional keybind to begin a UI-mode Mouse Inspect.",
|
||||
KeyCode.None);
|
||||
|
||||
Force_Unlock_Mouse = new ConfigElement<bool>("Force Unlock Mouse",
|
||||
"Force the Cursor to be unlocked (visible) when the UnityExplorer menu is open.",
|
||||
true);
|
||||
Force_Unlock_Mouse.OnValueChanged += (bool value) => UniverseLib.Config.ConfigManager.Force_Unlock_Mouse = value;
|
||||
CSConsole_Assembly_Blacklist = new("CSharp Console Assembly Blacklist",
|
||||
"Use this to blacklist Assembly names from being referenced by the C# Console. Requires a Reset of the C# Console.\n" +
|
||||
"Separate each Assembly with a semicolon ';'." +
|
||||
"For example, to blacklist Assembly-CSharp, you would add 'Assembly-CSharp;'",
|
||||
"");
|
||||
|
||||
Force_Unlock_Toggle = new ConfigElement<KeyCode>("Force Unlock Toggle Key",
|
||||
"The keybind to toggle the 'Force Unlock Mouse' setting. Only usable when UnityExplorer is open.",
|
||||
KeyCode.None);
|
||||
|
||||
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);
|
||||
Disable_EventSystem_Override.OnValueChanged += (bool value) => UniverseLib.Config.ConfigManager.Disable_EventSystem_Override = value;
|
||||
|
||||
Log_Unity_Debug = new ConfigElement<bool>("Log Unity Debug",
|
||||
"Should UnityEngine.Debug.Log messages be printed to UnityExplorer's log?",
|
||||
false);
|
||||
|
||||
Default_Output_Path = new ConfigElement<string>("Default Output Path",
|
||||
"The default output path when exporting things from UnityExplorer.",
|
||||
Path.Combine(ExplorerCore.ExplorerFolder, "Output"));
|
||||
|
||||
Startup_Delay_Time = new ConfigElement<float>("Startup Delay Time",
|
||||
"The delay on startup before the UI is created.",
|
||||
1f);
|
||||
|
||||
Reflection_Signature_Blacklist = new ConfigElement<string>("Member Signature Blacklist",
|
||||
Reflection_Signature_Blacklist = new("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 'UnityEngine.Camera.main;'",
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace UnityExplorer.Config
|
||||
namespace UnityExplorer.Config
|
||||
{
|
||||
public interface IConfigElement
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Tomlet;
|
||||
using Tomlet;
|
||||
using Tomlet.Models;
|
||||
using UnityExplorer.UI;
|
||||
|
||||
@@ -48,6 +45,9 @@ namespace UnityExplorer.Config
|
||||
TomlDocument document = TomlParser.ParseFile(CONFIG_PATH);
|
||||
foreach (string key in document.Keys)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(UIManager.Panels), key))
|
||||
continue;
|
||||
|
||||
UIManager.Panels panelKey = (UIManager.Panels)Enum.Parse(typeof(UIManager.Panels), key);
|
||||
ConfigManager.GetPanelSaveData(panelKey).Value = document.GetString(key);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
using UnityEngine;
|
||||
using UnityExplorer.UI;
|
||||
#if CPP
|
||||
#if UNHOLLOWER
|
||||
using UnhollowerRuntimeLib;
|
||||
#else
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace UnityExplorer
|
||||
@@ -29,5 +33,39 @@ namespace UnityExplorer
|
||||
{
|
||||
ExplorerCore.Update();
|
||||
}
|
||||
|
||||
// For editor, to clean up objects
|
||||
|
||||
internal void OnDestroy()
|
||||
{
|
||||
OnApplicationQuit();
|
||||
}
|
||||
|
||||
internal bool quitting;
|
||||
|
||||
internal void OnApplicationQuit()
|
||||
{
|
||||
if (quitting) return;
|
||||
quitting = true;
|
||||
|
||||
TryDestroy(UIManager.UIRoot?.transform.root.gameObject);
|
||||
|
||||
TryDestroy((typeof(Universe).Assembly.GetType("UniverseLib.UniversalBehaviour")
|
||||
.GetProperty("Instance", BindingFlags.Static | BindingFlags.NonPublic)
|
||||
.GetValue(null, null)
|
||||
as Component).gameObject);
|
||||
|
||||
TryDestroy(this.gameObject);
|
||||
}
|
||||
|
||||
internal void TryDestroy(GameObject obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (obj)
|
||||
Destroy(obj);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-5
@@ -1,12 +1,17 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.IO;
|
||||
global using System.Linq;
|
||||
global using System.Reflection;
|
||||
global using UnityEngine;
|
||||
global using UnityEngine.UI;
|
||||
global using UniverseLib;
|
||||
global using UniverseLib.Utility;
|
||||
using UnityExplorer.Config;
|
||||
using UnityExplorer.ObjectExplorer;
|
||||
using UnityExplorer.Runtime;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib;
|
||||
using UniverseLib.Input;
|
||||
|
||||
namespace UnityExplorer
|
||||
@@ -14,7 +19,7 @@ namespace UnityExplorer
|
||||
public static class ExplorerCore
|
||||
{
|
||||
public const string NAME = "UnityExplorer";
|
||||
public const string VERSION = "4.7.2";
|
||||
public const string VERSION = "4.9.0";
|
||||
public const string AUTHOR = "Sinai";
|
||||
public const string GUID = "com.sinai.unityexplorer";
|
||||
|
||||
@@ -72,7 +77,9 @@ namespace UnityExplorer
|
||||
{
|
||||
// check master toggle
|
||||
if (InputManager.GetKeyDown(ConfigManager.Master_Toggle.Value))
|
||||
{
|
||||
UIManager.ShowMenu = !UIManager.ShowMenu;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
|
||||
@@ -16,14 +14,13 @@ namespace UnityExplorer.Hooks
|
||||
public float DefaultHeight => 30;
|
||||
|
||||
public Text MethodNameLabel;
|
||||
public Text HookedLabel;
|
||||
public ButtonRef HookButton;
|
||||
|
||||
public int CurrentDisplayedIndex;
|
||||
|
||||
private void OnHookClicked()
|
||||
{
|
||||
HookManager.Instance.AddHookClicked(CurrentDisplayedIndex);
|
||||
HookCreator.AddHookClicked(CurrentDisplayedIndex);
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
@@ -44,9 +41,6 @@ namespace UnityExplorer.Hooks
|
||||
UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600);
|
||||
UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
HookedLabel = UIFactory.CreateLabel(UIRoot, "HookedLabel", "✓", TextAnchor.MiddleCenter, Color.green);
|
||||
UIFactory.SetLayoutElement(HookedLabel.gameObject, minHeight: 25, minWidth: 100);
|
||||
|
||||
HookButton = UIFactory.CreateButton(UIRoot, "HookButton", "Hook", new Color(0.2f, 0.25f, 0.2f));
|
||||
UIFactory.SetLayoutElement(HookButton.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||
HookButton.OnClick += OnHookClicked;
|
||||
|
||||
+13
-14
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
|
||||
@@ -24,17 +22,18 @@ namespace UnityExplorer.Hooks
|
||||
|
||||
private void OnToggleActiveClicked()
|
||||
{
|
||||
HookManager.Instance.EnableOrDisableHookClicked(CurrentDisplayedIndex);
|
||||
HookList.EnableOrDisableHookClicked(CurrentDisplayedIndex);
|
||||
}
|
||||
|
||||
private void OnDeleteClicked()
|
||||
{
|
||||
HookManager.Instance.DeleteHookClicked(CurrentDisplayedIndex);
|
||||
HookList.DeleteHookClicked(CurrentDisplayedIndex);
|
||||
HookCreator.AddHooksScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
private void OnEditPatchClicked()
|
||||
{
|
||||
HookManager.Instance.EditPatchClicked(CurrentDisplayedIndex);
|
||||
HookList.EditPatchClicked(CurrentDisplayedIndex);
|
||||
}
|
||||
|
||||
public GameObject CreateContent(GameObject parent)
|
||||
@@ -48,18 +47,18 @@ namespace UnityExplorer.Hooks
|
||||
MethodNameLabel = UIFactory.CreateLabel(UIRoot, "MethodName", "NOT SET", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(MethodNameLabel.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
ToggleActiveButton = UIFactory.CreateButton(UIRoot, "ToggleActiveBtn", "Enabled", new Color(0.15f, 0.2f, 0.15f));
|
||||
UIFactory.SetLayoutElement(ToggleActiveButton.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||
ToggleActiveButton = UIFactory.CreateButton(UIRoot, "ToggleActiveBtn", "On", new Color(0.15f, 0.2f, 0.15f));
|
||||
UIFactory.SetLayoutElement(ToggleActiveButton.Component.gameObject, minHeight: 25, minWidth: 35);
|
||||
ToggleActiveButton.OnClick += OnToggleActiveClicked;
|
||||
|
||||
DeleteButton = UIFactory.CreateButton(UIRoot, "DeleteButton", "Delete", new Color(0.2f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(DeleteButton.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||
DeleteButton.OnClick += OnDeleteClicked;
|
||||
|
||||
EditPatchButton = UIFactory.CreateButton(UIRoot, "EditButton", "Edit Hook Source", new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(EditPatchButton.Component.gameObject, minHeight: 25, minWidth: 150);
|
||||
EditPatchButton = UIFactory.CreateButton(UIRoot, "EditButton", "Edit", new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(EditPatchButton.Component.gameObject, minHeight: 25, minWidth: 35);
|
||||
EditPatchButton.OnClick += OnEditPatchClicked;
|
||||
|
||||
DeleteButton = UIFactory.CreateButton(UIRoot, "DeleteButton", "X", new Color(0.2f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(DeleteButton.Component.gameObject, minHeight: 25, minWidth: 35);
|
||||
DeleteButton.OnClick += OnDeleteClicked;
|
||||
|
||||
return UIRoot;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
using HarmonyLib;
|
||||
using UnityExplorer.CSConsole;
|
||||
using UnityExplorer.Runtime;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
|
||||
namespace UnityExplorer.Hooks
|
||||
{
|
||||
public class HookCreator : ICellPoolDataSource<AddHookCell>
|
||||
{
|
||||
public int ItemCount => filteredEligibleMethods.Count;
|
||||
|
||||
static readonly List<MethodInfo> currentAddEligibleMethods = new();
|
||||
static readonly List<MethodInfo> filteredEligibleMethods = new();
|
||||
static readonly List<string> currentEligibleNamesForFiltering = new();
|
||||
|
||||
// hook editor
|
||||
static readonly LexerBuilder Lexer = new();
|
||||
internal static HookInstance CurrentEditedHook;
|
||||
|
||||
// Add Hooks UI
|
||||
internal static GameObject AddHooksRoot;
|
||||
internal static ScrollPool<AddHookCell> AddHooksScrollPool;
|
||||
internal static Text AddHooksLabel;
|
||||
internal static InputFieldRef AddHooksMethodFilterInput;
|
||||
internal static InputFieldRef ClassSelectorInputField;
|
||||
internal static Type pendingGenericDefinition;
|
||||
internal static MethodInfo pendingGenericMethod;
|
||||
|
||||
public static bool PendingGeneric => pendingGenericDefinition != null || pendingGenericMethod != null;
|
||||
|
||||
// Hook Source Editor UI
|
||||
public static GameObject EditorRoot { get; private set; }
|
||||
public static Text EditingHookLabel { get; private set; }
|
||||
public static InputFieldScroller EditorInputScroller { get; private set; }
|
||||
public static InputFieldRef EditorInput => EditorInputScroller.InputField;
|
||||
public static Text EditorInputText { get; private set; }
|
||||
public static Text EditorHighlightText { get; private set; }
|
||||
|
||||
// ~~~~~~ New hook method selector ~~~~~~~
|
||||
|
||||
public void OnClassSelectedForHooks(string typeFullName)
|
||||
{
|
||||
Type type = ReflectionUtility.GetTypeByName(typeFullName);
|
||||
if (type == null)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not find any type by name {typeFullName}!");
|
||||
return;
|
||||
}
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
pendingGenericDefinition = type;
|
||||
HookManagerPanel.genericArgsHandler.Show(OnGenericClassChosen, OnGenericClassCancel, type);
|
||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.GenericArgsSelector);
|
||||
return;
|
||||
}
|
||||
|
||||
ShowMethodsForType(type);
|
||||
}
|
||||
|
||||
void ShowMethodsForType(Type type)
|
||||
{
|
||||
SetAddHooksLabelType(SignatureHighlighter.Parse(type, true));
|
||||
|
||||
AddHooksMethodFilterInput.Text = string.Empty;
|
||||
|
||||
filteredEligibleMethods.Clear();
|
||||
currentAddEligibleMethods.Clear();
|
||||
currentEligibleNamesForFiltering.Clear();
|
||||
foreach (MethodInfo method in type.GetMethods(ReflectionUtility.FLAGS))
|
||||
{
|
||||
if (UERuntimeHelper.IsBlacklisted(method))
|
||||
continue;
|
||||
currentAddEligibleMethods.Add(method);
|
||||
currentEligibleNamesForFiltering.Add(SignatureHighlighter.RemoveHighlighting(SignatureHighlighter.ParseMethod(method)));
|
||||
filteredEligibleMethods.Add(method);
|
||||
}
|
||||
|
||||
AddHooksScrollPool.Refresh(true, true);
|
||||
}
|
||||
|
||||
void OnGenericClassChosen(Type[] genericArgs)
|
||||
{
|
||||
Type generic = pendingGenericDefinition.MakeGenericType(genericArgs);
|
||||
ShowMethodsForType(generic);
|
||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
||||
}
|
||||
|
||||
void OnGenericClassCancel()
|
||||
{
|
||||
pendingGenericDefinition = null;
|
||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
||||
}
|
||||
|
||||
public void SetAddHooksLabelType(string typeText)
|
||||
{
|
||||
AddHooksLabel.text = $"Adding hooks to: {typeText}";
|
||||
|
||||
AddHooksMethodFilterInput.GameObject.SetActive(true);
|
||||
AddHooksScrollPool.UIRoot.SetActive(true);
|
||||
}
|
||||
|
||||
public static void AddHookClicked(int index)
|
||||
{
|
||||
if (index >= filteredEligibleMethods.Count)
|
||||
return;
|
||||
|
||||
MethodInfo method = filteredEligibleMethods[index];
|
||||
if (!method.IsGenericMethod && HookList.hookedSignatures.Contains(method.FullDescription()))
|
||||
{
|
||||
ExplorerCore.Log($"Non-generic methods can only be hooked once.");
|
||||
return;
|
||||
}
|
||||
else if (method.IsGenericMethod)
|
||||
{
|
||||
pendingGenericMethod = method;
|
||||
HookManagerPanel.genericArgsHandler.Show(OnGenericMethodChosen, OnGenericMethodCancel, method);
|
||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.GenericArgsSelector);
|
||||
return;
|
||||
}
|
||||
|
||||
AddHook(filteredEligibleMethods[index]);
|
||||
}
|
||||
|
||||
static void OnGenericMethodChosen(Type[] arguments)
|
||||
{
|
||||
MethodInfo generic = pendingGenericMethod.MakeGenericMethod(arguments);
|
||||
AddHook(generic);
|
||||
}
|
||||
|
||||
static void OnGenericMethodCancel()
|
||||
{
|
||||
pendingGenericMethod = null;
|
||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
||||
}
|
||||
|
||||
public static void AddHook(MethodInfo method)
|
||||
{
|
||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
||||
|
||||
string sig = method.FullDescription();
|
||||
if (HookList.hookedSignatures.Contains(sig))
|
||||
{
|
||||
ExplorerCore.LogWarning($"Method is already hooked!");
|
||||
return;
|
||||
}
|
||||
|
||||
HookInstance hook = new(method);
|
||||
HookList.hookedSignatures.Add(sig);
|
||||
HookList.currentHooks.Add(sig, hook);
|
||||
|
||||
AddHooksScrollPool.Refresh(true, false);
|
||||
HookList.HooksScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
public void OnAddHookFilterInputChanged(string input)
|
||||
{
|
||||
filteredEligibleMethods.Clear();
|
||||
|
||||
if (string.IsNullOrEmpty(input))
|
||||
filteredEligibleMethods.AddRange(currentAddEligibleMethods);
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < currentAddEligibleMethods.Count; i++)
|
||||
{
|
||||
MethodInfo eligible = currentAddEligibleMethods[i];
|
||||
string sig = currentEligibleNamesForFiltering[i];
|
||||
if (sig.ContainsIgnoreCase(input))
|
||||
filteredEligibleMethods.Add(eligible);
|
||||
}
|
||||
}
|
||||
|
||||
AddHooksScrollPool.Refresh(true, true);
|
||||
}
|
||||
|
||||
// Set eligible method cell
|
||||
|
||||
public void OnCellBorrowed(AddHookCell cell) { }
|
||||
|
||||
public void SetCell(AddHookCell cell, int index)
|
||||
{
|
||||
if (index >= filteredEligibleMethods.Count)
|
||||
{
|
||||
cell.Disable();
|
||||
return;
|
||||
}
|
||||
|
||||
cell.CurrentDisplayedIndex = index;
|
||||
MethodInfo method = filteredEligibleMethods[index];
|
||||
|
||||
cell.MethodNameLabel.text = SignatureHighlighter.ParseMethod(method);
|
||||
}
|
||||
|
||||
// ~~~~~~~~ Hook source editor ~~~~~~~~
|
||||
|
||||
internal static void SetEditedHook(HookInstance hook)
|
||||
{
|
||||
CurrentEditedHook = hook;
|
||||
EditingHookLabel.text = $"Editing: {SignatureHighlighter.Parse(hook.TargetMethod.DeclaringType, false, hook.TargetMethod)}";
|
||||
EditorInput.Text = hook.PatchSourceCode;
|
||||
}
|
||||
|
||||
internal static void OnEditorInputChanged(string value)
|
||||
{
|
||||
EditorHighlightText.text = Lexer.BuildHighlightedString(value, 0, value.Length - 1, 0, EditorInput.Component.caretPosition, out _);
|
||||
}
|
||||
|
||||
internal static void EditorInputCancel()
|
||||
{
|
||||
CurrentEditedHook = null;
|
||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
||||
}
|
||||
|
||||
internal static void EditorInputSave()
|
||||
{
|
||||
string input = EditorInput.Text;
|
||||
bool wasEnabled = CurrentEditedHook.Enabled;
|
||||
if (CurrentEditedHook.CompileAndGenerateProcessor(input))
|
||||
{
|
||||
if (wasEnabled)
|
||||
CurrentEditedHook.Patch();
|
||||
|
||||
CurrentEditedHook.PatchSourceCode = input;
|
||||
CurrentEditedHook = null;
|
||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
||||
}
|
||||
|
||||
HookList.HooksScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
// UI Construction
|
||||
|
||||
internal void ConstructAddHooksView(GameObject rightGroup)
|
||||
{
|
||||
AddHooksRoot = UIFactory.CreateUIObject("AddHooksPanel", rightGroup);
|
||||
UIFactory.SetLayoutElement(AddHooksRoot, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(AddHooksRoot, false, false, true, true);
|
||||
|
||||
GameObject addRow = UIFactory.CreateHorizontalGroup(AddHooksRoot, "AddRow", false, true, true, true, 4,
|
||||
new Vector4(2, 2, 2, 2), new Color(0.2f, 0.2f, 0.2f));
|
||||
UIFactory.SetLayoutElement(addRow, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
|
||||
ClassSelectorInputField = UIFactory.CreateInputField(addRow, "ClassInput", "Enter a class to add hooks to...");
|
||||
UIFactory.SetLayoutElement(ClassSelectorInputField.Component.gameObject, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0);
|
||||
TypeCompleter completer = new(typeof(object), ClassSelectorInputField, true, false, true);
|
||||
//completer.AllTypes = true;
|
||||
|
||||
ButtonRef addButton = UIFactory.CreateButton(addRow, "AddButton", "View Methods");
|
||||
UIFactory.SetLayoutElement(addButton.Component.gameObject, minWidth: 110, minHeight: 25);
|
||||
addButton.OnClick += () => { OnClassSelectedForHooks(ClassSelectorInputField.Text); };
|
||||
|
||||
AddHooksLabel = UIFactory.CreateLabel(AddHooksRoot, "AddLabel", "Choose a class to begin...", TextAnchor.MiddleCenter);
|
||||
UIFactory.SetLayoutElement(AddHooksLabel.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999);
|
||||
|
||||
AddHooksMethodFilterInput = UIFactory.CreateInputField(AddHooksRoot, "FilterInputField", "Filter method names...");
|
||||
UIFactory.SetLayoutElement(AddHooksMethodFilterInput.Component.gameObject, minHeight: 30, flexibleWidth: 9999);
|
||||
AddHooksMethodFilterInput.OnValueChanged += OnAddHookFilterInputChanged;
|
||||
|
||||
AddHooksScrollPool = UIFactory.CreateScrollPool<AddHookCell>(AddHooksRoot, "MethodAddScrollPool",
|
||||
out GameObject addScrollRoot, out GameObject addContent);
|
||||
UIFactory.SetLayoutElement(addScrollRoot, flexibleHeight: 9999);
|
||||
AddHooksScrollPool.Initialize(this);
|
||||
|
||||
AddHooksMethodFilterInput.GameObject.SetActive(false);
|
||||
AddHooksScrollPool.UIRoot.SetActive(false);
|
||||
}
|
||||
|
||||
public void ConstructEditor(GameObject parent)
|
||||
{
|
||||
EditorRoot = UIFactory.CreateUIObject("HookSourceEditor", parent);
|
||||
UIFactory.SetLayoutElement(EditorRoot, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(EditorRoot, true, true, true, true, 2, 3, 3, 3, 3);
|
||||
|
||||
EditingHookLabel = UIFactory.CreateLabel(EditorRoot, "EditingHookLabel", "NOT SET", TextAnchor.MiddleCenter);
|
||||
EditingHookLabel.fontStyle = FontStyle.Bold;
|
||||
UIFactory.SetLayoutElement(EditingHookLabel.gameObject, flexibleWidth: 9999, minHeight: 25);
|
||||
|
||||
Text editorLabel = UIFactory.CreateLabel(EditorRoot,
|
||||
"EditorLabel",
|
||||
"* Accepted method names are <b>Prefix</b>, <b>Postfix</b>, <b>Finalizer</b> and <b>Transpiler</b> (can define multiple).\n" +
|
||||
"* Your patch methods must be static.\n" +
|
||||
"* Hooks are temporary! Copy the source into your IDE to avoid losing work if you wish to keep it!",
|
||||
TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(editorLabel.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
GameObject editorButtonRow = UIFactory.CreateHorizontalGroup(EditorRoot, "ButtonRow", false, false, true, true, 5);
|
||||
UIFactory.SetLayoutElement(editorButtonRow, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
ButtonRef editorSaveButton = UIFactory.CreateButton(editorButtonRow, "DoneButton", "Save and Return", new Color(0.2f, 0.3f, 0.2f));
|
||||
UIFactory.SetLayoutElement(editorSaveButton.Component.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
editorSaveButton.OnClick += EditorInputSave;
|
||||
|
||||
ButtonRef editorDoneButton = UIFactory.CreateButton(editorButtonRow, "DoneButton", "Cancel and Return", new Color(0.2f, 0.2f, 0.2f));
|
||||
UIFactory.SetLayoutElement(editorDoneButton.Component.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
editorDoneButton.OnClick += EditorInputCancel;
|
||||
|
||||
int fontSize = 16;
|
||||
GameObject inputObj = UIFactory.CreateScrollInputField(EditorRoot, "EditorInput", "", out InputFieldScroller inputScroller, fontSize);
|
||||
EditorInputScroller = inputScroller;
|
||||
EditorInput.OnValueChanged += OnEditorInputChanged;
|
||||
|
||||
EditorInputText = EditorInput.Component.textComponent;
|
||||
EditorInputText.supportRichText = false;
|
||||
EditorInputText.color = Color.clear;
|
||||
EditorInput.Component.customCaretColor = true;
|
||||
EditorInput.Component.caretColor = Color.white;
|
||||
EditorInput.PlaceholderText.fontSize = fontSize;
|
||||
|
||||
// Lexer highlight text overlay
|
||||
GameObject highlightTextObj = UIFactory.CreateUIObject("HighlightText", EditorInputText.gameObject);
|
||||
RectTransform highlightTextRect = highlightTextObj.GetComponent<RectTransform>();
|
||||
highlightTextRect.pivot = new Vector2(0, 1);
|
||||
highlightTextRect.anchorMin = Vector2.zero;
|
||||
highlightTextRect.anchorMax = Vector2.one;
|
||||
highlightTextRect.offsetMin = Vector2.zero;
|
||||
highlightTextRect.offsetMax = Vector2.zero;
|
||||
|
||||
EditorHighlightText = highlightTextObj.AddComponent<Text>();
|
||||
EditorHighlightText.color = Color.white;
|
||||
EditorHighlightText.supportRichText = true;
|
||||
EditorHighlightText.fontSize = fontSize;
|
||||
|
||||
// Set fonts
|
||||
EditorInputText.font = UniversalUI.ConsoleFont;
|
||||
EditorInput.PlaceholderText.font = UniversalUI.ConsoleFont;
|
||||
EditorHighlightText.font = UniversalUI.ConsoleFont;
|
||||
}
|
||||
}
|
||||
}
|
||||
+65
-45
@@ -1,12 +1,7 @@
|
||||
using HarmonyLib;
|
||||
using Mono.CSharp;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityExplorer.CSConsole;
|
||||
using UniverseLib;
|
||||
|
||||
namespace UnityExplorer.Hooks
|
||||
{
|
||||
@@ -14,12 +9,13 @@ namespace UnityExplorer.Hooks
|
||||
{
|
||||
// Static
|
||||
|
||||
private static readonly StringBuilder evalOutput = new();
|
||||
private static readonly ScriptEvaluator scriptEvaluator = new(new StringWriter(evalOutput));
|
||||
static readonly StringBuilder evaluatorOutput;
|
||||
static readonly ScriptEvaluator scriptEvaluator = new(new StringWriter(evaluatorOutput = new StringBuilder()));
|
||||
|
||||
static HookInstance()
|
||||
{
|
||||
scriptEvaluator.Run("using System;");
|
||||
scriptEvaluator.Run("using System.Text;");
|
||||
scriptEvaluator.Run("using System.Reflection;");
|
||||
scriptEvaluator.Run("using System.Collections;");
|
||||
scriptEvaluator.Run("using System.Collections.Generic;");
|
||||
@@ -28,21 +24,22 @@ namespace UnityExplorer.Hooks
|
||||
// Instance
|
||||
|
||||
public bool Enabled;
|
||||
|
||||
public MethodInfo TargetMethod;
|
||||
public string PatchSourceCode;
|
||||
|
||||
private readonly string shortSignature;
|
||||
private PatchProcessor patchProcessor;
|
||||
readonly string signature;
|
||||
PatchProcessor patchProcessor;
|
||||
|
||||
private MethodInfo postfix;
|
||||
private MethodInfo prefix;
|
||||
private MethodInfo finalizer;
|
||||
private MethodInfo transpiler;
|
||||
MethodInfo postfix;
|
||||
MethodInfo prefix;
|
||||
MethodInfo finalizer;
|
||||
MethodInfo transpiler;
|
||||
|
||||
public HookInstance(MethodInfo targetMethod)
|
||||
{
|
||||
this.TargetMethod = targetMethod;
|
||||
this.shortSignature = $"{targetMethod.DeclaringType.Name}.{targetMethod.Name}";
|
||||
this.signature = TargetMethod.FullDescription();
|
||||
|
||||
GenerateDefaultPatchSourceCode(targetMethod);
|
||||
|
||||
@@ -59,15 +56,15 @@ namespace UnityExplorer.Hooks
|
||||
{
|
||||
Unpatch();
|
||||
|
||||
StringBuilder codeBuilder = new();
|
||||
|
||||
try
|
||||
{
|
||||
patchProcessor = ExplorerCore.Harmony.CreateProcessor(TargetMethod);
|
||||
|
||||
// Dynamically compile the patch method
|
||||
|
||||
StringBuilder codeBuilder = new();
|
||||
|
||||
codeBuilder.AppendLine($"public class DynamicPatch_{DateTime.Now.Ticks}");
|
||||
codeBuilder.AppendLine($"static class DynamicPatch_{DateTime.Now.Ticks}");
|
||||
codeBuilder.AppendLine("{");
|
||||
codeBuilder.AppendLine(patchSource);
|
||||
codeBuilder.AppendLine("}");
|
||||
@@ -107,85 +104,108 @@ namespace UnityExplorer.Hooks
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception creating patch processor for target method {TargetMethod.FullDescription()}!\r\n{ex}");
|
||||
if (ex is FormatException)
|
||||
{
|
||||
string output = scriptEvaluator._textWriter.ToString();
|
||||
string[] outputSplit = output.Split('\n');
|
||||
if (outputSplit.Length >= 2)
|
||||
output = outputSplit[outputSplit.Length - 2];
|
||||
evaluatorOutput.Clear();
|
||||
|
||||
if (ScriptEvaluator._reportPrinter.ErrorsCount > 0)
|
||||
ExplorerCore.LogWarning($"Unable to compile the code. Evaluator's last output was:\r\n{output}");
|
||||
else
|
||||
ExplorerCore.LogWarning($"Exception generating patch source code: {ex}");
|
||||
}
|
||||
else
|
||||
ExplorerCore.LogWarning($"Exception generating patch source code: {ex}");
|
||||
|
||||
// ExplorerCore.Log(codeBuilder.ToString());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static string FullDescriptionClean(Type type)
|
||||
{
|
||||
string description = type.FullDescription().Replace("+", ".");
|
||||
if (description.EndsWith("&"))
|
||||
description = $"ref {description.Substring(0, description.Length - 1)}";
|
||||
return description;
|
||||
}
|
||||
|
||||
private string GenerateDefaultPatchSourceCode(MethodInfo targetMethod)
|
||||
{
|
||||
StringBuilder codeBuilder = new();
|
||||
// Arguments
|
||||
|
||||
codeBuilder.Append("public static void Postfix(System.Reflection.MethodBase __originalMethod");
|
||||
codeBuilder.Append("static void Postfix(");
|
||||
|
||||
if (!targetMethod.IsStatic)
|
||||
codeBuilder.Append($", {targetMethod.DeclaringType.FullName} __instance");
|
||||
bool isStatic = targetMethod.IsStatic;
|
||||
|
||||
List<string> arguments = new();
|
||||
|
||||
if (!isStatic)
|
||||
arguments.Add($"{FullDescriptionClean(targetMethod.DeclaringType)} __instance");
|
||||
|
||||
if (targetMethod.ReturnType != typeof(void))
|
||||
codeBuilder.Append($", {targetMethod.ReturnType.FullName} __result");
|
||||
arguments.Add($"{FullDescriptionClean(targetMethod.ReturnType)} __result");
|
||||
|
||||
ParameterInfo[] parameters = targetMethod.GetParameters();
|
||||
|
||||
int paramIdx = 0;
|
||||
foreach (ParameterInfo param in parameters)
|
||||
{
|
||||
codeBuilder.Append($", {param.ParameterType.FullDescription().Replace("&", "")} __{paramIdx}");
|
||||
arguments.Add($"{FullDescriptionClean(param.ParameterType)} __{paramIdx}");
|
||||
paramIdx++;
|
||||
}
|
||||
|
||||
codeBuilder.Append(string.Join(", ", arguments.ToArray()));
|
||||
|
||||
codeBuilder.Append(")\n");
|
||||
|
||||
// Patch body
|
||||
|
||||
codeBuilder.AppendLine("{");
|
||||
|
||||
codeBuilder.AppendLine(" try {");
|
||||
|
||||
// Log message
|
||||
|
||||
StringBuilder logMessage = new();
|
||||
logMessage.Append($"Patch called: {shortSignature}\\n");
|
||||
codeBuilder.AppendLine(" StringBuilder sb = new StringBuilder();");
|
||||
codeBuilder.AppendLine($" sb.AppendLine(\"--------------------\");");
|
||||
codeBuilder.AppendLine($" sb.AppendLine(\"{signature}\");");
|
||||
|
||||
if (!targetMethod.IsStatic)
|
||||
logMessage.Append("__instance: {__instance.ToString()}\\n");
|
||||
codeBuilder.AppendLine($" sb.Append(\"- __instance: \").AppendLine(__instance.ToString());");
|
||||
|
||||
paramIdx = 0;
|
||||
foreach (ParameterInfo param in parameters)
|
||||
{
|
||||
logMessage.Append($"Parameter {paramIdx} {param.Name}: ");
|
||||
codeBuilder.Append($" sb.Append(\"- Parameter {paramIdx} '{param.Name}': \")");
|
||||
|
||||
Type pType = param.ParameterType;
|
||||
if (pType.IsByRef) pType = pType.GetElementType();
|
||||
if (pType.IsValueType)
|
||||
logMessage.Append($"{{__{paramIdx}.ToString()}}");
|
||||
codeBuilder.AppendLine($".AppendLine(__{paramIdx}.ToString());");
|
||||
else
|
||||
logMessage.Append($"{{__{paramIdx}?.ToString() ?? \"null\"}}");
|
||||
logMessage.Append("\\n");
|
||||
codeBuilder.AppendLine($".AppendLine(__{paramIdx}?.ToString() ?? \"null\");");
|
||||
|
||||
paramIdx++;
|
||||
}
|
||||
|
||||
if (targetMethod.ReturnType != typeof(void))
|
||||
{
|
||||
logMessage.Append("Return value: ");
|
||||
codeBuilder.Append(" sb.Append(\"- Return value: \")");
|
||||
if (targetMethod.ReturnType.IsValueType)
|
||||
logMessage.Append("{__result.ToString()}");
|
||||
codeBuilder.AppendLine(".AppendLine(__result.ToString());");
|
||||
else
|
||||
logMessage.Append("{__result?.ToString() ?? \"null\"}");
|
||||
logMessage.Append("\\n");
|
||||
codeBuilder.AppendLine(".AppendLine(__result?.ToString() ?? \"null\");");
|
||||
}
|
||||
|
||||
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.Log($\"{logMessage}\");");
|
||||
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.Log(sb.ToString());");
|
||||
codeBuilder.AppendLine(" }");
|
||||
codeBuilder.AppendLine(" catch (System.Exception ex) {");
|
||||
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.LogWarning($\"Exception in patch of {shortSignature}:\\n{{ex}}\");");
|
||||
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.LogWarning($\"Exception in patch of {signature}:\\n{{ex}}\");");
|
||||
codeBuilder.AppendLine(" }");
|
||||
|
||||
// End patch body
|
||||
|
||||
codeBuilder.AppendLine("}");
|
||||
|
||||
//ExplorerCore.Log(codeBuilder.ToString());
|
||||
|
||||
return PatchSourceCode = codeBuilder.ToString();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
using HarmonyLib;
|
||||
using System.Collections.Specialized;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
|
||||
namespace UnityExplorer.Hooks
|
||||
{
|
||||
public class HookList : ICellPoolDataSource<HookCell>
|
||||
{
|
||||
public int ItemCount => currentHooks.Count;
|
||||
|
||||
internal static readonly HashSet<string> hookedSignatures = new();
|
||||
internal static readonly OrderedDictionary currentHooks = new();
|
||||
|
||||
internal static GameObject UIRoot;
|
||||
internal static ScrollPool<HookCell> HooksScrollPool;
|
||||
|
||||
public static void EnableOrDisableHookClicked(int index)
|
||||
{
|
||||
HookInstance hook = (HookInstance)currentHooks[index];
|
||||
hook.TogglePatch();
|
||||
|
||||
HooksScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
public static void DeleteHookClicked(int index)
|
||||
{
|
||||
HookInstance hook = (HookInstance)currentHooks[index];
|
||||
|
||||
if (HookCreator.CurrentEditedHook == hook)
|
||||
HookCreator.EditorInputCancel();
|
||||
|
||||
hook.Unpatch();
|
||||
currentHooks.RemoveAt(index);
|
||||
hookedSignatures.Remove(hook.TargetMethod.FullDescription());
|
||||
|
||||
HooksScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
public static void EditPatchClicked(int index)
|
||||
{
|
||||
if (HookCreator.PendingGeneric)
|
||||
HookManagerPanel.genericArgsHandler.Cancel();
|
||||
|
||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.HookSourceEditor);
|
||||
HookInstance hook = (HookInstance)currentHooks[index];
|
||||
HookCreator.SetEditedHook(hook);
|
||||
}
|
||||
|
||||
// Set current hook cell
|
||||
|
||||
public void OnCellBorrowed(HookCell cell) { }
|
||||
|
||||
public void SetCell(HookCell cell, int index)
|
||||
{
|
||||
if (index >= currentHooks.Count)
|
||||
{
|
||||
cell.Disable();
|
||||
return;
|
||||
}
|
||||
|
||||
cell.CurrentDisplayedIndex = index;
|
||||
HookInstance hook = (HookInstance)currentHooks[index];
|
||||
|
||||
cell.MethodNameLabel.text = SignatureHighlighter.ParseMethod(hook.TargetMethod);
|
||||
|
||||
cell.ToggleActiveButton.ButtonText.text = hook.Enabled ? "On" : "Off";
|
||||
RuntimeHelper.SetColorBlockAuto(cell.ToggleActiveButton.Component,
|
||||
hook.Enabled ? new Color(0.15f, 0.2f, 0.15f) : new Color(0.2f, 0.2f, 0.15f));
|
||||
}
|
||||
|
||||
// UI
|
||||
|
||||
internal void ConstructUI(GameObject leftGroup)
|
||||
{
|
||||
UIRoot = UIFactory.CreateUIObject("CurrentHooksPanel", leftGroup);
|
||||
UIFactory.SetLayoutElement(UIRoot, preferredHeight: 150, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(UIRoot, true, true, true, true);
|
||||
|
||||
Text hooksLabel = UIFactory.CreateLabel(UIRoot, "HooksLabel", "Current Hooks", TextAnchor.MiddleCenter);
|
||||
UIFactory.SetLayoutElement(hooksLabel.gameObject, minHeight: 30, flexibleWidth: 9999);
|
||||
|
||||
HooksScrollPool = UIFactory.CreateScrollPool<HookCell>(UIRoot, "HooksScrollPool",
|
||||
out GameObject hooksScroll, out GameObject hooksContent);
|
||||
UIFactory.SetLayoutElement(hooksScroll, flexibleHeight: 9999);
|
||||
HooksScrollPool.Initialize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.CSConsole;
|
||||
using UnityExplorer.Runtime;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.Hooks
|
||||
{
|
||||
public class HookManager : ICellPoolDataSource<HookCell>, ICellPoolDataSource<AddHookCell>
|
||||
{
|
||||
private static HookManager s_instance;
|
||||
public static HookManager Instance => s_instance ?? (s_instance = new HookManager());
|
||||
|
||||
public HookManagerPanel Panel => UIManager.GetPanel<HookManagerPanel>(UIManager.Panels.HookManager);
|
||||
|
||||
// This class acts as the data source for both current hooks and eligable methods when adding hooks.
|
||||
// 'isAddingMethods' keeps track of which pool is currently the displayed one, so our ItemCount reflects the
|
||||
// correct pool cells.
|
||||
private bool isAddingMethods;
|
||||
public int ItemCount => isAddingMethods ? filteredEligableMethods.Count : currentHooks.Count;
|
||||
|
||||
// current hooks
|
||||
private readonly HashSet<string> hookedSignatures = new();
|
||||
private readonly OrderedDictionary currentHooks = new();
|
||||
|
||||
// adding hooks
|
||||
private readonly List<MethodInfo> currentAddEligableMethods = new();
|
||||
private readonly List<MethodInfo> filteredEligableMethods = new();
|
||||
|
||||
// hook editor
|
||||
private readonly LexerBuilder Lexer = new();
|
||||
private HookInstance currentEditedHook;
|
||||
|
||||
// ~~~~~~~~~~~ Main Current Hooks window ~~~~~~~~~~~
|
||||
|
||||
public void EnableOrDisableHookClicked(int index)
|
||||
{
|
||||
HookInstance hook = (HookInstance)currentHooks[index];
|
||||
hook.TogglePatch();
|
||||
|
||||
Panel.HooksScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
public void DeleteHookClicked(int index)
|
||||
{
|
||||
HookInstance hook = (HookInstance)currentHooks[index];
|
||||
hook.Unpatch();
|
||||
currentHooks.RemoveAt(index);
|
||||
hookedSignatures.Remove(hook.TargetMethod.FullDescription());
|
||||
|
||||
Panel.HooksScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
public void EditPatchClicked(int index)
|
||||
{
|
||||
Panel.SetPage(HookManagerPanel.Pages.HookSourceEditor);
|
||||
HookInstance hook = (HookInstance)currentHooks[index];
|
||||
currentEditedHook = hook;
|
||||
Panel.EditorInput.Text = hook.PatchSourceCode;
|
||||
}
|
||||
|
||||
// Set current hook cell
|
||||
|
||||
public void OnCellBorrowed(HookCell cell) { }
|
||||
|
||||
public void SetCell(HookCell cell, int index)
|
||||
{
|
||||
if (index >= this.currentHooks.Count)
|
||||
{
|
||||
cell.Disable();
|
||||
return;
|
||||
}
|
||||
|
||||
cell.CurrentDisplayedIndex = index;
|
||||
HookInstance hook = (HookInstance)this.currentHooks[index];
|
||||
|
||||
cell.MethodNameLabel.text = SignatureHighlighter.HighlightMethod(hook.TargetMethod);
|
||||
|
||||
cell.ToggleActiveButton.ButtonText.text = hook.Enabled ? "Enabled" : "Disabled";
|
||||
RuntimeHelper.SetColorBlockAuto(cell.ToggleActiveButton.Component,
|
||||
hook.Enabled ? new Color(0.15f, 0.2f, 0.15f) : new Color(0.2f, 0.2f, 0.15f));
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~ Add Hooks window ~~~~~~~~~~~
|
||||
|
||||
public void OnClassSelectedForHooks(string typeFullName)
|
||||
{
|
||||
Type type = ReflectionUtility.GetTypeByName(typeFullName);
|
||||
if (type == null)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not find any type by name {typeFullName}!");
|
||||
return;
|
||||
}
|
||||
|
||||
Panel.SetAddHooksLabelType(SignatureHighlighter.Parse(type, true));
|
||||
|
||||
Panel.ResetMethodFilter();
|
||||
filteredEligableMethods.Clear();
|
||||
currentAddEligableMethods.Clear();
|
||||
foreach (MethodInfo method in type.GetMethods(ReflectionUtility.FLAGS))
|
||||
{
|
||||
if (method.IsGenericMethod || UERuntimeHelper.IsBlacklisted(method))
|
||||
continue;
|
||||
currentAddEligableMethods.Add(method);
|
||||
filteredEligableMethods.Add(method);
|
||||
}
|
||||
|
||||
isAddingMethods = true;
|
||||
Panel.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
||||
Panel.AddHooksScrollPool.Refresh(true, true);
|
||||
}
|
||||
|
||||
public void DoneAddingHooks()
|
||||
{
|
||||
isAddingMethods = false;
|
||||
Panel.SetPage(HookManagerPanel.Pages.CurrentHooks);
|
||||
Panel.HooksScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
public void AddHookClicked(int index)
|
||||
{
|
||||
if (index >= this.filteredEligableMethods.Count)
|
||||
return;
|
||||
|
||||
AddHook(filteredEligableMethods[index]);
|
||||
Panel.AddHooksScrollPool.Refresh(true, false);
|
||||
}
|
||||
|
||||
public void AddHook(MethodInfo method)
|
||||
{
|
||||
string sig = method.FullDescription();
|
||||
if (hookedSignatures.Contains(sig))
|
||||
return;
|
||||
|
||||
HookInstance hook = new(method);
|
||||
if (hook.Enabled)
|
||||
{
|
||||
hookedSignatures.Add(sig);
|
||||
currentHooks.Add(sig, hook);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAddHookFilterInputChanged(string input)
|
||||
{
|
||||
filteredEligableMethods.Clear();
|
||||
|
||||
if (string.IsNullOrEmpty(input))
|
||||
filteredEligableMethods.AddRange(currentAddEligableMethods);
|
||||
else
|
||||
{
|
||||
foreach (MethodInfo method in currentAddEligableMethods)
|
||||
{
|
||||
if (method.Name.ContainsIgnoreCase(input))
|
||||
filteredEligableMethods.Add(method);
|
||||
}
|
||||
}
|
||||
|
||||
Panel.AddHooksScrollPool.Refresh(true, true);
|
||||
}
|
||||
|
||||
// Set eligable method cell
|
||||
|
||||
public void OnCellBorrowed(AddHookCell cell) { }
|
||||
|
||||
public void SetCell(AddHookCell cell, int index)
|
||||
{
|
||||
if (index >= this.filteredEligableMethods.Count)
|
||||
{
|
||||
cell.Disable();
|
||||
return;
|
||||
}
|
||||
|
||||
cell.CurrentDisplayedIndex = index;
|
||||
MethodInfo method = this.filteredEligableMethods[index];
|
||||
|
||||
cell.MethodNameLabel.text = SignatureHighlighter.HighlightMethod(method);
|
||||
|
||||
string sig = method.FullDescription();
|
||||
if (hookedSignatures.Contains(sig))
|
||||
{
|
||||
cell.HookButton.Component.gameObject.SetActive(false);
|
||||
cell.HookedLabel.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cell.HookButton.Component.gameObject.SetActive(true);
|
||||
cell.HookedLabel.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~ Hook source editor window ~~~~~~~~~~~
|
||||
|
||||
public void OnEditorInputChanged(string value)
|
||||
{
|
||||
Panel.EditorHighlightText.text = Lexer.BuildHighlightedString(value, 0, value.Length - 1, 0,
|
||||
Panel.EditorInput.Component.caretPosition, out _);
|
||||
}
|
||||
|
||||
public void EditorInputCancel()
|
||||
{
|
||||
currentEditedHook = null;
|
||||
Panel.SetPage(HookManagerPanel.Pages.CurrentHooks);
|
||||
}
|
||||
|
||||
public void EditorInputSave()
|
||||
{
|
||||
string input = Panel.EditorInput.Text;
|
||||
bool wasEnabled = currentEditedHook.Enabled;
|
||||
if (currentEditedHook.CompileAndGenerateProcessor(input))
|
||||
{
|
||||
if (wasEnabled)
|
||||
currentEditedHook.Patch();
|
||||
currentEditedHook.PatchSourceCode = input;
|
||||
currentEditedHook = null;
|
||||
Panel.SetPage(HookManagerPanel.Pages.CurrentHooks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,21 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public class GameObjectInspector : InspectorBase
|
||||
{
|
||||
public GameObject GOTarget => Target as GameObject;
|
||||
public new GameObject Target => base.Target as GameObject;
|
||||
|
||||
public GameObject Content;
|
||||
|
||||
public GameObjectControls GOControls;
|
||||
public GameObjectControls Controls;
|
||||
|
||||
public TransformTree TransformTree;
|
||||
private ScrollPool<TransformCell> transformScroll;
|
||||
@@ -38,10 +31,10 @@ namespace UnityExplorer.Inspectors
|
||||
{
|
||||
base.OnBorrowedFromPool(target);
|
||||
|
||||
Target = target as GameObject;
|
||||
base.Target = target as GameObject;
|
||||
|
||||
GOControls.UpdateGameObjectInfo(true, true);
|
||||
GOControls.UpdateTransformControlValues(true);
|
||||
Controls.UpdateGameObjectInfo(true, true);
|
||||
Controls.TransformControl.UpdateTransformControlValues(true);
|
||||
|
||||
RuntimeHelper.StartCoroutine(InitCoroutine());
|
||||
}
|
||||
@@ -74,11 +67,11 @@ namespace UnityExplorer.Inspectors
|
||||
InspectorManager.ReleaseInspector(this);
|
||||
}
|
||||
|
||||
public void ChangeTarget(GameObject newTarget)
|
||||
public void OnTransformCellClicked(GameObject newTarget)
|
||||
{
|
||||
this.Target = newTarget;
|
||||
GOControls.UpdateGameObjectInfo(true, true);
|
||||
GOControls.UpdateTransformControlValues(true);
|
||||
base.Target = newTarget;
|
||||
Controls.UpdateGameObjectInfo(true, true);
|
||||
Controls.TransformControl.UpdateTransformControlValues(true);
|
||||
TransformTree.RefreshData(true, false, true, false);
|
||||
UpdateComponents();
|
||||
}
|
||||
@@ -90,21 +83,21 @@ namespace UnityExplorer.Inspectors
|
||||
if (!this.IsActive)
|
||||
return;
|
||||
|
||||
if (Target.IsNullOrDestroyed(false))
|
||||
if (base.Target.IsNullOrDestroyed(false))
|
||||
{
|
||||
InspectorManager.ReleaseInspector(this);
|
||||
return;
|
||||
}
|
||||
|
||||
GOControls.UpdateVectorSlider();
|
||||
GOControls.UpdateTransformControlValues(false);
|
||||
Controls.UpdateVectorSlider();
|
||||
Controls.TransformControl.UpdateTransformControlValues(false);
|
||||
|
||||
// Slow update
|
||||
if (timeOfLastUpdate.OccuredEarlierThan(1))
|
||||
{
|
||||
timeOfLastUpdate = Time.realtimeSinceStartup;
|
||||
|
||||
GOControls.UpdateGameObjectInfo(false, false);
|
||||
Controls.UpdateGameObjectInfo(false, false);
|
||||
|
||||
TransformTree.RefreshData(true, false, false, false);
|
||||
UpdateComponents();
|
||||
@@ -115,12 +108,12 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
private IEnumerable<GameObject> GetTransformEntries()
|
||||
{
|
||||
if (!GOTarget)
|
||||
if (!Target)
|
||||
return Enumerable.Empty<GameObject>();
|
||||
|
||||
cachedChildren.Clear();
|
||||
for (int i = 0; i < GOTarget.transform.childCount; i++)
|
||||
cachedChildren.Add(GOTarget.transform.GetChild(i).gameObject);
|
||||
for (int i = 0; i < Target.transform.childCount; i++)
|
||||
cachedChildren.Add(Target.transform.GetChild(i).gameObject);
|
||||
return cachedChildren;
|
||||
}
|
||||
|
||||
@@ -130,11 +123,11 @@ namespace UnityExplorer.Inspectors
|
||||
private readonly List<bool> behaviourEnabledStates = new();
|
||||
|
||||
// ComponentList.GetRootEntriesMethod
|
||||
private List<Component> GetComponentEntries() => GOTarget ? componentEntries : Enumerable.Empty<Component>().ToList();
|
||||
private List<Component> GetComponentEntries() => Target ? componentEntries : Enumerable.Empty<Component>().ToList();
|
||||
|
||||
public void UpdateComponents()
|
||||
{
|
||||
if (!GOTarget)
|
||||
if (!Target)
|
||||
{
|
||||
componentEntries.Clear();
|
||||
compInstanceIDs.Clear();
|
||||
@@ -146,8 +139,8 @@ namespace UnityExplorer.Inspectors
|
||||
}
|
||||
|
||||
// Check if we actually need to refresh the component cells or not.
|
||||
IEnumerable<Component> comps = GOTarget.GetComponents<Component>();
|
||||
IEnumerable<Behaviour> behaviours = GOTarget.GetComponents<Behaviour>();
|
||||
IEnumerable<Component> comps = Target.GetComponents<Component>();
|
||||
IEnumerable<Behaviour> behaviours = Target.GetComponents<Behaviour>();
|
||||
|
||||
bool needRefresh = false;
|
||||
|
||||
@@ -193,7 +186,8 @@ namespace UnityExplorer.Inspectors
|
||||
compInstanceIDs.Clear();
|
||||
foreach (Component comp in comps)
|
||||
{
|
||||
if (!comp) continue;
|
||||
if (!comp)
|
||||
continue;
|
||||
componentEntries.Add(comp);
|
||||
compInstanceIDs.Add(comp.GetInstanceID());
|
||||
}
|
||||
@@ -202,8 +196,23 @@ namespace UnityExplorer.Inspectors
|
||||
behaviourEnabledStates.Clear();
|
||||
foreach (Behaviour behaviour in behaviours)
|
||||
{
|
||||
if (!behaviour) continue;
|
||||
behaviourEntries.Add(behaviour);
|
||||
if (!behaviour)
|
||||
continue;
|
||||
|
||||
// Don't ask me how, but in some games this can be true for certain components.
|
||||
// They get picked up from GetComponents<Behaviour>, but they are not actually Behaviour...?
|
||||
if (!typeof(Behaviour).IsAssignableFrom(behaviour.GetType()))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
behaviourEntries.Add(behaviour);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning(ex);
|
||||
}
|
||||
|
||||
behaviourEnabledStates.Add(behaviour.enabled);
|
||||
}
|
||||
|
||||
@@ -215,7 +224,7 @@ namespace UnityExplorer.Inspectors
|
||||
private void OnAddChildClicked(string input)
|
||||
{
|
||||
GameObject newObject = new(input);
|
||||
newObject.transform.parent = GOTarget.transform;
|
||||
newObject.transform.parent = Target.transform;
|
||||
|
||||
TransformTree.RefreshData(true, false, true, false);
|
||||
}
|
||||
@@ -226,7 +235,7 @@ namespace UnityExplorer.Inspectors
|
||||
{
|
||||
try
|
||||
{
|
||||
RuntimeHelper.AddComponent<Component>(GOTarget, type);
|
||||
RuntimeHelper.AddComponent<Component>(Target, type);
|
||||
UpdateComponents();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -254,7 +263,7 @@ namespace UnityExplorer.Inspectors
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2);
|
||||
|
||||
// Construct GO Controls
|
||||
GOControls = new GameObjectControls(this);
|
||||
Controls = new GameObjectControls(this);
|
||||
|
||||
ConstructLists();
|
||||
|
||||
@@ -293,12 +302,8 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
transformScroll = UIFactory.CreateScrollPool<TransformCell>(leftGroup, "TransformTree", out GameObject transformObj,
|
||||
out GameObject transformContent, new Color(0.11f, 0.11f, 0.11f));
|
||||
UIFactory.SetLayoutElement(transformObj, flexibleHeight: 9999);
|
||||
UIFactory.SetLayoutElement(transformContent, flexibleHeight: 9999);
|
||||
|
||||
TransformTree = new TransformTree(transformScroll, GetTransformEntries);
|
||||
TransformTree.Init();
|
||||
TransformTree.OnClickOverrideHandler = ChangeTarget;
|
||||
TransformTree = new TransformTree(transformScroll, GetTransformEntries, OnTransformCellClicked);
|
||||
|
||||
// Right group (Components)
|
||||
|
||||
@@ -321,7 +326,7 @@ namespace UnityExplorer.Inspectors
|
||||
addCompButton.OnClick += () => { OnAddComponentClicked(addCompInput.Text); };
|
||||
|
||||
// comp autocompleter
|
||||
new TypeCompleter(typeof(Component), addCompInput);
|
||||
new TypeCompleter(typeof(Component), addCompInput, false, false, false);
|
||||
|
||||
// Component List
|
||||
|
||||
|
||||
@@ -1,696 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib;
|
||||
using UniverseLib.Input;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public class GameObjectControls
|
||||
{
|
||||
public GameObjectInspector Parent;
|
||||
private GameObject GOTarget => Parent.GOTarget;
|
||||
|
||||
// Top info
|
||||
|
||||
private ButtonRef ViewParentButton;
|
||||
private InputFieldRef PathInput;
|
||||
|
||||
private InputFieldRef NameInput;
|
||||
private Toggle ActiveSelfToggle;
|
||||
private Text ActiveSelfText;
|
||||
private Toggle IsStaticToggle;
|
||||
|
||||
private InputFieldRef SceneInput;
|
||||
private InputFieldRef InstanceIDInput;
|
||||
private InputFieldRef TagInput;
|
||||
|
||||
private Dropdown LayerDropdown;
|
||||
private Dropdown FlagsDropdown;
|
||||
|
||||
// transform controls
|
||||
|
||||
private TransformControl PositionControl;
|
||||
private TransformControl LocalPositionControl;
|
||||
private TransformControl RotationControl;
|
||||
private TransformControl ScaleControl;
|
||||
|
||||
private VectorSlider currentSlidingVectorControl;
|
||||
private float currentVectorValue;
|
||||
|
||||
public GameObjectControls(GameObjectInspector parent)
|
||||
{
|
||||
this.Parent = parent;
|
||||
|
||||
ConstructTopInfo();
|
||||
ConstructTransformControls();
|
||||
}
|
||||
|
||||
private void OnCopyClicked()
|
||||
{
|
||||
ClipboardPanel.Copy(this.GOTarget);
|
||||
}
|
||||
|
||||
#region GO Controls
|
||||
|
||||
private string lastGoName;
|
||||
private string lastPath;
|
||||
private bool lastParentState;
|
||||
private int lastSceneHandle;
|
||||
private string lastTag;
|
||||
private int lastLayer;
|
||||
private int lastFlags;
|
||||
|
||||
public void UpdateGameObjectInfo(bool firstUpdate, bool force)
|
||||
{
|
||||
if (firstUpdate)
|
||||
{
|
||||
InstanceIDInput.Text = GOTarget.GetInstanceID().ToString();
|
||||
}
|
||||
|
||||
if (force || (!NameInput.Component.isFocused && GOTarget.name != lastGoName))
|
||||
{
|
||||
lastGoName = GOTarget.name;
|
||||
Parent.Tab.TabText.text = $"[G] {GOTarget.name}";
|
||||
NameInput.Text = GOTarget.name;
|
||||
}
|
||||
|
||||
if (force || !PathInput.Component.isFocused)
|
||||
{
|
||||
string path = GOTarget.transform.GetTransformPath();
|
||||
if (path != lastPath)
|
||||
{
|
||||
lastPath = path;
|
||||
PathInput.Text = path;
|
||||
}
|
||||
}
|
||||
|
||||
if (force || GOTarget.transform.parent != lastParentState)
|
||||
{
|
||||
lastParentState = GOTarget.transform.parent;
|
||||
ViewParentButton.Component.interactable = lastParentState;
|
||||
if (lastParentState)
|
||||
{
|
||||
ViewParentButton.ButtonText.color = Color.white;
|
||||
ViewParentButton.ButtonText.text = "◄ View Parent";
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewParentButton.ButtonText.color = Color.grey;
|
||||
ViewParentButton.ButtonText.text = "No parent";
|
||||
}
|
||||
}
|
||||
|
||||
if (force || GOTarget.activeSelf != ActiveSelfToggle.isOn)
|
||||
{
|
||||
ActiveSelfToggle.Set(GOTarget.activeSelf, false);
|
||||
ActiveSelfText.color = ActiveSelfToggle.isOn ? Color.green : Color.red;
|
||||
}
|
||||
|
||||
if (force || GOTarget.isStatic != IsStaticToggle.isOn)
|
||||
{
|
||||
IsStaticToggle.Set(GOTarget.isStatic, false);
|
||||
}
|
||||
|
||||
if (force || GOTarget.scene.handle != lastSceneHandle)
|
||||
{
|
||||
lastSceneHandle = GOTarget.scene.handle;
|
||||
SceneInput.Text = GOTarget.scene.IsValid() ? GOTarget.scene.name : "None (Asset/Resource)";
|
||||
}
|
||||
|
||||
if (force || (!TagInput.Component.isFocused && GOTarget.tag != lastTag))
|
||||
{
|
||||
lastTag = GOTarget.tag;
|
||||
TagInput.Text = lastTag;
|
||||
}
|
||||
|
||||
if (force || (GOTarget.layer != lastLayer))
|
||||
{
|
||||
lastLayer = GOTarget.layer;
|
||||
LayerDropdown.value = GOTarget.layer;
|
||||
}
|
||||
|
||||
if (force || ((int)GOTarget.hideFlags != lastFlags))
|
||||
{
|
||||
lastFlags = (int)GOTarget.hideFlags;
|
||||
FlagsDropdown.captionText.text = GOTarget.hideFlags.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnViewParentClicked()
|
||||
{
|
||||
if (this.GOTarget && this.GOTarget.transform.parent)
|
||||
{
|
||||
Parent.ChangeTarget(this.GOTarget.transform.parent.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPathEndEdit(string input)
|
||||
{
|
||||
lastPath = input;
|
||||
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
DoSetParent(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform parentToSet = null;
|
||||
|
||||
if (input.EndsWith("/"))
|
||||
input = input.Remove(input.Length - 1);
|
||||
|
||||
// try the easy way
|
||||
if (GameObject.Find(input) is GameObject found)
|
||||
{
|
||||
parentToSet = found.transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
// look for inactive objects
|
||||
string name = input.Split('/').Last();
|
||||
UnityEngine.Object[] allObjects = RuntimeHelper.FindObjectsOfTypeAll(typeof(GameObject));
|
||||
List<GameObject> shortList = new();
|
||||
foreach (UnityEngine.Object obj in allObjects)
|
||||
if (obj.name == name) shortList.Add(obj.TryCast<GameObject>());
|
||||
foreach (GameObject go in shortList)
|
||||
{
|
||||
string path = go.transform.GetTransformPath(true);
|
||||
if (path.EndsWith("/"))
|
||||
path = path.Remove(path.Length - 1);
|
||||
if (path == input)
|
||||
{
|
||||
parentToSet = go.transform;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parentToSet)
|
||||
DoSetParent(parentToSet);
|
||||
else
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not find any GameObject name or path '{input}'!");
|
||||
UpdateGameObjectInfo(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void DoSetParent(Transform transform)
|
||||
{
|
||||
ExplorerCore.Log($"Setting target's transform parent to: {(transform == null ? "null" : $"'{transform.name}'")}");
|
||||
|
||||
if (GOTarget.GetComponent<RectTransform>())
|
||||
GOTarget.transform.SetParent(transform, false);
|
||||
else
|
||||
GOTarget.transform.parent = transform;
|
||||
|
||||
UpdateGameObjectInfo(false, false);
|
||||
UpdateTransformControlValues(false);
|
||||
}
|
||||
|
||||
private void OnNameEndEdit(string value)
|
||||
{
|
||||
GOTarget.name = value;
|
||||
UpdateGameObjectInfo(false, true);
|
||||
}
|
||||
|
||||
private void OnActiveSelfToggled(bool value)
|
||||
{
|
||||
GOTarget.SetActive(value);
|
||||
UpdateGameObjectInfo(false, true);
|
||||
}
|
||||
|
||||
private void OnTagEndEdit(string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
GOTarget.tag = value;
|
||||
UpdateGameObjectInfo(false, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception setting tag! {ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExploreButtonClicked()
|
||||
{
|
||||
ObjectExplorerPanel panel = UIManager.GetPanel<UI.Panels.ObjectExplorerPanel>(UIManager.Panels.ObjectExplorer);
|
||||
panel.SceneExplorer.JumpToTransform(this.Parent.GOTarget.transform);
|
||||
}
|
||||
|
||||
private void OnLayerDropdownChanged(int value)
|
||||
{
|
||||
GOTarget.layer = value;
|
||||
UpdateGameObjectInfo(false, true);
|
||||
}
|
||||
|
||||
private void OnFlagsDropdownChanged(int value)
|
||||
{
|
||||
try
|
||||
{
|
||||
HideFlags enumVal = hideFlagsValues[FlagsDropdown.options[value].text];
|
||||
GOTarget.hideFlags = enumVal;
|
||||
|
||||
UpdateGameObjectInfo(false, true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception setting hideFlags: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroyClicked()
|
||||
{
|
||||
GameObject.Destroy(this.GOTarget);
|
||||
InspectorManager.ReleaseInspector(Parent);
|
||||
}
|
||||
|
||||
private void OnInstantiateClicked()
|
||||
{
|
||||
GameObject clone = GameObject.Instantiate(this.GOTarget);
|
||||
InspectorManager.Inspect(clone);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Transform Controls
|
||||
|
||||
private enum TransformType { Position, LocalPosition, Rotation, Scale }
|
||||
|
||||
private class TransformControl
|
||||
{
|
||||
public TransformType Type;
|
||||
public InputFieldRef Input;
|
||||
|
||||
public TransformControl(TransformType type, InputFieldRef input)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Input = input;
|
||||
}
|
||||
}
|
||||
|
||||
private class VectorSlider
|
||||
{
|
||||
public int axis;
|
||||
public Slider slider;
|
||||
public TransformControl parentControl;
|
||||
|
||||
public VectorSlider(int axis, Slider slider, TransformControl parentControl)
|
||||
{
|
||||
this.axis = axis;
|
||||
this.slider = slider;
|
||||
this.parentControl = parentControl;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 lastPosValue;
|
||||
private Vector3 lastLocalValue;
|
||||
private Quaternion lastRotValue;
|
||||
private Vector3 lastScaleValue;
|
||||
|
||||
public void UpdateTransformControlValues(bool force)
|
||||
{
|
||||
Transform transform = GOTarget.transform;
|
||||
if (force || (!PositionControl.Input.Component.isFocused && lastPosValue != transform.position))
|
||||
{
|
||||
PositionControl.Input.Text = ParseUtility.ToStringForInput(transform.position, typeof(Vector3));
|
||||
lastPosValue = transform.position;
|
||||
}
|
||||
if (force || (!LocalPositionControl.Input.Component.isFocused && lastLocalValue != transform.localPosition))
|
||||
{
|
||||
LocalPositionControl.Input.Text = ParseUtility.ToStringForInput(transform.localPosition, typeof(Vector3));
|
||||
lastLocalValue = transform.localPosition;
|
||||
}
|
||||
if (force || (!RotationControl.Input.Component.isFocused && lastRotValue != transform.localRotation))
|
||||
{
|
||||
RotationControl.Input.Text = ParseUtility.ToStringForInput(transform.localRotation, typeof(Quaternion));
|
||||
lastRotValue = transform.localRotation;
|
||||
}
|
||||
if (force || (!ScaleControl.Input.Component.isFocused && lastScaleValue != transform.localScale))
|
||||
{
|
||||
ScaleControl.Input.Text = ParseUtility.ToStringForInput(transform.localScale, typeof(Vector3));
|
||||
lastScaleValue = transform.localScale;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTransformInputEndEdit(TransformType type, string input)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TransformType.Position:
|
||||
{
|
||||
if (ParseUtility.TryParse(input, typeof(Vector3), out object boxed, out _))
|
||||
GOTarget.transform.position = (Vector3)boxed;
|
||||
}
|
||||
break;
|
||||
case TransformType.LocalPosition:
|
||||
{
|
||||
if (ParseUtility.TryParse(input, typeof(Vector3), out object boxed, out _))
|
||||
GOTarget.transform.localPosition = (Vector3)boxed;
|
||||
}
|
||||
break;
|
||||
case TransformType.Rotation:
|
||||
{
|
||||
if (ParseUtility.TryParse(input, typeof(Quaternion), out object boxed, out _))
|
||||
GOTarget.transform.localRotation = (Quaternion)boxed;
|
||||
}
|
||||
break;
|
||||
case TransformType.Scale:
|
||||
{
|
||||
if (ParseUtility.TryParse(input, typeof(Vector3), out object boxed, out _))
|
||||
GOTarget.transform.localScale = (Vector3)boxed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateTransformControlValues(true);
|
||||
}
|
||||
|
||||
private void OnVectorSliderChanged(VectorSlider slider, float value)
|
||||
{
|
||||
if (value == 0f)
|
||||
{
|
||||
currentSlidingVectorControl = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentSlidingVectorControl = slider;
|
||||
currentVectorValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateVectorSlider()
|
||||
{
|
||||
if (currentSlidingVectorControl == null)
|
||||
return;
|
||||
|
||||
if (!InputManager.GetMouseButton(0))
|
||||
{
|
||||
currentSlidingVectorControl.slider.value = 0f;
|
||||
currentSlidingVectorControl = null;
|
||||
currentVectorValue = 0f;
|
||||
return;
|
||||
}
|
||||
|
||||
Transform transform = GOTarget.transform;
|
||||
|
||||
Vector3 vector = Vector2.zero;
|
||||
switch (currentSlidingVectorControl.parentControl.Type)
|
||||
{
|
||||
case TransformType.Position:
|
||||
vector = transform.position; break;
|
||||
case TransformType.LocalPosition:
|
||||
vector = transform.localPosition; break;
|
||||
case TransformType.Rotation:
|
||||
vector = transform.eulerAngles; break;
|
||||
case TransformType.Scale:
|
||||
vector = transform.localScale; break;
|
||||
}
|
||||
|
||||
// apply vector value change
|
||||
switch (currentSlidingVectorControl.axis)
|
||||
{
|
||||
case 0:
|
||||
vector.x += currentVectorValue; break;
|
||||
case 1:
|
||||
vector.y += currentVectorValue; break;
|
||||
case 2:
|
||||
vector.z += currentVectorValue; break;
|
||||
}
|
||||
|
||||
// set vector back to transform
|
||||
switch (currentSlidingVectorControl.parentControl.Type)
|
||||
{
|
||||
case TransformType.Position:
|
||||
transform.position = vector; break;
|
||||
case TransformType.LocalPosition:
|
||||
transform.localPosition = vector; break;
|
||||
case TransformType.Rotation:
|
||||
transform.eulerAngles = vector; break;
|
||||
case TransformType.Scale:
|
||||
transform.localScale = vector; break;
|
||||
}
|
||||
|
||||
UpdateTransformControlValues(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region GO Controls UI Construction
|
||||
|
||||
private void ConstructTopInfo()
|
||||
{
|
||||
GameObject topInfoHolder = UIFactory.CreateVerticalGroup(Parent.Content, "TopInfoHolder", false, false, true, true, 3,
|
||||
new Vector4(3, 3, 3, 3), new Color(0.1f, 0.1f, 0.1f), TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(topInfoHolder, minHeight: 100, flexibleWidth: 9999);
|
||||
topInfoHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
// first row (parent, path)
|
||||
|
||||
GameObject firstRow = UIFactory.CreateUIObject("ParentRow", topInfoHolder);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(firstRow, false, false, true, true, 5, 0, 0, 0, 0, default);
|
||||
UIFactory.SetLayoutElement(firstRow, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
ViewParentButton = UIFactory.CreateButton(firstRow, "ViewParentButton", "◄ View Parent", new Color(0.2f, 0.2f, 0.2f));
|
||||
ViewParentButton.ButtonText.fontSize = 13;
|
||||
UIFactory.SetLayoutElement(ViewParentButton.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||
ViewParentButton.OnClick += OnViewParentClicked;
|
||||
|
||||
this.PathInput = UIFactory.CreateInputField(firstRow, "PathInput", "...");
|
||||
PathInput.Component.textComponent.color = Color.grey;
|
||||
PathInput.Component.textComponent.fontSize = 14;
|
||||
UIFactory.SetLayoutElement(PathInput.UIRoot, minHeight: 25, minWidth: 100, flexibleWidth: 9999);
|
||||
PathInput.Component.lineType = InputField.LineType.MultiLineSubmit;
|
||||
|
||||
ButtonRef copyButton = UIFactory.CreateButton(firstRow, "CopyButton", "Copy to Clipboard", new Color(0.2f, 0.2f, 0.2f, 1));
|
||||
copyButton.ButtonText.color = Color.yellow;
|
||||
UIFactory.SetLayoutElement(copyButton.Component.gameObject, minHeight: 25, minWidth: 120);
|
||||
copyButton.OnClick += OnCopyClicked;
|
||||
|
||||
//var pathApplyBtn = UIFactory.CreateButton(firstRow, "PathButton", "Set Parent Path", new Color(0.2f, 0.2f, 0.2f));
|
||||
//UIFactory.SetLayoutElement(pathApplyBtn.Component.gameObject, minHeight: 25, minWidth: 120);
|
||||
//pathApplyBtn.OnClick += () => { OnPathEndEdit(PathInput.Text); };
|
||||
|
||||
PathInput.Component.GetOnEndEdit().AddListener((string val) => { OnPathEndEdit(val); });
|
||||
|
||||
// Title and update row
|
||||
|
||||
GameObject titleRow = UIFactory.CreateUIObject("TitleRow", topInfoHolder);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(titleRow, false, false, true, true, 5);
|
||||
|
||||
Text titleLabel = UIFactory.CreateLabel(titleRow, "Title", SignatureHighlighter.Parse(typeof(GameObject), false),
|
||||
TextAnchor.MiddleLeft, fontSize: 17);
|
||||
UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 30, minWidth: 100);
|
||||
|
||||
// name
|
||||
|
||||
NameInput = UIFactory.CreateInputField(titleRow, "NameInput", "untitled");
|
||||
UIFactory.SetLayoutElement(NameInput.Component.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999);
|
||||
NameInput.Component.textComponent.fontSize = 15;
|
||||
NameInput.Component.GetOnEndEdit().AddListener((string val) => { OnNameEndEdit(val); });
|
||||
|
||||
// second row (toggles, instanceID, tag, buttons)
|
||||
|
||||
GameObject secondRow = UIFactory.CreateUIObject("ParentRow", topInfoHolder);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(secondRow, false, false, true, true, 5, 0, 0, 0, 0, default);
|
||||
UIFactory.SetLayoutElement(secondRow, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
// activeSelf
|
||||
GameObject activeToggleObj = UIFactory.CreateToggle(secondRow, "ActiveSelf", out ActiveSelfToggle, out ActiveSelfText);
|
||||
UIFactory.SetLayoutElement(activeToggleObj, minHeight: 25, minWidth: 100);
|
||||
ActiveSelfText.text = "ActiveSelf";
|
||||
ActiveSelfToggle.onValueChanged.AddListener(OnActiveSelfToggled);
|
||||
|
||||
// isStatic
|
||||
GameObject isStaticObj = UIFactory.CreateToggle(secondRow, "IsStatic", out IsStaticToggle, out Text staticText);
|
||||
UIFactory.SetLayoutElement(isStaticObj, minHeight: 25, minWidth: 80);
|
||||
staticText.text = "IsStatic";
|
||||
staticText.color = Color.grey;
|
||||
IsStaticToggle.interactable = false;
|
||||
|
||||
// InstanceID
|
||||
Text instanceIdLabel = UIFactory.CreateLabel(secondRow, "InstanceIDLabel", "Instance ID:", TextAnchor.MiddleRight, Color.grey);
|
||||
UIFactory.SetLayoutElement(instanceIdLabel.gameObject, minHeight: 25, minWidth: 90);
|
||||
|
||||
InstanceIDInput = UIFactory.CreateInputField(secondRow, "InstanceIDInput", "error");
|
||||
UIFactory.SetLayoutElement(InstanceIDInput.Component.gameObject, minHeight: 25, minWidth: 110);
|
||||
InstanceIDInput.Component.textComponent.color = Color.grey;
|
||||
InstanceIDInput.Component.readOnly = true;
|
||||
|
||||
//Tag
|
||||
Text tagLabel = UIFactory.CreateLabel(secondRow, "TagLabel", "Tag:", TextAnchor.MiddleRight, Color.grey);
|
||||
UIFactory.SetLayoutElement(tagLabel.gameObject, minHeight: 25, minWidth: 40);
|
||||
|
||||
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.GetOnEndEdit().AddListener((string val) => { OnTagEndEdit(val); });
|
||||
|
||||
// Instantiate
|
||||
ButtonRef instantiateBtn = UIFactory.CreateButton(secondRow, "InstantiateBtn", "Instantiate", new Color(0.2f, 0.2f, 0.2f));
|
||||
UIFactory.SetLayoutElement(instantiateBtn.Component.gameObject, minHeight: 25, minWidth: 120);
|
||||
instantiateBtn.OnClick += OnInstantiateClicked;
|
||||
|
||||
// Destroy
|
||||
ButtonRef destroyBtn = UIFactory.CreateButton(secondRow, "DestroyBtn", "Destroy", new Color(0.3f, 0.2f, 0.2f));
|
||||
UIFactory.SetLayoutElement(destroyBtn.Component.gameObject, minHeight: 25, minWidth: 80);
|
||||
destroyBtn.OnClick += OnDestroyClicked;
|
||||
|
||||
// third row (scene, layer, flags)
|
||||
|
||||
GameObject thirdrow = UIFactory.CreateUIObject("ParentRow", topInfoHolder);
|
||||
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
|
||||
ButtonRef 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
|
||||
Text sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey);
|
||||
UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||
|
||||
SceneInput = UIFactory.CreateInputField(thirdrow, "SceneInput", "untitled");
|
||||
UIFactory.SetLayoutElement(SceneInput.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 999);
|
||||
SceneInput.Component.readOnly = true;
|
||||
SceneInput.Component.textComponent.color = new Color(0.7f, 0.7f, 0.7f);
|
||||
|
||||
// Layer
|
||||
Text layerLabel = UIFactory.CreateLabel(thirdrow, "LayerLabel", "Layer:", TextAnchor.MiddleLeft, Color.grey);
|
||||
UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||
|
||||
GameObject layerDrop = UIFactory.CreateDropdown(thirdrow, "LayerDropdown", out LayerDropdown, "0", 14, OnLayerDropdownChanged);
|
||||
UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 110, flexibleWidth: 999);
|
||||
LayerDropdown.captionText.color = SignatureHighlighter.EnumGreen;
|
||||
if (layerToNames == null)
|
||||
GetLayerNames();
|
||||
foreach (string name in layerToNames)
|
||||
LayerDropdown.options.Add(new Dropdown.OptionData(name));
|
||||
LayerDropdown.value = 0;
|
||||
LayerDropdown.RefreshShownValue();
|
||||
|
||||
// Flags
|
||||
Text flagsLabel = UIFactory.CreateLabel(thirdrow, "FlagsLabel", "Flags:", TextAnchor.MiddleRight, Color.grey);
|
||||
UIFactory.SetLayoutElement(flagsLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||
|
||||
GameObject flagsDrop = UIFactory.CreateDropdown(thirdrow, "FlagsDropdown", out FlagsDropdown, "None", 14, OnFlagsDropdownChanged);
|
||||
FlagsDropdown.captionText.color = SignatureHighlighter.EnumGreen;
|
||||
UIFactory.SetLayoutElement(flagsDrop, minHeight: 25, minWidth: 135, flexibleWidth: 999);
|
||||
if (hideFlagsValues == null)
|
||||
GetHideFlagNames();
|
||||
foreach (string name in hideFlagsValues.Keys)
|
||||
FlagsDropdown.options.Add(new Dropdown.OptionData(name));
|
||||
FlagsDropdown.value = 0;
|
||||
FlagsDropdown.RefreshShownValue();
|
||||
}
|
||||
|
||||
private static List<string> layerToNames;
|
||||
|
||||
private static void GetLayerNames()
|
||||
{
|
||||
layerToNames = new List<string>();
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
string name = RuntimeHelper.LayerToName(i);
|
||||
if (string.IsNullOrEmpty(name))
|
||||
name = i.ToString();
|
||||
layerToNames.Add(name);
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, HideFlags> hideFlagsValues;
|
||||
|
||||
private static void GetHideFlagNames()
|
||||
{
|
||||
hideFlagsValues = new Dictionary<string, HideFlags>();
|
||||
|
||||
Array names = Enum.GetValues(typeof(HideFlags));
|
||||
foreach (HideFlags value in names)
|
||||
{
|
||||
hideFlagsValues.Add(value.ToString(), value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Transform Controls UI Construction
|
||||
|
||||
private void ConstructTransformControls()
|
||||
{
|
||||
GameObject transformGroup = UIFactory.CreateVerticalGroup(Parent.Content, "TransformControls", false, false, true, true, 2,
|
||||
new Vector4(2, 2, 0, 0), new Color(0.1f, 0.1f, 0.1f));
|
||||
UIFactory.SetLayoutElement(transformGroup, minHeight: 100, flexibleWidth: 9999);
|
||||
//transformGroup.SetActive(false);
|
||||
//var groupRect = transformGroup.GetComponent<RectTransform>();
|
||||
//groupRect.anchorMin = new Vector2(0, 1);
|
||||
//groupRect.anchorMax = new Vector2(1, 1);
|
||||
//groupRect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, 100);
|
||||
|
||||
PositionControl = AddTransformRow(transformGroup, "Position:", TransformType.Position);
|
||||
LocalPositionControl = AddTransformRow(transformGroup, "Local Position:", TransformType.LocalPosition);
|
||||
RotationControl = AddTransformRow(transformGroup, "Rotation:", TransformType.Rotation);
|
||||
ScaleControl = AddTransformRow(transformGroup, "Scale:", TransformType.Scale);
|
||||
}
|
||||
|
||||
private TransformControl AddTransformRow(GameObject transformGroup, string title, TransformType type)
|
||||
{
|
||||
GameObject rowObj = UIFactory.CreateUIObject("Row_" + title, transformGroup);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(rowObj, false, false, true, true, 5, 0, 0, 0, 0, default);
|
||||
UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
Text titleLabel = UIFactory.CreateLabel(rowObj, "PositionLabel", title, TextAnchor.MiddleRight, Color.grey);
|
||||
UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 25, minWidth: 110);
|
||||
|
||||
InputFieldRef inputField = UIFactory.CreateInputField(rowObj, "InputField", "...");
|
||||
UIFactory.SetLayoutElement(inputField.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
|
||||
|
||||
inputField.Component.GetOnEndEdit().AddListener((string value) => { OnTransformInputEndEdit(type, value); });
|
||||
|
||||
TransformControl control = new(type, inputField);
|
||||
|
||||
AddVectorAxisSlider(rowObj, "X", 0, control);
|
||||
AddVectorAxisSlider(rowObj, "Y", 1, control);
|
||||
AddVectorAxisSlider(rowObj, "Z", 2, control);
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
private VectorSlider AddVectorAxisSlider(GameObject parent, string title, int axis, TransformControl control)
|
||||
{
|
||||
Text label = UIFactory.CreateLabel(parent, "Label_" + title, title + ":", TextAnchor.MiddleRight, Color.grey);
|
||||
UIFactory.SetLayoutElement(label.gameObject, minHeight: 25, minWidth: 30);
|
||||
|
||||
GameObject sliderObj = UIFactory.CreateSlider(parent, "Slider_" + title, out Slider slider);
|
||||
UIFactory.SetLayoutElement(sliderObj, minHeight: 25, minWidth: 120, flexibleWidth: 0);
|
||||
slider.m_FillImage.color = Color.clear;
|
||||
|
||||
slider.minValue = -1;
|
||||
slider.maxValue = 1;
|
||||
VectorSlider sliderControl = new(axis, slider, control);
|
||||
|
||||
slider.onValueChanged.AddListener((float val) =>
|
||||
{
|
||||
OnVectorSliderChanged(sliderControl, val);
|
||||
});
|
||||
|
||||
return sliderControl;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib.UI.ObjectPool;
|
||||
|
||||
namespace UnityExplorer.Inspectors
|
||||
@@ -9,6 +7,7 @@ namespace UnityExplorer.Inspectors
|
||||
{
|
||||
public bool IsActive { get; internal set; }
|
||||
public object Target { get; set; }
|
||||
public Type TargetType { get; protected set; }
|
||||
|
||||
public InspectorTab Tab { get; internal set; }
|
||||
|
||||
@@ -24,6 +23,8 @@ namespace UnityExplorer.Inspectors
|
||||
public virtual void OnBorrowedFromPool(object target)
|
||||
{
|
||||
this.Target = target;
|
||||
this.TargetType = target is Type type ? type : target.GetActualType();
|
||||
|
||||
Tab = Pool<InspectorTab>.Borrow();
|
||||
Tab.UIRoot.transform.SetParent(InspectorPanel.Instance.NavbarHolder.transform, false);
|
||||
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI.ObjectPool;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
@@ -23,7 +17,7 @@ namespace UnityExplorer
|
||||
|
||||
public static event Action OnInspectedTabsChanged;
|
||||
|
||||
public static void Inspect(object obj, CacheObjectBase sourceCache = null)
|
||||
public static void Inspect(object obj, CacheObjectBase parent = null)
|
||||
{
|
||||
if (obj.IsNullOrDestroyed())
|
||||
return;
|
||||
@@ -36,19 +30,34 @@ namespace UnityExplorer
|
||||
if (obj is GameObject)
|
||||
CreateInspector<GameObjectInspector>(obj);
|
||||
else
|
||||
CreateInspector<ReflectionInspector>(obj, false, sourceCache);
|
||||
CreateInspector<ReflectionInspector>(obj, false, parent);
|
||||
}
|
||||
|
||||
public static void Inspect(Type type)
|
||||
{
|
||||
if (TryFocusActiveInspector(type))
|
||||
return;
|
||||
|
||||
CreateInspector<ReflectionInspector>(type, true);
|
||||
}
|
||||
|
||||
private static bool TryFocusActiveInspector(object target)
|
||||
static bool TryFocusActiveInspector(object target)
|
||||
{
|
||||
foreach (InspectorBase inspector in Inspectors)
|
||||
{
|
||||
if (inspector.Target.ReferenceEqual(target))
|
||||
bool shouldFocus = false;
|
||||
|
||||
if (target is Type targetAsType)
|
||||
{
|
||||
if (inspector.TargetType.FullName == targetAsType.FullName)
|
||||
shouldFocus = true;
|
||||
}
|
||||
else if(inspector.Target.ReferenceEqual(target))
|
||||
{
|
||||
shouldFocus = true;
|
||||
}
|
||||
|
||||
if (shouldFocus)
|
||||
{
|
||||
UIManager.SetPanelActive(UIManager.Panels.Inspector, true);
|
||||
SetInspectorActive(inspector);
|
||||
@@ -76,7 +85,7 @@ namespace UnityExplorer
|
||||
}
|
||||
}
|
||||
|
||||
internal static void CloseAllTabs()
|
||||
public static void CloseAllTabs()
|
||||
{
|
||||
if (Inspectors.Any())
|
||||
{
|
||||
@@ -89,18 +98,17 @@ namespace UnityExplorer
|
||||
UIManager.SetPanelActive(UIManager.Panels.Inspector, false);
|
||||
}
|
||||
|
||||
private static void CreateInspector<T>(object target, bool staticReflection = false,
|
||||
CacheObjectBase parentObject = null) where T : InspectorBase
|
||||
static void CreateInspector<T>(object target, bool staticReflection = false, CacheObjectBase parent = null) where T : InspectorBase
|
||||
{
|
||||
T inspector = Pool<T>.Borrow();
|
||||
Inspectors.Add(inspector);
|
||||
inspector.Target = target;
|
||||
|
||||
if (parentObject != null && parentObject.CanWrite)
|
||||
if (parent != null && parent.CanWrite)
|
||||
{
|
||||
// only set parent cache object if we are inspecting a struct, otherwise there is no point.
|
||||
if (target.GetType().IsValueType && inspector is ReflectionInspector ri)
|
||||
ri.ParentCacheObject = parentObject;
|
||||
ri.ParentCacheObject = parent;
|
||||
}
|
||||
|
||||
UIManager.SetPanelActive(UIManager.Panels.Inspector, true);
|
||||
@@ -115,7 +123,7 @@ namespace UnityExplorer
|
||||
OnInspectedTabsChanged?.Invoke();
|
||||
}
|
||||
|
||||
internal static void ReleaseInspector<T>(T inspector) where T : InspectorBase
|
||||
public static void ReleaseInspector<T>(T inspector) where T : InspectorBase
|
||||
{
|
||||
if (lastActiveInspector == inspector)
|
||||
lastActiveInspector = null;
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.ObjectPool;
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Config;
|
||||
using UnityExplorer.Config;
|
||||
using UnityExplorer.Inspectors.MouseInspectors;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib.Input;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Panels;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
@@ -17,7 +14,7 @@ namespace UnityExplorer.Inspectors
|
||||
UI
|
||||
}
|
||||
|
||||
public class MouseInspector : UEPanel
|
||||
public class MouseInspector : PanelBase
|
||||
{
|
||||
public static MouseInspector Instance { get; private set; }
|
||||
|
||||
@@ -38,19 +35,15 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
// UIPanel
|
||||
internal static readonly string UIBaseGUID = $"{ExplorerCore.GUID}.MouseInspector";
|
||||
private UIBase inspectorUIBase;
|
||||
internal static UIBase inspectorUIBase;
|
||||
|
||||
public override string Name => "Inspect Under Mouse";
|
||||
public override UIManager.Panels PanelType => UIManager.Panels.MouseInspector;
|
||||
public override int MinWidth => -1;
|
||||
public override int MinHeight => -1;
|
||||
public override Vector2 DefaultAnchorMin => Vector2.zero;
|
||||
public override Vector2 DefaultAnchorMax => Vector2.zero;
|
||||
|
||||
public override bool CanDragAndResize => false;
|
||||
public override bool NavButtonWanted => false;
|
||||
public override bool ShouldSaveActiveState => false;
|
||||
public override bool ShowByDefault => false;
|
||||
|
||||
internal Text objNameLabel;
|
||||
internal Text objPathLabel;
|
||||
@@ -117,17 +110,11 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
public bool TryUpdate()
|
||||
{
|
||||
if (ConfigManager.World_MouseInspect_Keybind.Value != KeyCode.None)
|
||||
{
|
||||
if (InputManager.GetKeyDown(ConfigManager.World_MouseInspect_Keybind.Value))
|
||||
Instance.StartInspect(MouseInspectMode.World);
|
||||
}
|
||||
if (InputManager.GetKeyDown(ConfigManager.World_MouseInspect_Keybind.Value))
|
||||
Instance.StartInspect(MouseInspectMode.World);
|
||||
|
||||
if (ConfigManager.World_MouseInspect_Keybind.Value != KeyCode.None)
|
||||
{
|
||||
if (InputManager.GetKeyDown(ConfigManager.World_MouseInspect_Keybind.Value))
|
||||
Instance.StartInspect(MouseInspectMode.World);
|
||||
}
|
||||
if (InputManager.GetKeyDown(ConfigManager.UI_MouseInspect_Keybind.Value))
|
||||
Instance.StartInspect(MouseInspectMode.UI);
|
||||
|
||||
if (Inspecting)
|
||||
UpdateInspect();
|
||||
@@ -225,11 +212,10 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
UIRoot.SetActive(false);
|
||||
|
||||
// Create a new canvas for this panel to live on.
|
||||
// It needs to always be shown on the main display, other panels can move displays.
|
||||
|
||||
inspectorUIBase = UniversalUI.RegisterUI(UIBaseGUID, null);
|
||||
UIRoot.transform.SetParent(inspectorUIBase.RootObject.transform);
|
||||
//// Create a new canvas for this panel to live on.
|
||||
//// It needs to always be shown on the main display, other panels can move displays.
|
||||
//
|
||||
//UIRoot.transform.SetParent(inspectorUIBase.RootObject.transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.Inspectors.MouseInspectors
|
||||
namespace UnityExplorer.Inspectors.MouseInspectors
|
||||
{
|
||||
public abstract class MouseInspectorBase
|
||||
{
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UniverseLib;
|
||||
|
||||
namespace UnityExplorer.Inspectors.MouseInspectors
|
||||
{
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.Inspectors.MouseInspectors
|
||||
namespace UnityExplorer.Inspectors.MouseInspectors
|
||||
{
|
||||
public class WorldInspector : MouseInspectorBase
|
||||
{
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection.Emit;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.Config;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.ObjectPool;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.Inspectors
|
||||
{
|
||||
@@ -33,54 +28,53 @@ namespace UnityExplorer.Inspectors
|
||||
public class ReflectionInspector : InspectorBase, ICellPoolDataSource<CacheMemberCell>, ICacheObjectController
|
||||
{
|
||||
public CacheObjectBase ParentCacheObject { get; set; }
|
||||
public Type TargetType { get; private set; }
|
||||
public bool StaticOnly { get; internal set; }
|
||||
public bool CanWrite => true;
|
||||
|
||||
public bool AutoUpdateWanted => autoUpdateToggle.isOn;
|
||||
|
||||
private List<CacheMember> members = new();
|
||||
private readonly List<CacheMember> filteredMembers = new();
|
||||
List<CacheMember> members = new();
|
||||
readonly List<CacheMember> filteredMembers = new();
|
||||
|
||||
private BindingFlags scopeFlagsFilter;
|
||||
private string nameFilter;
|
||||
|
||||
private MemberFilter MemberFilter = MemberFilter.All;
|
||||
string nameFilter;
|
||||
BindingFlags scopeFlagsFilter;
|
||||
MemberFilter memberFilter = MemberFilter.All;
|
||||
|
||||
// Updating
|
||||
|
||||
private bool refreshWanted;
|
||||
private string lastNameFilter;
|
||||
private BindingFlags lastFlagsFilter;
|
||||
private MemberFilter lastMemberFilter = MemberFilter.All;
|
||||
private float timeOfLastAutoUpdate;
|
||||
bool refreshWanted;
|
||||
string lastNameFilter;
|
||||
BindingFlags lastFlagsFilter;
|
||||
MemberFilter lastMemberFilter = MemberFilter.All;
|
||||
float timeOfLastAutoUpdate;
|
||||
|
||||
// UI
|
||||
|
||||
internal GameObject mainContentHolder;
|
||||
private static int LeftGroupWidth { get; set; }
|
||||
private static int RightGroupWidth { get; set; }
|
||||
static int LeftGroupWidth { get; set; }
|
||||
static int RightGroupWidth { get; set; }
|
||||
|
||||
static readonly Color disabledButtonColor = new(0.24f, 0.24f, 0.24f);
|
||||
static readonly Color enabledButtonColor = new(0.2f, 0.27f, 0.2f);
|
||||
|
||||
public GameObject ContentRoot { get; private set; }
|
||||
public ScrollPool<CacheMemberCell> MemberScrollPool { get; private set; }
|
||||
public int ItemCount => filteredMembers.Count;
|
||||
public UnityObjectWidget UnityWidget { get; private set; }
|
||||
public string TabButtonText { get; set; }
|
||||
|
||||
public UnityObjectWidget UnityWidget;
|
||||
InputFieldRef hiddenNameText;
|
||||
Text nameText;
|
||||
Text assemblyText;
|
||||
Toggle autoUpdateToggle;
|
||||
|
||||
public InputFieldRef HiddenNameText;
|
||||
public Text NameText;
|
||||
public Text AssemblyText;
|
||||
private Toggle autoUpdateToggle;
|
||||
ButtonRef dnSpyButton;
|
||||
|
||||
internal string currentBaseTabText;
|
||||
ButtonRef makeGenericButton;
|
||||
GenericConstructorWidget genericConstructor;
|
||||
|
||||
private readonly Dictionary<BindingFlags, ButtonRef> scopeFilterButtons = new();
|
||||
private readonly List<Toggle> memberTypeToggles = new();
|
||||
private InputFieldRef filterInputField;
|
||||
|
||||
// const
|
||||
|
||||
private readonly Color disabledButtonColor = new(0.24f, 0.24f, 0.24f);
|
||||
private readonly Color enabledButtonColor = new(0.2f, 0.27f, 0.2f);
|
||||
InputFieldRef filterInputField;
|
||||
readonly List<Toggle> memberTypeToggles = new();
|
||||
readonly Dictionary<BindingFlags, ButtonRef> scopeFilterButtons = new();
|
||||
|
||||
// Setup
|
||||
|
||||
@@ -125,6 +119,8 @@ namespace UnityExplorer.Inspectors
|
||||
this.UnityWidget = null;
|
||||
}
|
||||
|
||||
genericConstructor?.Cancel();
|
||||
|
||||
base.OnReturnToPool();
|
||||
}
|
||||
|
||||
@@ -138,6 +134,8 @@ namespace UnityExplorer.Inspectors
|
||||
Target = null;
|
||||
TargetType = target as Type;
|
||||
prefix = "[S]";
|
||||
|
||||
makeGenericButton.GameObject.SetActive(TargetType.IsGenericTypeDefinition);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -146,17 +144,23 @@ namespace UnityExplorer.Inspectors
|
||||
}
|
||||
|
||||
// Setup main labels and tab text
|
||||
currentBaseTabText = $"{prefix} {SignatureHighlighter.Parse(TargetType, false)}";
|
||||
Tab.TabText.text = currentBaseTabText;
|
||||
NameText.text = SignatureHighlighter.Parse(TargetType, true);
|
||||
HiddenNameText.Text = SignatureHighlighter.RemoveHighlighting(NameText.text);
|
||||
TabButtonText = $"{prefix} {SignatureHighlighter.Parse(TargetType, false)}";
|
||||
Tab.TabText.text = TabButtonText;
|
||||
nameText.text = SignatureHighlighter.Parse(TargetType, true);
|
||||
hiddenNameText.Text = SignatureHighlighter.RemoveHighlighting(nameText.text);
|
||||
|
||||
string asmText;
|
||||
if (TargetType.Assembly is AssemblyBuilder || string.IsNullOrEmpty(TargetType.Assembly.Location))
|
||||
{
|
||||
asmText = $"{TargetType.Assembly.GetName().Name} <color=grey><i>(in memory)</i></color>";
|
||||
dnSpyButton.GameObject.SetActive(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
asmText = Path.GetFileName(TargetType.Assembly.Location);
|
||||
AssemblyText.text = $"<color=grey>Assembly:</color> {asmText}";
|
||||
dnSpyButton.GameObject.SetActive(true);
|
||||
}
|
||||
assemblyText.text = $"<color=grey>Assembly:</color> {asmText}";
|
||||
|
||||
// Unity object helper widget
|
||||
|
||||
@@ -195,11 +199,11 @@ namespace UnityExplorer.Inspectors
|
||||
}
|
||||
|
||||
// check filter changes or force-refresh
|
||||
if (refreshWanted || nameFilter != lastNameFilter || scopeFlagsFilter != lastFlagsFilter || lastMemberFilter != MemberFilter)
|
||||
if (refreshWanted || nameFilter != lastNameFilter || scopeFlagsFilter != lastFlagsFilter || lastMemberFilter != memberFilter)
|
||||
{
|
||||
lastNameFilter = nameFilter;
|
||||
lastFlagsFilter = scopeFlagsFilter;
|
||||
lastMemberFilter = MemberFilter;
|
||||
lastMemberFilter = memberFilter;
|
||||
|
||||
FilterMembers();
|
||||
MemberScrollPool.Refresh(true, true);
|
||||
@@ -219,17 +223,8 @@ namespace UnityExplorer.Inspectors
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateClicked()
|
||||
{
|
||||
UpdateDisplayedMembers();
|
||||
}
|
||||
|
||||
// Filtering
|
||||
|
||||
public void SetFilter(string name) => SetFilter(name, scopeFlagsFilter);
|
||||
|
||||
public void SetFilter(BindingFlags flags) => SetFilter(nameFilter, flags);
|
||||
|
||||
public void SetFilter(string name, BindingFlags flags)
|
||||
{
|
||||
this.nameFilter = name;
|
||||
@@ -245,15 +240,7 @@ namespace UnityExplorer.Inspectors
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMemberTypeToggled(MemberFilter flag, bool val)
|
||||
{
|
||||
if (!val)
|
||||
MemberFilter &= ~flag;
|
||||
else
|
||||
MemberFilter |= flag;
|
||||
}
|
||||
|
||||
private void FilterMembers()
|
||||
void FilterMembers()
|
||||
{
|
||||
filteredMembers.Clear();
|
||||
|
||||
@@ -268,10 +255,10 @@ namespace UnityExplorer.Inspectors
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((member is CacheMethod && !MemberFilter.HasFlag(MemberFilter.Method))
|
||||
|| (member is CacheField && !MemberFilter.HasFlag(MemberFilter.Field))
|
||||
|| (member is CacheProperty && !MemberFilter.HasFlag(MemberFilter.Property))
|
||||
|| (member is CacheConstructor && !MemberFilter.HasFlag(MemberFilter.Constructor)))
|
||||
if ((member is CacheMethod && !memberFilter.HasFlag(MemberFilter.Method))
|
||||
|| (member is CacheField && !memberFilter.HasFlag(MemberFilter.Field))
|
||||
|| (member is CacheProperty && !memberFilter.HasFlag(MemberFilter.Property))
|
||||
|| (member is CacheConstructor && !memberFilter.HasFlag(MemberFilter.Constructor)))
|
||||
continue;
|
||||
|
||||
if (!string.IsNullOrEmpty(nameFilter) && !member.NameForFiltering.ContainsIgnoreCase(nameFilter))
|
||||
@@ -281,7 +268,7 @@ namespace UnityExplorer.Inspectors
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDisplayedMembers()
|
||||
void UpdateDisplayedMembers()
|
||||
{
|
||||
bool shouldRefresh = false;
|
||||
foreach (CacheMemberCell cell in MemberScrollPool.CellPool)
|
||||
@@ -320,13 +307,13 @@ namespace UnityExplorer.Inspectors
|
||||
SetCellLayout(cell);
|
||||
}
|
||||
|
||||
private void CalculateLayouts()
|
||||
void CalculateLayouts()
|
||||
{
|
||||
LeftGroupWidth = (int)Math.Max(200, (0.4f * InspectorManager.PanelWidth) - 5);
|
||||
RightGroupWidth = (int)Math.Max(200, InspectorManager.PanelWidth - LeftGroupWidth - 65);
|
||||
}
|
||||
|
||||
private void SetCellLayout(CacheObjectCell cell)
|
||||
void SetCellLayout(CacheObjectCell cell)
|
||||
{
|
||||
cell.NameLayout.minWidth = LeftGroupWidth;
|
||||
cell.RightGroupLayout.minWidth = RightGroupWidth;
|
||||
@@ -335,11 +322,85 @@ namespace UnityExplorer.Inspectors
|
||||
cell.Occupant.IValue.SetLayout();
|
||||
}
|
||||
|
||||
private void OnCopyClicked()
|
||||
// UI listeners
|
||||
|
||||
void OnUpdateClicked()
|
||||
{
|
||||
UpdateDisplayedMembers();
|
||||
}
|
||||
|
||||
public void OnSetNameFilter(string name)
|
||||
{
|
||||
SetFilter(name, scopeFlagsFilter);
|
||||
}
|
||||
|
||||
public void OnSetFlags(BindingFlags flags)
|
||||
{
|
||||
SetFilter(nameFilter, flags);
|
||||
}
|
||||
|
||||
void OnMemberTypeToggled(MemberFilter flag, bool val)
|
||||
{
|
||||
if (!val)
|
||||
memberFilter &= ~flag;
|
||||
else
|
||||
memberFilter |= flag;
|
||||
}
|
||||
|
||||
void OnCopyClicked()
|
||||
{
|
||||
ClipboardPanel.Copy(this.Target ?? this.TargetType);
|
||||
}
|
||||
|
||||
void OnDnSpyButtonClicked()
|
||||
{
|
||||
string path = ConfigManager.DnSpy_Path.Value;
|
||||
if (File.Exists(path) && path.EndsWith("dnspy.exe", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Type type = TargetType;
|
||||
// if constructed generic type, use the generic type definition
|
||||
if (type.IsGenericType && !type.IsGenericTypeDefinition)
|
||||
type = type.GetGenericTypeDefinition();
|
||||
|
||||
string args = $"\"{type.Assembly.Location}\" --select T:{type.FullName}";
|
||||
Process.Start(path, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
Notification.ShowMessage($"Please set a valid dnSpy path in UnityExplorer Settings.");
|
||||
}
|
||||
}
|
||||
|
||||
void OnMakeGenericClicked()
|
||||
{
|
||||
ContentRoot.SetActive(false);
|
||||
|
||||
if (genericConstructor == null)
|
||||
{
|
||||
genericConstructor = new();
|
||||
genericConstructor.ConstructUI(UIRoot);
|
||||
}
|
||||
|
||||
genericConstructor.UIRoot.SetActive(true);
|
||||
genericConstructor.Show(OnGenericSubmit, OnGenericCancel, TargetType);
|
||||
}
|
||||
|
||||
void OnGenericSubmit(Type[] args)
|
||||
{
|
||||
ContentRoot.SetActive(true);
|
||||
genericConstructor.UIRoot.SetActive(false);
|
||||
|
||||
Type newType = TargetType.MakeGenericType(args);
|
||||
InspectorManager.Inspect(newType);
|
||||
//InspectorManager.ReleaseInspector(this);
|
||||
}
|
||||
|
||||
void OnGenericCancel()
|
||||
{
|
||||
ContentRoot.SetActive(true);
|
||||
genericConstructor.UIRoot.SetActive(false);
|
||||
}
|
||||
|
||||
// UI Construction
|
||||
|
||||
public override GameObject CreateContent(GameObject parent)
|
||||
@@ -349,51 +410,68 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
// Class name, assembly
|
||||
|
||||
GameObject topRow = UIFactory.CreateHorizontalGroup(UIRoot, "TopRow", false, false, true, true, 4, default, new(1, 1, 1, 0), TextAnchor.MiddleLeft);
|
||||
GameObject topRow = UIFactory.CreateHorizontalGroup(UIRoot, "TopRow", false, false, true, true, 4, default,
|
||||
new(0.1f, 0.1f, 0.1f), TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(topRow, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
GameObject titleHolder = UIFactory.CreateUIObject("TitleHolder", topRow);
|
||||
UIFactory.SetLayoutElement(titleHolder, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
|
||||
NameText = UIFactory.CreateLabel(titleHolder, "VisibleTitle", "NotSet", TextAnchor.MiddleLeft);
|
||||
RectTransform namerect = NameText.GetComponent<RectTransform>();
|
||||
nameText = UIFactory.CreateLabel(titleHolder, "VisibleTitle", "NotSet", TextAnchor.MiddleLeft);
|
||||
RectTransform namerect = nameText.GetComponent<RectTransform>();
|
||||
namerect.anchorMin = new Vector2(0, 0);
|
||||
namerect.anchorMax = new Vector2(1, 1);
|
||||
NameText.fontSize = 17;
|
||||
UIFactory.SetLayoutElement(NameText.gameObject, minHeight: 35, flexibleHeight: 0, minWidth: 300, flexibleWidth: 9999);
|
||||
nameText.fontSize = 17;
|
||||
UIFactory.SetLayoutElement(nameText.gameObject, minHeight: 35, flexibleHeight: 0, minWidth: 300, flexibleWidth: 9999);
|
||||
|
||||
HiddenNameText = UIFactory.CreateInputField(titleHolder, "Title", "not set");
|
||||
RectTransform hiddenrect = HiddenNameText.Component.gameObject.GetComponent<RectTransform>();
|
||||
hiddenNameText = UIFactory.CreateInputField(titleHolder, "Title", "not set");
|
||||
RectTransform hiddenrect = hiddenNameText.Component.gameObject.GetComponent<RectTransform>();
|
||||
hiddenrect.anchorMin = new Vector2(0, 0);
|
||||
hiddenrect.anchorMax = new Vector2(1, 1);
|
||||
HiddenNameText.Component.readOnly = true;
|
||||
HiddenNameText.Component.lineType = InputField.LineType.MultiLineNewline;
|
||||
HiddenNameText.Component.gameObject.GetComponent<Image>().color = Color.clear;
|
||||
HiddenNameText.Component.textComponent.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
HiddenNameText.Component.textComponent.fontSize = 17;
|
||||
HiddenNameText.Component.textComponent.color = Color.clear;
|
||||
UIFactory.SetLayoutElement(HiddenNameText.Component.gameObject, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
hiddenNameText.Component.readOnly = true;
|
||||
hiddenNameText.Component.lineType = InputField.LineType.MultiLineNewline;
|
||||
hiddenNameText.Component.gameObject.GetComponent<Image>().color = Color.clear;
|
||||
hiddenNameText.Component.textComponent.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
hiddenNameText.Component.textComponent.fontSize = 17;
|
||||
hiddenNameText.Component.textComponent.color = Color.clear;
|
||||
UIFactory.SetLayoutElement(hiddenNameText.Component.gameObject, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
|
||||
makeGenericButton = UIFactory.CreateButton(topRow, "MakeGenericButton", "Construct Generic", new Color(0.2f, 0.3f, 0.2f));
|
||||
UIFactory.SetLayoutElement(makeGenericButton.GameObject, minWidth: 140, minHeight: 25);
|
||||
makeGenericButton.OnClick += OnMakeGenericClicked;
|
||||
makeGenericButton.GameObject.SetActive(false);
|
||||
|
||||
ButtonRef copyButton = UIFactory.CreateButton(topRow, "CopyButton", "Copy to Clipboard", new Color(0.2f, 0.2f, 0.2f, 1));
|
||||
copyButton.ButtonText.color = Color.yellow;
|
||||
UIFactory.SetLayoutElement(copyButton.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 0);
|
||||
copyButton.OnClick += OnCopyClicked;
|
||||
|
||||
AssemblyText = UIFactory.CreateLabel(UIRoot, "AssemblyLabel", "not set", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(AssemblyText.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
// Assembly row
|
||||
|
||||
mainContentHolder = UIFactory.CreateVerticalGroup(UIRoot, "MemberHolder", false, false, true, true, 5, new Vector4(2, 2, 2, 2),
|
||||
GameObject asmRow = UIFactory.CreateHorizontalGroup(UIRoot, "AssemblyRow", false, false, true, true, 5, default, new(1, 1, 1, 0));
|
||||
UIFactory.SetLayoutElement(asmRow, flexibleWidth: 9999, minHeight: 25);
|
||||
|
||||
assemblyText = UIFactory.CreateLabel(asmRow, "AssemblyLabel", "not set", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(assemblyText.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
dnSpyButton = UIFactory.CreateButton(asmRow, "DnSpyButton", "View in dnSpy");
|
||||
UIFactory.SetLayoutElement(dnSpyButton.GameObject, minWidth: 120, minHeight: 25);
|
||||
dnSpyButton.OnClick += OnDnSpyButtonClicked;
|
||||
|
||||
// Content
|
||||
|
||||
ContentRoot = UIFactory.CreateVerticalGroup(UIRoot, "ContentRoot", 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);
|
||||
UIFactory.SetLayoutElement(ContentRoot, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
ConstructFirstRow(mainContentHolder);
|
||||
ConstructFirstRow(ContentRoot);
|
||||
|
||||
ConstructSecondRow(mainContentHolder);
|
||||
ConstructSecondRow(ContentRoot);
|
||||
|
||||
// Member scroll pool
|
||||
|
||||
GameObject 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));
|
||||
GameObject memberBorder = UIFactory.CreateVerticalGroup(ContentRoot, "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);
|
||||
|
||||
MemberScrollPool = UIFactory.CreateScrollPool<CacheMemberCell>(memberBorder, "MemberList", out GameObject scrollObj,
|
||||
@@ -411,7 +489,7 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
// First row
|
||||
|
||||
private void ConstructFirstRow(GameObject parent)
|
||||
void ConstructFirstRow(GameObject parent)
|
||||
{
|
||||
GameObject rowObj = UIFactory.CreateUIObject("FirstRow", parent);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(rowObj, true, true, true, true, 5, 2, 2, 2, 2);
|
||||
@@ -422,7 +500,7 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
filterInputField = UIFactory.CreateInputField(rowObj, "NameFilterInput", "...");
|
||||
UIFactory.SetLayoutElement(filterInputField.UIRoot, minHeight: 25, flexibleWidth: 300);
|
||||
filterInputField.OnValueChanged += (string val) => { SetFilter(val); };
|
||||
filterInputField.OnValueChanged += (string val) => { OnSetNameFilter(val); };
|
||||
|
||||
GameObject spacer = UIFactory.CreateUIObject("Spacer", rowObj);
|
||||
UIFactory.SetLayoutElement(spacer, minWidth: 25);
|
||||
@@ -431,7 +509,7 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
ButtonRef updateButton = UIFactory.CreateButton(rowObj, "UpdateButton", "Update displayed values", new Color(0.22f, 0.28f, 0.22f));
|
||||
UIFactory.SetLayoutElement(updateButton.Component.gameObject, minHeight: 25, minWidth: 175, flexibleWidth: 0);
|
||||
updateButton.OnClick += UpdateClicked;
|
||||
updateButton.OnClick += OnUpdateClicked;
|
||||
|
||||
GameObject toggleObj = UIFactory.CreateToggle(rowObj, "AutoUpdateToggle", out autoUpdateToggle, out Text toggleText);
|
||||
UIFactory.SetLayoutElement(toggleObj, minWidth: 125, minHeight: 25);
|
||||
@@ -441,7 +519,7 @@ namespace UnityExplorer.Inspectors
|
||||
|
||||
// Second row
|
||||
|
||||
private void ConstructSecondRow(GameObject parent)
|
||||
void ConstructSecondRow(GameObject parent)
|
||||
{
|
||||
GameObject rowObj = UIFactory.CreateUIObject("SecondRow", parent);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(rowObj, false, false, true, true, 5, 2, 2, 2, 2);
|
||||
@@ -466,7 +544,7 @@ namespace UnityExplorer.Inspectors
|
||||
AddMemberTypeToggle(rowObj, MemberTypes.Constructor, 110);
|
||||
}
|
||||
|
||||
private void AddScopeFilterButton(GameObject parent, BindingFlags flags, bool setAsActive = false)
|
||||
void AddScopeFilterButton(GameObject parent, BindingFlags flags, bool setAsActive = false)
|
||||
{
|
||||
string lbl = flags == BindingFlags.Default ? "All" : flags.ToString();
|
||||
Color color = setAsActive ? enabledButtonColor : disabledButtonColor;
|
||||
@@ -475,10 +553,10 @@ namespace UnityExplorer.Inspectors
|
||||
UIFactory.SetLayoutElement(button.Component.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 70, flexibleWidth: 0);
|
||||
scopeFilterButtons.Add(flags, button);
|
||||
|
||||
button.OnClick += () => { SetFilter(flags); };
|
||||
button.OnClick += () => { OnSetFlags(flags); };
|
||||
}
|
||||
|
||||
private void AddMemberTypeToggle(GameObject parent, MemberTypes type, int width)
|
||||
void AddMemberTypeToggle(GameObject parent, MemberTypes type, int width)
|
||||
{
|
||||
GameObject toggleObj = UIFactory.CreateToggle(parent, "Toggle_" + type, out Toggle toggle, out Text toggleText);
|
||||
UIFactory.SetLayoutElement(toggleObj, minHeight: 25, minWidth: width);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#if BIE
|
||||
using BepInEx.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityExplorer.Config;
|
||||
|
||||
namespace UnityExplorer.Loader.BIE
|
||||
@@ -59,7 +57,7 @@ namespace UnityExplorer.Loader.BIE
|
||||
|
||||
public override void SaveConfig()
|
||||
{
|
||||
// not required
|
||||
Config.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
using BepInEx;
|
||||
using BepInEx.Logging;
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityExplorer.Config;
|
||||
using UnityExplorer.Loader.BIE;
|
||||
#if CPP
|
||||
using BepInEx.IL2CPP;
|
||||
using UnhollowerRuntimeLib;
|
||||
#endif
|
||||
|
||||
namespace UnityExplorer
|
||||
@@ -31,8 +28,14 @@ namespace UnityExplorer
|
||||
#else
|
||||
=> Log;
|
||||
#endif
|
||||
|
||||
public string UnhollowedModulesFolder => Path.Combine(Paths.BepInExRootPath, "unhollowed");
|
||||
const string IL2CPP_LIBS_FOLDER =
|
||||
#if UNHOLLOWER
|
||||
"unhollowed"
|
||||
#else
|
||||
"interop"
|
||||
#endif
|
||||
;
|
||||
public string UnhollowedModulesFolder => Path.Combine(Paths.BepInExRootPath, IL2CPP_LIBS_FOLDER);
|
||||
|
||||
public ConfigHandler ConfigHandler => _configHandler;
|
||||
private BepInExConfigHandler _configHandler;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using UnityExplorer.Config;
|
||||
using UnityExplorer.Config;
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
|
||||
@@ -6,27 +6,53 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Config;
|
||||
using UnityExplorer.UI;
|
||||
using UniverseLib;
|
||||
|
||||
namespace UnityExplorer.Loader.Standalone
|
||||
{
|
||||
public class ExplorerEditorBehaviour : MonoBehaviour
|
||||
{
|
||||
internal static ExplorerEditorBehaviour Instance { get; private set; }
|
||||
|
||||
public bool Hide_On_Startup = true;
|
||||
public KeyCode Master_Toggle_Key = KeyCode.F7;
|
||||
public UIManager.VerticalAnchor Main_Navbar_Anchor = UIManager.VerticalAnchor.Top;
|
||||
public bool Log_Unity_Debug = false;
|
||||
public float Startup_Delay_Time = 1f;
|
||||
public KeyCode World_MouseInspect_Keybind;
|
||||
public KeyCode UI_MouseInspect_Keybind;
|
||||
public bool Force_Unlock_Mouse = true;
|
||||
public KeyCode Force_Unlock_Toggle;
|
||||
public bool Disable_EventSystem_Override;
|
||||
|
||||
internal void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
ExplorerEditorLoader.Initialize();
|
||||
DontDestroyOnLoad(this);
|
||||
this.gameObject.hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
|
||||
internal void OnDestroy()
|
||||
{
|
||||
OnApplicationQuit();
|
||||
}
|
||||
|
||||
internal void OnApplicationQuit()
|
||||
{
|
||||
if (UI.UIManager.UIRoot)
|
||||
Destroy(UI.UIManager.UIRoot.transform.root.gameObject);
|
||||
Destroy(this.gameObject);
|
||||
}
|
||||
|
||||
internal void LoadConfigs()
|
||||
{
|
||||
ConfigManager.Hide_On_Startup.Value = this.Hide_On_Startup;
|
||||
ConfigManager.Master_Toggle.Value = this.Master_Toggle_Key;
|
||||
ConfigManager.Main_Navbar_Anchor.Value = this.Main_Navbar_Anchor;
|
||||
ConfigManager.Log_Unity_Debug.Value = this.Log_Unity_Debug;
|
||||
ConfigManager.Startup_Delay_Time.Value = this.Startup_Delay_Time;
|
||||
ConfigManager.World_MouseInspect_Keybind.Value = this.World_MouseInspect_Keybind;
|
||||
ConfigManager.UI_MouseInspect_Keybind.Value = this.UI_MouseInspect_Keybind;
|
||||
ConfigManager.Force_Unlock_Mouse.Value = this.Force_Unlock_Mouse;
|
||||
ConfigManager.Force_Unlock_Toggle.Value = this.Force_Unlock_Toggle;
|
||||
ConfigManager.Disable_EventSystem_Override.Value = this.Disable_EventSystem_Override;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace UnityExplorer.Loader.Standalone
|
||||
protected override void CheckExplorerFolder()
|
||||
{
|
||||
if (explorerFolderDest == null)
|
||||
explorerFolderDest = Application.dataPath;
|
||||
explorerFolderDest = Path.GetDirectoryName(Application.dataPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets.ButtonList;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.ObjectExplorer
|
||||
{
|
||||
@@ -34,12 +27,15 @@ namespace UnityExplorer.ObjectExplorer
|
||||
private ScrollPool<ButtonCell> resultsScrollPool;
|
||||
private List<object> currentResults = new();
|
||||
|
||||
//public TypeCompleter typeAutocompleter;
|
||||
public TypeCompleter unityObjectTypeCompleter;
|
||||
public TypeCompleter allTypesCompleter;
|
||||
|
||||
public override GameObject UIRoot => uiRoot;
|
||||
private GameObject uiRoot;
|
||||
private GameObject sceneFilterRow;
|
||||
private GameObject childFilterRow;
|
||||
private GameObject classInputRow;
|
||||
public TypeCompleter typeAutocompleter;
|
||||
private GameObject nameInputRow;
|
||||
private InputFieldRef nameInputField;
|
||||
private Text resultsLabel;
|
||||
@@ -98,14 +94,18 @@ namespace UnityExplorer.ObjectExplorer
|
||||
|
||||
nameInputRow.SetActive(context == SearchContext.UnityObject);
|
||||
|
||||
if (context == SearchContext.Class)
|
||||
typeAutocompleter.AllTypes = true;
|
||||
else
|
||||
switch (context)
|
||||
{
|
||||
typeAutocompleter.BaseType = context == SearchContext.UnityObject ? typeof(UnityEngine.Object) : typeof(object);
|
||||
typeAutocompleter.AllTypes = false;
|
||||
case SearchContext.UnityObject:
|
||||
unityObjectTypeCompleter.Enabled = true;
|
||||
allTypesCompleter.Enabled = false;
|
||||
break;
|
||||
case SearchContext.Singleton:
|
||||
case SearchContext.Class:
|
||||
allTypesCompleter.Enabled = true;
|
||||
unityObjectTypeCompleter.Enabled = false;
|
||||
break;
|
||||
}
|
||||
typeAutocompleter.CacheTypes();
|
||||
}
|
||||
|
||||
private void OnSceneFilterDropChanged(int value) => sceneFilter = (SceneFilter)value;
|
||||
@@ -185,7 +185,9 @@ namespace UnityExplorer.ObjectExplorer
|
||||
InputFieldRef classInputField = UIFactory.CreateInputField(classInputRow, "ClassInput", "...");
|
||||
UIFactory.SetLayoutElement(classInputField.UIRoot, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
|
||||
typeAutocompleter = new TypeCompleter(typeof(UnityEngine.Object), classInputField);
|
||||
unityObjectTypeCompleter = new(typeof(UnityEngine.Object), classInputField, true, false, true);
|
||||
allTypesCompleter = new(null, classInputField, true, false, true);
|
||||
allTypesCompleter.Enabled = false;
|
||||
classInputField.OnValueChanged += OnTypeInputChanged;
|
||||
|
||||
//unityObjectClassRow.SetActive(false);
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.Utility;
|
||||
using UniverseLib.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.ObjectExplorer
|
||||
{
|
||||
@@ -156,7 +148,7 @@ namespace UnityExplorer.ObjectExplorer
|
||||
{
|
||||
if ((!string.IsNullOrEmpty(input) && !Tree.Filtering) || (string.IsNullOrEmpty(input) && Tree.Filtering))
|
||||
{
|
||||
Tree.cachedTransforms.Clear();
|
||||
Tree.Clear();
|
||||
}
|
||||
|
||||
Tree.CurrentFilter = input;
|
||||
@@ -259,8 +251,7 @@ namespace UnityExplorer.ObjectExplorer
|
||||
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
|
||||
UIFactory.SetLayoutElement(scrollContent, flexibleHeight: 9999);
|
||||
|
||||
Tree = new TransformTree(scrollPool, GetRootEntries);
|
||||
Tree.Init();
|
||||
Tree = new TransformTree(scrollPool, GetRootEntries, OnCellClicked);
|
||||
Tree.RefreshData(true, true, true, false);
|
||||
//scrollPool.Viewport.GetComponent<Mask>().enabled = false;
|
||||
//UIRoot.GetComponent<Mask>().enabled = false;
|
||||
@@ -272,6 +263,8 @@ namespace UnityExplorer.ObjectExplorer
|
||||
RuntimeHelper.StartCoroutine(TempFixCoro());
|
||||
}
|
||||
|
||||
void OnCellClicked(GameObject obj) => InspectorManager.Inspect(obj);
|
||||
|
||||
// To "fix" a strange FPS drop issue with MelonLoader.
|
||||
private IEnumerator TempFixCoro()
|
||||
{
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UniverseLib;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace UnityExplorer.ObjectExplorer
|
||||
{
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UniverseLib;
|
||||
using UniverseLib.Utility;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace UnityExplorer.ObjectExplorer
|
||||
{
|
||||
@@ -135,7 +128,7 @@ namespace UnityExplorer.ObjectExplorer
|
||||
|
||||
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
foreach (Type type in asm.TryGetTypes())
|
||||
foreach (Type type in asm.GetTypes())
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ContainsIgnoreCase(nameFilter))
|
||||
continue;
|
||||
@@ -173,7 +166,7 @@ namespace UnityExplorer.ObjectExplorer
|
||||
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
// Search all non-static, non-enum classes.
|
||||
foreach (Type type in asm.TryGetTypes().Where(it => !(it.IsSealed && it.IsAbstract) && !it.IsEnum))
|
||||
foreach (Type type in asm.GetTypes().Where(it => !(it.IsSealed && it.IsAbstract) && !it.IsEnum))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityExplorer;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#if MONO
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.Runtime
|
||||
{
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityExplorer.Config;
|
||||
using UniverseLib;
|
||||
using UnityExplorer.Config;
|
||||
|
||||
namespace UnityExplorer.Runtime
|
||||
{
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityExplorer.Runtime
|
||||
namespace UnityExplorer.Runtime
|
||||
{
|
||||
internal static class UnityCrashPrevention
|
||||
{
|
||||
|
||||
+12
-7
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
#if CPP
|
||||
#if INTEROP
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using Il2CppInterop.Runtime;
|
||||
#else
|
||||
using UnhollowerRuntimeLib;
|
||||
using UnhollowerBaseLib;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace UnityExplorer.Tests
|
||||
{
|
||||
@@ -174,6 +175,7 @@ namespace UnityExplorer.Tests
|
||||
public static Il2CppSystem.Collections.IDictionary IL2CPP_IDict;
|
||||
public static Il2CppSystem.Collections.IList IL2CPP_IList;
|
||||
public static Dictionary<Il2CppSystem.Object, Il2CppSystem.Object> IL2CPP_BoxedDict;
|
||||
public static Il2CppSystem.Array IL2CPP_NonGenericArray;
|
||||
|
||||
public static Il2CppSystem.Object IL2CPP_BoxedInt;
|
||||
public static Il2CppSystem.Int32 IL2CPP_Int;
|
||||
@@ -187,6 +189,9 @@ namespace UnityExplorer.Tests
|
||||
|
||||
private static void Init_IL2CPP()
|
||||
{
|
||||
ExplorerCore.Log("IL2CPP 0: Non-generic array");
|
||||
IL2CPP_NonGenericArray = new Il2CppStructArray<int>(5).TryCast<Il2CppSystem.Array>();
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 1: Il2Cpp Dictionary<string, string>");
|
||||
IL2CPP_Dict = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
|
||||
IL2CPP_Dict.Add("key1", "value1");
|
||||
@@ -253,7 +258,7 @@ namespace UnityExplorer.Tests
|
||||
}
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 9: Il2Cpp struct array of ints");
|
||||
IL2CPP_structArray = new UnhollowerBaseLib.Il2CppStructArray<int>(5);
|
||||
IL2CPP_structArray = new Il2CppStructArray<int>(5);
|
||||
IL2CPP_structArray[0] = 0;
|
||||
IL2CPP_structArray[1] = 1;
|
||||
IL2CPP_structArray[2] = 2;
|
||||
@@ -261,7 +266,7 @@ namespace UnityExplorer.Tests
|
||||
IL2CPP_structArray[4] = 4;
|
||||
|
||||
ExplorerCore.Log($"IL2CPP 10: Il2Cpp reference array of boxed objects");
|
||||
IL2CPP_ReferenceArray = new UnhollowerBaseLib.Il2CppReferenceArray<Il2CppSystem.Object>(3);
|
||||
IL2CPP_ReferenceArray = new Il2CppReferenceArray<Il2CppSystem.Object>(3);
|
||||
IL2CPP_ReferenceArray[0] = new Il2CppSystem.Int32 { m_value = 5 }.BoxIl2CppObject();
|
||||
IL2CPP_ReferenceArray[1] = null;
|
||||
IL2CPP_ReferenceArray[2] = (Il2CppSystem.String)"whats up";
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Config;
|
||||
using UniverseLib;
|
||||
using UniverseLib.Input;
|
||||
|
||||
namespace UnityExplorer.UI
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Panels;
|
||||
|
||||
namespace UnityExplorer.UI
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI;
|
||||
|
||||
namespace UnityExplorer.UI
|
||||
{
|
||||
@@ -39,7 +37,6 @@ namespace UnityExplorer.UI
|
||||
|
||||
private static void ConstructUI()
|
||||
{
|
||||
|
||||
popupLabel = UIFactory.CreateLabel(UIManager.UIRoot, "ClipboardNotification", "", TextAnchor.MiddleCenter);
|
||||
popupLabel.rectTransform.sizeDelta = new(500, 100);
|
||||
popupLabel.gameObject.AddComponent<Outline>();
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib.Input;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets.ButtonList;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
@@ -69,15 +61,22 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
if (CurrentHandler == provider)
|
||||
{
|
||||
Suggestions.Clear();
|
||||
CurrentHandler = null;
|
||||
UIRoot.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSuggestions(IEnumerable<Suggestion> suggestions)
|
||||
public void SetSuggestions(List<Suggestion> suggestions, bool jumpToTop = true)
|
||||
{
|
||||
Suggestions = suggestions as List<Suggestion> ?? suggestions.ToList();
|
||||
SelectedIndex = 0;
|
||||
Suggestions = suggestions;
|
||||
|
||||
if (jumpToTop)
|
||||
{
|
||||
SelectedIndex = 0;
|
||||
if (scrollPool.DataSource.ItemCount > 0)
|
||||
scrollPool.JumpToIndex(0, null);
|
||||
}
|
||||
|
||||
if (!Suggestions.Any())
|
||||
base.UIRoot.SetActive(false);
|
||||
@@ -86,7 +85,7 @@ namespace UnityExplorer.UI.Panels
|
||||
base.UIRoot.SetActive(true);
|
||||
base.UIRoot.transform.SetAsLastSibling();
|
||||
buttonListDataHandler.RefreshData();
|
||||
scrollPool.Refresh(true, true);
|
||||
scrollPool.Refresh(true, jumpToTop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,6 +193,12 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
private void SetCell(ButtonCell cell, int index)
|
||||
{
|
||||
if (CurrentHandler == null)
|
||||
{
|
||||
UIRoot.SetActive(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= Suggestions.Count)
|
||||
{
|
||||
cell.Disable();
|
||||
@@ -225,13 +230,18 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
InputFieldRef input = CurrentHandler.InputField;
|
||||
|
||||
if (!input.Component.isFocused || input.Component.caretPosition == lastCaretPosition && input.UIRoot.transform.position == lastInputPosition)
|
||||
return;
|
||||
lastInputPosition = input.UIRoot.transform.position;
|
||||
lastCaretPosition = input.Component.caretPosition;
|
||||
//if (!input.Component.isFocused
|
||||
// || (input.Component.caretPosition == lastCaretPosition && input.UIRoot.transform.position == lastInputPosition))
|
||||
// return;
|
||||
|
||||
if (input.Component.caretPosition == lastCaretPosition && input.UIRoot.transform.position == lastInputPosition)
|
||||
return;
|
||||
|
||||
if (CurrentHandler.AnchorToCaretPosition)
|
||||
{
|
||||
if (!input.Component.isFocused)
|
||||
return;
|
||||
|
||||
TextGenerator textGen = input.Component.cachedInputTextGenerator;
|
||||
int caretIdx = Math.Max(0, Math.Min(textGen.characterCount - 1, input.Component.caretPosition));
|
||||
|
||||
@@ -248,6 +258,9 @@ namespace UnityExplorer.UI.Panels
|
||||
uiRoot.transform.position = input.Transform.position + new Vector3(-(input.Transform.rect.width / 2) + 10, -20, 0);
|
||||
}
|
||||
|
||||
lastInputPosition = input.UIRoot.transform.position;
|
||||
lastCaretPosition = input.Component.caretPosition;
|
||||
|
||||
this.Dragger.OnEndResize();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Collections;
|
||||
using UnityExplorer.CSConsole;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets;
|
||||
@@ -145,7 +141,7 @@ namespace UnityExplorer.UI.Panels
|
||||
GameObject inputObj = UIFactory.CreateScrollInputField(inputArea, "ConsoleInput", ConsoleController.STARTUP_TEXT,
|
||||
out InputFieldScroller inputScroller, fontSize);
|
||||
InputScroller = inputScroller;
|
||||
ConsoleController.defaultInputFieldAlpha = Input.Component.selectionColor.a;
|
||||
ConsoleController.DefaultInputFieldAlpha = Input.Component.selectionColor.a;
|
||||
Input.OnValueChanged += InvokeOnValueChanged;
|
||||
|
||||
// move line number text with input field
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.Utility;
|
||||
using UniverseLib.UI;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
using UniverseLib.Input;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
#if UNHOLLOWER
|
||||
using UnhollowerRuntimeLib;
|
||||
#endif
|
||||
#if INTEROP
|
||||
using Il2CppInterop.Runtime.Injection;
|
||||
#endif
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
internal class FreeCamPanel : UEPanel
|
||||
{
|
||||
public FreeCamPanel(UIBase owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Name => "Freecam";
|
||||
public override UIManager.Panels PanelType => UIManager.Panels.Freecam;
|
||||
public override int MinWidth => 400;
|
||||
public override int MinHeight => 320;
|
||||
public override Vector2 DefaultAnchorMin => new(0.4f, 0.4f);
|
||||
public override Vector2 DefaultAnchorMax => new(0.6f, 0.6f);
|
||||
public override bool NavButtonWanted => true;
|
||||
public override bool ShouldSaveActiveState => true;
|
||||
|
||||
internal static bool inFreeCamMode;
|
||||
internal static bool usingGameCamera;
|
||||
internal static Camera ourCamera;
|
||||
internal static Camera lastMainCamera;
|
||||
internal static FreeCamBehaviour freeCamScript;
|
||||
|
||||
internal static float desiredMoveSpeed = 10f;
|
||||
|
||||
internal static Vector3 originalCameraPosition;
|
||||
internal static Quaternion originalCameraRotation;
|
||||
|
||||
internal static Vector3? currentUserCameraPosition;
|
||||
internal static Quaternion? currentUserCameraRotation;
|
||||
|
||||
internal static Vector3 previousMousePosition;
|
||||
|
||||
internal static Vector3 lastSetCameraPosition;
|
||||
|
||||
static ButtonRef startStopButton;
|
||||
static Toggle useGameCameraToggle;
|
||||
static InputFieldRef positionInput;
|
||||
static InputFieldRef moveSpeedInput;
|
||||
static ButtonRef inspectButton;
|
||||
|
||||
internal static void BeginFreecam()
|
||||
{
|
||||
inFreeCamMode = true;
|
||||
|
||||
previousMousePosition = InputManager.MousePosition;
|
||||
|
||||
CacheMainCamera();
|
||||
SetupFreeCamera();
|
||||
|
||||
inspectButton.GameObject.SetActive(true);
|
||||
}
|
||||
|
||||
static void CacheMainCamera()
|
||||
{
|
||||
Camera currentMain = Camera.main;
|
||||
if (currentMain)
|
||||
{
|
||||
lastMainCamera = currentMain;
|
||||
originalCameraPosition = currentMain.transform.position;
|
||||
originalCameraRotation = currentMain.transform.rotation;
|
||||
|
||||
if (currentUserCameraPosition == null)
|
||||
{
|
||||
currentUserCameraPosition = currentMain.transform.position;
|
||||
currentUserCameraRotation = currentMain.transform.rotation;
|
||||
}
|
||||
}
|
||||
else
|
||||
originalCameraRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
static void SetupFreeCamera()
|
||||
{
|
||||
if (useGameCameraToggle.isOn)
|
||||
{
|
||||
if (!lastMainCamera)
|
||||
{
|
||||
ExplorerCore.LogWarning($"There is no previous Camera found, reverting to default Free Cam.");
|
||||
useGameCameraToggle.isOn = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
usingGameCamera = true;
|
||||
ourCamera = lastMainCamera;
|
||||
}
|
||||
}
|
||||
|
||||
if (!useGameCameraToggle.isOn)
|
||||
{
|
||||
usingGameCamera = false;
|
||||
|
||||
if (lastMainCamera)
|
||||
lastMainCamera.enabled = false;
|
||||
}
|
||||
|
||||
if (!ourCamera)
|
||||
{
|
||||
ourCamera = new GameObject("UE_Freecam").AddComponent<Camera>();
|
||||
ourCamera.gameObject.tag = "MainCamera";
|
||||
GameObject.DontDestroyOnLoad(ourCamera.gameObject);
|
||||
ourCamera.gameObject.hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
|
||||
if (!freeCamScript)
|
||||
freeCamScript = ourCamera.gameObject.AddComponent<FreeCamBehaviour>();
|
||||
|
||||
ourCamera.transform.position = (Vector3)currentUserCameraPosition;
|
||||
ourCamera.transform.rotation = (Quaternion)currentUserCameraRotation;
|
||||
|
||||
ourCamera.gameObject.SetActive(true);
|
||||
ourCamera.enabled = true;
|
||||
}
|
||||
|
||||
internal static void EndFreecam()
|
||||
{
|
||||
inFreeCamMode = false;
|
||||
|
||||
if (usingGameCamera)
|
||||
{
|
||||
ourCamera = null;
|
||||
|
||||
if (lastMainCamera)
|
||||
{
|
||||
lastMainCamera.transform.position = originalCameraPosition;
|
||||
lastMainCamera.transform.rotation = originalCameraRotation;
|
||||
}
|
||||
}
|
||||
|
||||
if (ourCamera)
|
||||
ourCamera.gameObject.SetActive(false);
|
||||
else
|
||||
inspectButton.GameObject.SetActive(false);
|
||||
|
||||
if (freeCamScript)
|
||||
{
|
||||
GameObject.Destroy(freeCamScript);
|
||||
freeCamScript = null;
|
||||
}
|
||||
|
||||
if (lastMainCamera)
|
||||
lastMainCamera.enabled = true;
|
||||
}
|
||||
|
||||
static void SetCameraPosition(Vector3 pos)
|
||||
{
|
||||
if (!ourCamera || lastSetCameraPosition == pos)
|
||||
return;
|
||||
|
||||
ourCamera.transform.position = pos;
|
||||
lastSetCameraPosition = pos;
|
||||
}
|
||||
|
||||
internal static void UpdatePositionInput()
|
||||
{
|
||||
if (!ourCamera)
|
||||
return;
|
||||
|
||||
if (positionInput.Component.isFocused)
|
||||
return;
|
||||
|
||||
lastSetCameraPosition = ourCamera.transform.position;
|
||||
positionInput.Text = ParseUtility.ToStringForInput<Vector3>(lastSetCameraPosition);
|
||||
}
|
||||
|
||||
// ~~~~~~~~ UI construction / callbacks ~~~~~~~~
|
||||
|
||||
protected override void ConstructPanelContent()
|
||||
{
|
||||
startStopButton = UIFactory.CreateButton(ContentRoot, "ToggleButton", "Freecam");
|
||||
UIFactory.SetLayoutElement(startStopButton.GameObject, minWidth: 150, minHeight: 25, flexibleWidth: 9999);
|
||||
startStopButton.OnClick += StartStopButton_OnClick;
|
||||
SetToggleButtonState();
|
||||
|
||||
AddSpacer(5);
|
||||
|
||||
GameObject toggleObj = UIFactory.CreateToggle(ContentRoot, "UseGameCameraToggle", out useGameCameraToggle, out Text toggleText);
|
||||
UIFactory.SetLayoutElement(toggleObj, minHeight: 25, flexibleWidth: 9999);
|
||||
useGameCameraToggle.onValueChanged.AddListener(OnUseGameCameraToggled);
|
||||
useGameCameraToggle.isOn = false;
|
||||
toggleText.text = "Use Game Camera?";
|
||||
|
||||
AddSpacer(5);
|
||||
|
||||
GameObject posRow = AddInputField("Position", "Freecam Pos:", "eg. 0 0 0", out positionInput, PositionInput_OnEndEdit);
|
||||
|
||||
ButtonRef resetPosButton = UIFactory.CreateButton(posRow, "ResetButton", "Reset");
|
||||
UIFactory.SetLayoutElement(resetPosButton.GameObject, minWidth: 70, minHeight: 25);
|
||||
resetPosButton.OnClick += OnResetPosButtonClicked;
|
||||
|
||||
AddSpacer(5);
|
||||
|
||||
AddInputField("MoveSpeed", "Move Speed:", "Default: 1", out moveSpeedInput, MoveSpeedInput_OnEndEdit);
|
||||
moveSpeedInput.Text = desiredMoveSpeed.ToString();
|
||||
|
||||
AddSpacer(5);
|
||||
|
||||
string instructions = @"Controls:
|
||||
- WASD / Arrows: Movement
|
||||
- Space / PgUp: Move up
|
||||
- LeftCtrl / PgDown: Move down
|
||||
- Right Mouse Button: Free look
|
||||
- Shift: Super speed";
|
||||
|
||||
Text instructionsText = UIFactory.CreateLabel(ContentRoot, "Instructions", instructions, TextAnchor.UpperLeft);
|
||||
UIFactory.SetLayoutElement(instructionsText.gameObject, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
AddSpacer(5);
|
||||
|
||||
inspectButton = UIFactory.CreateButton(ContentRoot, "InspectButton", "Inspect Free Camera");
|
||||
UIFactory.SetLayoutElement(inspectButton.GameObject, flexibleWidth: 9999, minHeight: 25);
|
||||
inspectButton.OnClick += () => { InspectorManager.Inspect(ourCamera); };
|
||||
inspectButton.GameObject.SetActive(false);
|
||||
|
||||
AddSpacer(5);
|
||||
}
|
||||
|
||||
void AddSpacer(int height)
|
||||
{
|
||||
GameObject obj = UIFactory.CreateUIObject("Spacer", ContentRoot);
|
||||
UIFactory.SetLayoutElement(obj, minHeight: height, flexibleHeight: 0);
|
||||
}
|
||||
|
||||
GameObject AddInputField(string name, string labelText, string placeHolder, out InputFieldRef inputField, Action<string> onInputEndEdit)
|
||||
{
|
||||
GameObject row = UIFactory.CreateHorizontalGroup(ContentRoot, $"{name}_Group", false, false, true, true, 3, default, new(1, 1, 1, 0));
|
||||
|
||||
Text posLabel = UIFactory.CreateLabel(row, $"{name}_Label", labelText);
|
||||
UIFactory.SetLayoutElement(posLabel.gameObject, minWidth: 100, minHeight: 25);
|
||||
|
||||
inputField = UIFactory.CreateInputField(row, $"{name}_Input", placeHolder);
|
||||
UIFactory.SetLayoutElement(inputField.GameObject, minWidth: 125, minHeight: 25, flexibleWidth: 9999);
|
||||
inputField.Component.GetOnEndEdit().AddListener(onInputEndEdit);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
void StartStopButton_OnClick()
|
||||
{
|
||||
EventSystemHelper.SetSelectedGameObject(null);
|
||||
|
||||
if (inFreeCamMode)
|
||||
EndFreecam();
|
||||
else
|
||||
BeginFreecam();
|
||||
|
||||
SetToggleButtonState();
|
||||
}
|
||||
|
||||
void SetToggleButtonState()
|
||||
{
|
||||
if (inFreeCamMode)
|
||||
{
|
||||
RuntimeHelper.SetColorBlockAuto(startStopButton.Component, new(0.4f, 0.2f, 0.2f));
|
||||
startStopButton.ButtonText.text = "End Freecam";
|
||||
}
|
||||
else
|
||||
{
|
||||
RuntimeHelper.SetColorBlockAuto(startStopButton.Component, new(0.2f, 0.4f, 0.2f));
|
||||
startStopButton.ButtonText.text = "Begin Freecam";
|
||||
}
|
||||
}
|
||||
|
||||
void OnUseGameCameraToggled(bool value)
|
||||
{
|
||||
EventSystemHelper.SetSelectedGameObject(null);
|
||||
|
||||
if (!inFreeCamMode)
|
||||
return;
|
||||
|
||||
EndFreecam();
|
||||
BeginFreecam();
|
||||
}
|
||||
|
||||
void OnResetPosButtonClicked()
|
||||
{
|
||||
currentUserCameraPosition = originalCameraPosition;
|
||||
currentUserCameraRotation = originalCameraRotation;
|
||||
|
||||
if (inFreeCamMode && ourCamera)
|
||||
{
|
||||
ourCamera.transform.position = (Vector3)currentUserCameraPosition;
|
||||
ourCamera.transform.rotation = (Quaternion)currentUserCameraRotation;
|
||||
}
|
||||
|
||||
positionInput.Text = ParseUtility.ToStringForInput<Vector3>(originalCameraPosition);
|
||||
}
|
||||
|
||||
void PositionInput_OnEndEdit(string input)
|
||||
{
|
||||
EventSystemHelper.SetSelectedGameObject(null);
|
||||
|
||||
if (!ParseUtility.TryParse(input, out Vector3 parsed, out Exception parseEx))
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not parse position to Vector3: {parseEx.ReflectionExToString()}");
|
||||
UpdatePositionInput();
|
||||
return;
|
||||
}
|
||||
|
||||
SetCameraPosition(parsed);
|
||||
}
|
||||
|
||||
void MoveSpeedInput_OnEndEdit(string input)
|
||||
{
|
||||
EventSystemHelper.SetSelectedGameObject(null);
|
||||
|
||||
if (!ParseUtility.TryParse(input, out float parsed, out Exception parseEx))
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not parse value: {parseEx.ReflectionExToString()}");
|
||||
moveSpeedInput.Text = desiredMoveSpeed.ToString();
|
||||
return;
|
||||
}
|
||||
|
||||
desiredMoveSpeed = parsed;
|
||||
}
|
||||
}
|
||||
|
||||
internal class FreeCamBehaviour : MonoBehaviour
|
||||
{
|
||||
#if CPP
|
||||
static FreeCamBehaviour()
|
||||
{
|
||||
ClassInjector.RegisterTypeInIl2Cpp<FreeCamBehaviour>();
|
||||
}
|
||||
|
||||
public FreeCamBehaviour(IntPtr ptr) : base(ptr) { }
|
||||
#endif
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
if (FreeCamPanel.inFreeCamMode)
|
||||
{
|
||||
if (!FreeCamPanel.ourCamera)
|
||||
{
|
||||
FreeCamPanel.EndFreecam();
|
||||
return;
|
||||
}
|
||||
|
||||
Transform transform = FreeCamPanel.ourCamera.transform;
|
||||
|
||||
FreeCamPanel.currentUserCameraPosition = transform.position;
|
||||
FreeCamPanel.currentUserCameraRotation = transform.rotation;
|
||||
|
||||
float moveSpeed = FreeCamPanel.desiredMoveSpeed * Time.deltaTime;
|
||||
|
||||
if (InputManager.GetKey(KeyCode.LeftShift) || InputManager.GetKey(KeyCode.RightShift))
|
||||
moveSpeed *= 10f;
|
||||
|
||||
if (InputManager.GetKey(KeyCode.LeftArrow) || InputManager.GetKey(KeyCode.A))
|
||||
transform.position += transform.right * -1 * moveSpeed;
|
||||
|
||||
if (InputManager.GetKey(KeyCode.RightArrow) || InputManager.GetKey(KeyCode.D))
|
||||
transform.position += transform.right * moveSpeed;
|
||||
|
||||
if (InputManager.GetKey(KeyCode.UpArrow) || InputManager.GetKey(KeyCode.W))
|
||||
transform.position += transform.forward * moveSpeed;
|
||||
|
||||
if (InputManager.GetKey(KeyCode.DownArrow) || InputManager.GetKey(KeyCode.S))
|
||||
transform.position += transform.forward * -1 * moveSpeed;
|
||||
|
||||
if (InputManager.GetKey(KeyCode.Space) || InputManager.GetKey(KeyCode.PageUp))
|
||||
transform.position += transform.up * moveSpeed;
|
||||
|
||||
if (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.PageDown))
|
||||
transform.position += transform.up * -1 * moveSpeed;
|
||||
|
||||
if (InputManager.GetMouseButton(1))
|
||||
{
|
||||
Vector3 mouseDelta = InputManager.MousePosition - FreeCamPanel.previousMousePosition;
|
||||
|
||||
float newRotationX = transform.localEulerAngles.y + mouseDelta.x * 0.3f;
|
||||
float newRotationY = transform.localEulerAngles.x - mouseDelta.y * 0.3f;
|
||||
transform.localEulerAngles = new Vector3(newRotationY, newRotationX, 0f);
|
||||
}
|
||||
|
||||
FreeCamPanel.UpdatePositionInput();
|
||||
|
||||
FreeCamPanel.previousMousePosition = InputManager.MousePosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,86 +1,63 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Hooks;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UnityExplorer.Hooks;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
public class HookManagerPanel : UEPanel
|
||||
{
|
||||
public static HookManagerPanel Instance { get; private set; }
|
||||
|
||||
public enum Pages
|
||||
{
|
||||
CurrentHooks,
|
||||
ClassMethodSelector,
|
||||
HookSourceEditor
|
||||
HookSourceEditor,
|
||||
GenericArgsSelector,
|
||||
}
|
||||
|
||||
public override UIManager.Panels PanelType => UIManager.Panels.HookManager;
|
||||
public static HookCreator hookCreator;
|
||||
public static HookList hookList;
|
||||
public static GenericConstructorWidget genericArgsHandler;
|
||||
|
||||
// Panel
|
||||
public override UIManager.Panels PanelType => UIManager.Panels.HookManager;
|
||||
public override string Name => "Hooks";
|
||||
public override bool ShowByDefault => false;
|
||||
|
||||
public override int MinWidth => 500;
|
||||
public override int MinHeight => 600;
|
||||
public override int MinWidth => 400;
|
||||
public override int MinHeight => 400;
|
||||
public override Vector2 DefaultAnchorMin => new(0.5f, 0.5f);
|
||||
public override Vector2 DefaultAnchorMax => new(0.5f, 0.5f);
|
||||
|
||||
public Pages CurrentPage { get; private set; } = Pages.CurrentHooks;
|
||||
|
||||
private GameObject currentHooksPanel;
|
||||
public ScrollPool<HookCell> HooksScrollPool;
|
||||
private InputFieldRef classSelectorInputField;
|
||||
|
||||
private GameObject addHooksPanel;
|
||||
public ScrollPool<AddHookCell> AddHooksScrollPool;
|
||||
private Text addHooksLabel;
|
||||
private InputFieldRef AddHooksMethodFilterInput;
|
||||
|
||||
private GameObject editorPanel;
|
||||
|
||||
public InputFieldScroller EditorInputScroller { get; private set; }
|
||||
public InputFieldRef EditorInput => EditorInputScroller.InputField;
|
||||
public Text EditorInputText { get; private set; }
|
||||
public Text EditorHighlightText { get; private set; }
|
||||
public Pages CurrentPage { get; private set; } = Pages.ClassMethodSelector;
|
||||
|
||||
public HookManagerPanel(UIBase owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
private void OnClassInputAddClicked()
|
||||
{
|
||||
HookManager.Instance.OnClassSelectedForHooks(this.classSelectorInputField.Text);
|
||||
}
|
||||
|
||||
public void SetAddHooksLabelType(string typeText) => addHooksLabel.text = $"Adding hooks to: {typeText}";
|
||||
|
||||
public void SetPage(Pages page)
|
||||
{
|
||||
switch (page)
|
||||
{
|
||||
case Pages.CurrentHooks:
|
||||
currentHooksPanel.SetActive(true);
|
||||
addHooksPanel.SetActive(false);
|
||||
editorPanel.SetActive(false);
|
||||
break;
|
||||
case Pages.ClassMethodSelector:
|
||||
currentHooksPanel.SetActive(false);
|
||||
addHooksPanel.SetActive(true);
|
||||
editorPanel.SetActive(false);
|
||||
HookCreator.AddHooksRoot.SetActive(true);
|
||||
HookCreator.EditorRoot.SetActive(false);
|
||||
genericArgsHandler.UIRoot.SetActive(false);
|
||||
break;
|
||||
|
||||
case Pages.HookSourceEditor:
|
||||
currentHooksPanel.SetActive(false);
|
||||
addHooksPanel.SetActive(false);
|
||||
editorPanel.SetActive(true);
|
||||
HookCreator.AddHooksRoot.SetActive(false);
|
||||
HookCreator.EditorRoot.SetActive(true);
|
||||
genericArgsHandler.UIRoot.SetActive(false);
|
||||
break;
|
||||
|
||||
case Pages.GenericArgsSelector:
|
||||
HookCreator.AddHooksRoot.SetActive(false);
|
||||
HookCreator.EditorRoot.SetActive(false);
|
||||
genericArgsHandler.UIRoot.SetActive(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetMethodFilter() => AddHooksMethodFilterInput.Text = string.Empty;
|
||||
|
||||
public override void SetDefaultSizeAndPosition()
|
||||
{
|
||||
base.SetDefaultSizeAndPosition();
|
||||
@@ -91,115 +68,35 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
protected override void ConstructPanelContent()
|
||||
{
|
||||
// ~~~~~~~~~ Active hooks scroll pool
|
||||
Instance = this;
|
||||
hookList = new();
|
||||
hookCreator = new();
|
||||
genericArgsHandler = new();
|
||||
|
||||
currentHooksPanel = UIFactory.CreateUIObject("CurrentHooksPanel", this.ContentRoot);
|
||||
UIFactory.SetLayoutElement(currentHooksPanel, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(currentHooksPanel, true, true, true, true);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(ContentRoot, true, false);
|
||||
|
||||
GameObject addRow = UIFactory.CreateHorizontalGroup(currentHooksPanel, "AddRow", false, true, true, true, 4,
|
||||
new Vector4(2, 2, 2, 2), new Color(0.2f, 0.2f, 0.2f));
|
||||
UIFactory.SetLayoutElement(addRow, minHeight: 30, flexibleWidth: 9999);
|
||||
// GameObject baseHoriGroup = UIFactory.CreateHorizontalGroup(ContentRoot, "HoriGroup", true, true, true, true);
|
||||
// UIFactory.SetLayoutElement(baseHoriGroup, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
classSelectorInputField = UIFactory.CreateInputField(addRow, "ClassInput", "Enter a class to add hooks to...");
|
||||
UIFactory.SetLayoutElement(classSelectorInputField.Component.gameObject, flexibleWidth: 9999);
|
||||
new TypeCompleter(typeof(object), classSelectorInputField, true, false);
|
||||
// // Left Group
|
||||
|
||||
ButtonRef addButton = UIFactory.CreateButton(addRow, "AddButton", "Add Hooks");
|
||||
UIFactory.SetLayoutElement(addButton.Component.gameObject, minWidth: 100, minHeight: 25);
|
||||
addButton.OnClick += OnClassInputAddClicked;
|
||||
//GameObject leftGroup = UIFactory.CreateVerticalGroup(ContentRoot, "LeftGroup", true, true, true, true);
|
||||
UIFactory.SetLayoutElement(ContentRoot.gameObject, minWidth: 300, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
Text hooksLabel = UIFactory.CreateLabel(currentHooksPanel, "HooksLabel", "Current Hooks", TextAnchor.MiddleCenter);
|
||||
UIFactory.SetLayoutElement(hooksLabel.gameObject, minHeight: 30, flexibleWidth: 9999);
|
||||
hookList.ConstructUI(ContentRoot);
|
||||
|
||||
HooksScrollPool = UIFactory.CreateScrollPool<HookCell>(currentHooksPanel, "HooksScrollPool",
|
||||
out GameObject hooksScroll, out GameObject hooksContent);
|
||||
UIFactory.SetLayoutElement(hooksScroll, flexibleHeight: 9999);
|
||||
HooksScrollPool.Initialize(HookManager.Instance);
|
||||
// // Right Group
|
||||
|
||||
// ~~~~~~~~~ Add hooks panel
|
||||
//GameObject rightGroup = UIFactory.CreateVerticalGroup(ContentRoot, "RightGroup", true, true, true, true);
|
||||
UIFactory.SetLayoutElement(ContentRoot, minWidth: 300, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
addHooksPanel = UIFactory.CreateUIObject("AddHooksPanel", this.ContentRoot);
|
||||
UIFactory.SetLayoutElement(addHooksPanel, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(addHooksPanel, true, true, true, true);
|
||||
hookCreator.ConstructAddHooksView(ContentRoot);
|
||||
|
||||
addHooksLabel = UIFactory.CreateLabel(addHooksPanel, "AddLabel", "NOT SET", TextAnchor.MiddleCenter);
|
||||
UIFactory.SetLayoutElement(addHooksLabel.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999);
|
||||
hookCreator.ConstructEditor(ContentRoot);
|
||||
HookCreator.EditorRoot.SetActive(false);
|
||||
|
||||
GameObject buttonRow = UIFactory.CreateHorizontalGroup(addHooksPanel, "ButtonRow", false, false, true, true, 5);
|
||||
UIFactory.SetLayoutElement(buttonRow, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
ButtonRef doneButton = UIFactory.CreateButton(buttonRow, "DoneButton", "Done", new Color(0.2f, 0.3f, 0.2f));
|
||||
UIFactory.SetLayoutElement(doneButton.Component.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
doneButton.OnClick += HookManager.Instance.DoneAddingHooks;
|
||||
|
||||
AddHooksMethodFilterInput = UIFactory.CreateInputField(addHooksPanel, "FilterInputField", "Filter method names...");
|
||||
UIFactory.SetLayoutElement(AddHooksMethodFilterInput.Component.gameObject, minHeight: 30, flexibleWidth: 9999);
|
||||
AddHooksMethodFilterInput.OnValueChanged += HookManager.Instance.OnAddHookFilterInputChanged;
|
||||
|
||||
AddHooksScrollPool = UIFactory.CreateScrollPool<AddHookCell>(addHooksPanel, "MethodAddScrollPool",
|
||||
out GameObject addScrollRoot, out GameObject addContent);
|
||||
UIFactory.SetLayoutElement(addScrollRoot, flexibleHeight: 9999);
|
||||
AddHooksScrollPool.Initialize(HookManager.Instance);
|
||||
|
||||
addHooksPanel.gameObject.SetActive(false);
|
||||
|
||||
// ~~~~~~~~~ Hook source editor panel
|
||||
|
||||
editorPanel = UIFactory.CreateUIObject("HookSourceEditor", this.ContentRoot);
|
||||
UIFactory.SetLayoutElement(editorPanel, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(editorPanel, true, true, true, true);
|
||||
|
||||
Text editorLabel = UIFactory.CreateLabel(editorPanel,
|
||||
"EditorLabel",
|
||||
"Edit Harmony patch source as desired. Accepted method names are Prefix, Postfix, Finalizer and Transpiler (can define multiple).\n\n" +
|
||||
"Hooks are temporary! Please copy the source into your IDE to avoid losing work if you wish to keep it!",
|
||||
TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(editorLabel.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
GameObject editorButtonRow = UIFactory.CreateHorizontalGroup(editorPanel, "ButtonRow", false, false, true, true, 5);
|
||||
UIFactory.SetLayoutElement(editorButtonRow, minHeight: 25, flexibleWidth: 9999);
|
||||
|
||||
ButtonRef editorSaveButton = UIFactory.CreateButton(editorButtonRow, "DoneButton", "Save and Return", new Color(0.2f, 0.3f, 0.2f));
|
||||
UIFactory.SetLayoutElement(editorSaveButton.Component.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
editorSaveButton.OnClick += HookManager.Instance.EditorInputSave;
|
||||
|
||||
ButtonRef editorDoneButton = UIFactory.CreateButton(editorButtonRow, "DoneButton", "Cancel and Return", new Color(0.2f, 0.2f, 0.2f));
|
||||
UIFactory.SetLayoutElement(editorDoneButton.Component.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||
editorDoneButton.OnClick += HookManager.Instance.EditorInputCancel;
|
||||
|
||||
int fontSize = 16;
|
||||
GameObject inputObj = UIFactory.CreateScrollInputField(editorPanel, "EditorInput", "", out InputFieldScroller inputScroller, fontSize);
|
||||
EditorInputScroller = inputScroller;
|
||||
EditorInput.OnValueChanged += HookManager.Instance.OnEditorInputChanged;
|
||||
|
||||
EditorInputText = EditorInput.Component.textComponent;
|
||||
EditorInputText.supportRichText = false;
|
||||
EditorInputText.color = Color.clear;
|
||||
EditorInput.Component.customCaretColor = true;
|
||||
EditorInput.Component.caretColor = Color.white;
|
||||
EditorInput.PlaceholderText.fontSize = fontSize;
|
||||
|
||||
// Lexer highlight text overlay
|
||||
GameObject highlightTextObj = UIFactory.CreateUIObject("HighlightText", EditorInputText.gameObject);
|
||||
RectTransform highlightTextRect = highlightTextObj.GetComponent<RectTransform>();
|
||||
highlightTextRect.pivot = new Vector2(0, 1);
|
||||
highlightTextRect.anchorMin = Vector2.zero;
|
||||
highlightTextRect.anchorMax = Vector2.one;
|
||||
highlightTextRect.offsetMin = Vector2.zero;
|
||||
highlightTextRect.offsetMax = Vector2.zero;
|
||||
|
||||
EditorHighlightText = highlightTextObj.AddComponent<Text>();
|
||||
EditorHighlightText.color = Color.white;
|
||||
EditorHighlightText.supportRichText = true;
|
||||
EditorHighlightText.fontSize = fontSize;
|
||||
|
||||
// Set fonts
|
||||
EditorInputText.font = UniversalUI.ConsoleFont;
|
||||
EditorInput.PlaceholderText.font = UniversalUI.ConsoleFont;
|
||||
EditorHighlightText.font = UniversalUI.ConsoleFont;
|
||||
|
||||
editorPanel.SetActive(false);
|
||||
genericArgsHandler.ConstructUI(ContentRoot);
|
||||
genericArgsHandler.UIRoot.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UnityExplorer.Inspectors;
|
||||
using UniverseLib.UI;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using System.Diagnostics;
|
||||
using UnityExplorer.Config;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
// TODO move the logic out of this class into a LogUtil class (also move ExplorerCore.Log into that)
|
||||
|
||||
public class LogPanel : UEPanel, ICellPoolDataSource<ConsoleLogCell>
|
||||
{
|
||||
public struct LogInfo
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Inspectors.MouseInspectors;
|
||||
using UnityExplorer.Inspectors.MouseInspectors;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Widgets.ButtonList;
|
||||
using UniverseLib.UI.Widgets.ScrollView;
|
||||
using UniverseLib.Utility;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.ObjectExplorer;
|
||||
using UniverseLib;
|
||||
using UnityExplorer.ObjectExplorer;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.CacheObject.Views;
|
||||
using UnityExplorer.Config;
|
||||
using UniverseLib.UI;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user