Compare commits

...

113 Commits

Author SHA1 Message Date
Sinai
1e1fb0e27b Merge branch 'master' of https://github.com/sinai-dev/UnityExplorer 2022-06-23 10:53:16 +10:00
Sinai
6b8a7d90c8 Update README.md 2022-06-23 10:53:14 +10:00
Sinai
1b4657dead
Update workflow for BepInEx CoreCLR build 2022-06-23 06:14:22 +10:00
Sinai
1af20ead9f Add BepInEx Il2CppInterop build 2022-06-23 06:03:58 +10:00
Sinai
706a18d1f6 Bump UniverseLib 2022-06-05 20:44:29 +10:00
Sinai
81dd8bad0e Update to C# 10.0, global usings 2022-05-26 06:19:50 +10:00
Sinai
97dffc81e1 Fix patch target on Time.timeScale 2022-05-19 00:07:12 +10:00
Sinai
bf2b22e768
Fix double zipped artifacts 2022-05-17 19:06:26 +10:00
Sinai
d1fbbfa62d Bump version 2022-05-15 19:12:00 +10:00
Sinai
56a3cef245 Add C# Console Assembly blacklist 2022-05-15 18:16:04 +10:00
Sinai
61e7915a55 Merge branch 'master' of https://github.com/sinai-dev/UnityExplorer 2022-05-14 01:55:13 +10:00
Sinai
88e63c8d6a Fix logic after changes in UniverseLib 2022-05-14 01:55:10 +10:00
Sinai
048e5980a0
Update README.md 2022-05-13 20:44:51 +10:00
Sinai
3b851b6e08 Use 7zip instead of Compress-Archive 2022-05-13 17:11:25 +10:00
Sinai
4c029dad90 Update TimeScaleWidget.cs 2022-05-11 22:49:28 +10:00
Sinai
3d61011e59 Move Time Scale Widget into separate class
And change "pause" to "lock" behaviour. Added patch to implement locking feature.
2022-05-10 01:44:08 +10:00
Sinai
5285239bc5 Update hooks list after edit save 2022-05-10 01:43:41 +10:00
Sinai
57d3a3f52e Fix UI Mouse Inspect hotkey not being implemented 2022-05-10 01:02:37 +10:00
Sinai
c88182c831 Bump version 2022-05-08 18:06:56 +10:00
Sinai
02e0102041 Merge branch 'master' of https://github.com/sinai-dev/UnityExplorer 2022-05-07 05:19:46 +10:00
Sinai
6adecef785 Fix generated patch code for static void methods
And always show the patch even if it failed to apply
2022-05-07 05:19:43 +10:00
Sinai
ff6c03e1f3
Update README.md 2022-05-06 15:46:49 +10:00
Sinai
1aedc505b2 Bump UniverseLib 2022-05-05 23:13:51 +10:00
Sinai
dbe993a7c7 Fix some casts for IL2CPP 2022-05-05 22:18:19 +10:00
Sinai
5a1676fb84 Update README.md 2022-05-05 19:56:29 +10:00
Sinai
a7a663aefa Prevent update overwriting input field changes 2022-05-05 19:53:02 +10:00
Sinai
76c77fb082 Add button to inspect scene of a GameObject 2022-05-05 19:52:25 +10:00
Sinai
a25017df69 Add wider Texture2DWidget support 2022-05-05 19:52:13 +10:00
Sinai
a1fab0c4a7 Add support for opening inspected Type in dnSpy 2022-05-05 19:50:52 +10:00
Sinai
4599747bfe Merge branch 'master' of https://github.com/sinai-dev/UnityExplorer 2022-05-05 02:45:43 +10:00
Sinai
3856e84c08 Bump version 2022-05-05 02:45:41 +10:00
Sinai
104288a912 Add support for Cubemaps in Texture2DWidget 2022-05-05 02:45:24 +10:00
Sinai
41e8a5ae33
Update README.md 2022-05-03 06:10:22 +10:00
Sinai
ef4bc75d5e Bump version 2022-04-30 20:53:31 +10:00
Sinai
68b81c6b53 Bump UniverseLib 2022-04-30 20:47:53 +10:00
Sinai
bd86f09313 Cleanup and refactor GameObjectControls
Split into proper classes, cleanup ugly code
2022-04-30 20:32:31 +10:00
Sinai
b35d6f5787 Cleanup 2022-04-30 20:31:33 +10:00
Sinai
b97eada516
Update README.md 2022-04-29 16:56:29 +10:00
Sinai
0a05848bef Implement control modifier to Home/End jump 2022-04-28 04:10:36 +10:00
Sinai
6e5610129a Add ILRepack back to build process 2022-04-27 20:13:17 +10:00
Sinai
acd30880a8 Bump UniverseLib 2022-04-27 03:04:28 +10:00
Sinai
f54ff89290 Bump UniverseLib 2022-04-25 22:52:24 +10:00
Sinai
62d565777d Bump UniverseLib and version 2022-04-25 19:39:44 +10:00
Sinai
870f82ab26 Fix Home jump when line is entirely whitespace 2022-04-25 05:48:13 +10:00
Sinai
9370c5e0e6 Fix jumpToTop and panel position behaviour 2022-04-25 05:47:57 +10:00
Sinai
b8cf96438c Correct a comment position 2022-04-24 19:38:17 +10:00
Sinai
7be7daf4d7 Bump version 2022-04-24 19:24:43 +10:00
Sinai
8f54415ae0 Remove small logic error with SymbolLexer 2022-04-24 19:23:05 +10:00
Sinai
aef4e11c01 C# Console: Implement Home and End keys 2022-04-24 19:13:43 +10:00
Sinai
af7e32ec49 Add a null check 2022-04-24 18:16:13 +10:00
Sinai
6f44a3376b Bump UniverseLib 2022-04-24 05:58:36 +10:00
Sinai
3a6b573ac3 Bump version 2022-04-24 05:57:29 +10:00
Sinai
cbe17927fb Ensure valid panel size after loading save data 2022-04-24 05:57:22 +10:00
Sinai
15f3f37948 Clean up all objects in editor 2022-04-24 05:56:47 +10:00
Sinai
de6760e427 Add more convenient editor config serialization 2022-04-24 05:56:36 +10:00
Sinai
83edd1b9bb Bump editor package 2022-04-24 02:12:57 +10:00
Sinai
613be34e95 Bump UniverseLib 2022-04-24 02:04:08 +10:00
Sinai
58c65b9b8b Make TypeCompleter asynchronous 2022-04-24 02:02:34 +10:00
Sinai
6fcf6a521c Bump version 2022-04-24 02:02:29 +10:00
Sinai
81a174f865 Remove call to obsolete methods 2022-04-24 01:59:53 +10:00
Sinai
b5e3cc2ea5 Use separate TypeCompleters for different contexts 2022-04-24 01:59:03 +10:00
Sinai
14f46ade6a Cancel pending generic when edit button pressed 2022-04-24 01:58:27 +10:00
Sinai
e92556805b Update BepInExConfigHandler.cs 2022-04-23 01:05:51 +10:00
Sinai
8662742461 Bump version 2022-04-23 00:19:31 +10:00
Sinai
63393a9d66 Update README.md 2022-04-22 22:31:36 +10:00
Sinai
13986f95c1 Update UnityExplorer.STANDALONE.Mono.dll 2022-04-22 22:27:48 +10:00
Sinai
b47bfa1e83 Remove Mono restriction on generic type eligibility 2022-04-22 22:27:43 +10:00
Sinai
12c51248fe Update Editor package 2022-04-22 22:20:01 +10:00
Sinai
9b9cb54a79 Fix a typo 2022-04-22 22:19:43 +10:00
Sinai
6a28a93e3a Update for obsolete method 2022-04-22 22:11:24 +10:00
Sinai
32e718faeb Bump UniverseLib 2022-04-22 21:31:30 +10:00
Sinai
4d46b74d54 Fix references for rename 2022-04-22 21:04:50 +10:00
Sinai
7e5246cead Recache types when borrowing 2022-04-22 21:04:23 +10:00
Sinai
abf5267364 Fix HookCreator method filtering 2022-04-22 21:03:51 +10:00
Sinai
3afee7254c Fix results TypeCompleter issues 2022-04-22 21:03:33 +10:00
Sinai
1643d4b7dd Allow generic class construction for unbound types 2022-04-22 21:03:11 +10:00
Sinai
cef8c12d20 Fix TryFocusActiveInspector for classes 2022-04-22 21:02:45 +10:00
Sinai
5e07847356 Make current hooks view smaller in height 2022-04-22 21:02:08 +10:00
Sinai
2dc6e386df Fix generated patch code for ref and subclasses 2022-04-22 21:01:47 +10:00
Sinai
ff882296fd Fix for GenericConstructorWidget, adjust UI 2022-04-22 21:01:09 +10:00
Sinai
ecc33927ee Make GenericConstructorWidget reusable 2022-04-22 21:00:18 +10:00
Sinai
6e91f2a792 Hooks: Add support for generic classes and methods 2022-04-22 09:15:51 +10:00
Sinai
97cb14d6fc HookInstance: Clean up generated patch code 2022-04-22 09:12:38 +10:00
Sinai
8b861f7c77 Log Panel: Remove a todo 2022-04-22 09:12:22 +10:00
Sinai
9379e0f813 Fix constraints on AddComponent TypeCompleter 2022-04-22 09:08:49 +10:00
Sinai
bdda12a040 Remove redundant reference to EvaluateWidget 2022-04-22 09:08:17 +10:00
Sinai
75bd654a94 TypeCompleter: Allow generics, support shorthand names 2022-04-22 09:07:51 +10:00
Sinai
f174c7543a C# Console: Fix autocomplete caret deselection 2022-04-22 09:06:52 +10:00
Sinai
08f2c6035e Bump version 2022-04-20 18:47:23 +10:00
Sinai
475e24a66a Update editor package 2022-04-20 18:47:19 +10:00
Sinai
c62b93535d Update position input when Reset button clicked 2022-04-20 18:47:12 +10:00
Sinai
374d0b3bae Bump UniverseLib 2022-04-20 18:46:48 +10:00
Sinai
1f87e89b97 Add some more functionality to Freecam
- Option to use Game's camera
- Button to reset position back to original cam pos
- Free cam position will be stored between stopping/starting free cam
2022-04-19 19:37:05 +10:00
Sinai
495bc41a8d Bump Editor package 2022-04-19 18:06:16 +10:00
Sinai
9cf62c3250 Bump UniverseLib, fix EventSystem issue 2022-04-19 18:05:55 +10:00
Sinai
4c9b3115cd Update UnityEditorPackage 2022-04-19 01:23:11 +10:00
Sinai
ebdce70418 Move instructions 2022-04-19 01:22:25 +10:00
Sinai
7c0b37440b Update UnityEditorPackage 2022-04-19 01:19:04 +10:00
Sinai
0d8ab8bf14 Allow FreeCam to run when menu closed 2022-04-19 01:12:33 +10:00
Sinai
5a3cad9be2 Fix weird Behaviour inheritance issue 2022-04-19 00:57:13 +10:00
Sinai
70d67f1dad Bump version 2022-04-18 21:39:50 +10:00
Sinai
469484d129 Add FreeCam panel 2022-04-18 21:39:17 +10:00
Sinai
c5e262d1c3 Fix UEPanel save data issue 2022-04-18 21:39:11 +10:00
Sinai
53c8dfcb6d Bump UniverseLib 2022-04-18 21:38:49 +10:00
Sinai
ae3ac21992 Add test for Il2CppSystem.Array 2022-04-18 19:12:42 +10:00
Sinai
7765b64748 Make MouseInspector panel just a PanelBase 2022-04-18 19:12:21 +10:00
Sinai
a5023d03f4 Update to UniverseLib 1.3.4 2022-04-18 19:11:39 +10:00
Sinai
a5e6b65dee Add UniverseLib to C# Console default usings 2022-04-18 19:10:24 +10:00
Sinai
c45cd8c1e1 Update editor package 2022-04-14 02:41:18 +10:00
Sinai
e46e24e1af Fix typo 2022-04-14 02:32:01 +10:00
Sinai
3d66493f9c Use UniverseLib PanelBase/PanelDragger 2022-04-14 01:25:59 +10:00
Sinai
7e0f98ef91 Automatic code cleanup (no real changes)
- Use explicit type of var
- Use 'new()'
- Remove unnecessary usings
- Sort usings
- Apply formatting
2022-04-12 05:20:35 +10:00
Sinai
693f5818be Remove duplicate UIManager.Update call 2022-04-12 04:46:04 +10:00
137 changed files with 4626 additions and 4924 deletions

View File

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

View File

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

View File

@ -62,9 +62,7 @@ The inspector is used to see detailed information on objects of any type and man
### Settings
* You can change the settings via the "Options" tab of the menu, or directly from the config file.
* BepInEx: `BepInEx\config\com.sinai.unityexplorer.cfg`
* MelonLoader: `UserData\MelonPreferences.cfg`
* Standalone `{DLL_location}\UnityExplorer\config.cfg`
* <AssetsFolder>/sinai-dev-UnityExplorer~/config.cfg
# Acknowledgments

View File

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

194
build.ps1
View File

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

BIN
lib/ILRepack.exe Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/interop/UnityEngine.dll Normal file

Binary file not shown.

BIN
lib/net6/System.Runtime.dll Normal file

Binary file not shown.

View File

@ -1,15 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using System.Text;
using UnityExplorer.CSConsole.Lexers;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.Utility;
namespace UnityExplorer.CSConsole
{
@ -29,10 +22,23 @@ namespace UnityExplorer.CSConsole
private readonly HashSet<char> delimiters = new()
{
'{', '}', ',', ';', '<', '>', '(', ')', '[', ']', '=', '|', '&', '?'
'{',
'}',
',',
';',
'<',
'>',
'(',
')',
'[',
']',
'=',
'|',
'&',
'?'
};
private readonly List<Suggestion> suggestions = new List<Suggestion>();
private readonly List<Suggestion> suggestions = new();
public void CheckAutocompletes()
{
@ -83,7 +89,7 @@ namespace UnityExplorer.CSConsole
// Get manual namespace completions
foreach (var ns in ReflectionUtility.AllNamespaces)
foreach (string ns in ReflectionUtility.AllNamespaces)
{
if (ns.StartsWith(input))
{
@ -97,7 +103,7 @@ namespace UnityExplorer.CSConsole
// Get manual keyword completions
foreach (var kw in KeywordLexer.keywords)
foreach (string kw in KeywordLexer.keywords)
{
if (kw.StartsWith(input))// && kw.Length > input.Length)
{
@ -121,11 +127,11 @@ namespace UnityExplorer.CSConsole
}
private readonly Dictionary<string, string> namespaceHighlights = new Dictionary<string, string>();
private readonly Dictionary<string, string> namespaceHighlights = new();
private readonly Dictionary<string, string> keywordHighlights = new Dictionary<string, string>();
private readonly Dictionary<string, string> keywordHighlights = new();
private readonly StringBuilder highlightBuilder = new StringBuilder();
private readonly StringBuilder highlightBuilder = new();
private const string OPEN_HIGHLIGHT = "<color=cyan>";
private string GetHighlightString(string prefix, string completion)

View File

@ -1,70 +1,61 @@
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 UniverseLib.Input;
using UnityExplorer.CSConsole;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib;
using UniverseLib.Input;
using UniverseLib.UI.Models;
using UniverseLib.Utility;
using HarmonyLib;
using UniverseLib.Runtime;
using Mono.CSharp;
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);
@ -99,11 +90,11 @@ namespace UnityExplorer.CSConsole
if (!Directory.Exists(ScriptsFolder))
Directory.CreateDirectory(ScriptsFolder);
var startupPath = Path.Combine(ScriptsFolder, "startup.cs");
string startupPath = Path.Combine(ScriptsFolder, "startup.cs");
if (File.Exists(startupPath))
{
ExplorerCore.Log($"Executing startup script from '{startupPath}'...");
var text = File.ReadAllText(startupPath);
string text = File.ReadAllText(startupPath);
Input.Text = text;
Evaluate();
}
@ -114,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);
@ -153,7 +123,7 @@ namespace UnityExplorer.CSConsole
if (Evaluator != null)
Evaluator.Dispose();
GenerateTextWriter();
Evaluator = new ScriptEvaluator(evaluatorStringWriter)
{
@ -161,7 +131,7 @@ namespace UnityExplorer.CSConsole
};
usingDirectives = new HashSet<string>();
foreach (var use in DefaultUsing)
foreach (string use in DefaultUsing)
AddUsing(use);
if (logSuccess)
@ -200,7 +170,7 @@ namespace UnityExplorer.CSConsole
{
// Compile the code. If it returned a CompiledMethod, it is REPL.
CompiledMethod repl = Evaluator.Compile(input);
if (repl != null)
{
// Valid REPL, we have a delegate to the evaluation.
@ -208,7 +178,7 @@ namespace UnityExplorer.CSConsole
{
object ret = null;
repl.Invoke(ref ret);
var result = ret?.ToString();
string result = ret?.ToString();
if (!string.IsNullOrEmpty(result))
ExplorerCore.Log($"Invoked REPL, result: {ret}");
else
@ -222,13 +192,13 @@ namespace UnityExplorer.CSConsole
else
{
// The compiled code was not REPL, so it was a using directive or it defined classes.
string output = Evaluator._textWriter.ToString();
var outputSplit = output.Split('\n');
string[] outputSplit = output.Split('\n');
if (outputSplit.Length >= 2)
output = outputSplit[outputSplit.Length - 2];
evaluatorOutput.Clear();
if (ScriptEvaluator._reportPrinter.ErrorsCount > 0)
throw new FormatException($"Unable to compile the code. Evaluator's last output was:\r\n{output}");
else if (!supressLog)
@ -250,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;
@ -286,7 +288,7 @@ namespace UnityExplorer.CSConsole
DoAutoIndent();
}
var inStringOrComment = HighlightVisibleInput();
HighlightVisibleInput(out bool inStringOrComment);
if (!settingCaretCoroutine)
{
@ -302,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;
@ -359,12 +348,12 @@ namespace UnityExplorer.CSConsole
// If caret moved, ensure caret is visible in the viewport
if (caretMoved)
{
var charInfo = Input.TextGenerator.characters[LastCaretPosition];
var charTop = charInfo.cursorPos.y;
var charBot = charTop - CSCONSOLE_LINEHEIGHT;
UICharInfo charInfo = Input.TextGenerator.characters[LastCaretPosition];
float charTop = charInfo.cursorPos.y;
float charBot = charTop - CSCONSOLE_LINEHEIGHT;
var viewportMin = Input.Transform.rect.height - Input.Transform.anchoredPosition.y - (Input.Transform.rect.height * 0.5f);
var viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
float viewportMin = Input.Transform.rect.height - Input.Transform.anchoredPosition.y - (Input.Transform.rect.height * 0.5f);
float viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
float diff = 0f;
if (charTop > viewportMin)
@ -374,118 +363,101 @@ namespace UnityExplorer.CSConsole
if (Math.Abs(diff) > 1)
{
var rect = Input.Transform;
RectTransform rect = Input.Transform;
rect.anchoredPosition = new Vector2(rect.anchoredPosition.x, rect.anchoredPosition.y - diff);
}
}
}
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()
static IEnumerator DoSetCaretCoroutine(int caretPosition)
{
try
{
foreach (var 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)
{
var color = Input.Component.selectionColor;
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
@ -495,12 +467,12 @@ namespace UnityExplorer.CSConsole
// the top and bottom position of the viewport in relation to the text height
// they need the half-height adjustment to normalize against the 'line.topY' value.
var viewportMin = Input.Transform.rect.height - Input.Transform.anchoredPosition.y - (Input.Transform.rect.height * 0.5f);
var viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
float viewportMin = Input.Transform.rect.height - Input.Transform.anchoredPosition.y - (Input.Transform.rect.height * 0.5f);
float viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
for (int i = 0; i < Input.TextGenerator.lineCount; i++)
{
var line = Input.TextGenerator.lines[i];
UILineInfo line = Input.TextGenerator.lines[i];
// if not set the top line yet, and top of line is below the viewport top
if (topLine == -1 && line.topY <= viewportMin)
topLine = i;
@ -520,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
@ -534,7 +506,7 @@ namespace UnityExplorer.CSConsole
realStartLine++;
char lastPrev = '\n';
var sb = new StringBuilder();
StringBuilder sb = new();
// append leading new lines for spacing (no point rendering line numbers we cant see)
for (int i = 0; i < topLine; i++)
@ -558,7 +530,7 @@ namespace UnityExplorer.CSConsole
Panel.LineNumberText.text = sb.ToString();
return ret;
return;
}
#endregion
@ -598,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)
{
@ -623,7 +593,7 @@ namespace UnityExplorer.CSConsole
}
}
prevContentLen = Input.Text.Length;
previousContentLength = Input.Text.Length;
}
#endregion
@ -631,8 +601,6 @@ namespace UnityExplorer.CSConsole
#region "Help" interaction
private static bool SRENotSupported;
private static void DisableConsole(Exception ex)
{
SRENotSupported = true;
@ -676,7 +644,7 @@ Doorstop example:
public static void SetupHelpInteraction()
{
var drop = Panel.HelpDropdown;
Dropdown drop = Panel.HelpDropdown;
helpDict.Add("Help", "");
helpDict.Add("Usings", HELP_USINGS);
@ -684,7 +652,7 @@ Doorstop example:
helpDict.Add("Classes", HELP_CLASSES);
helpDict.Add("Coroutines", HELP_COROUTINES);
foreach (var opt in helpDict)
foreach (KeyValuePair<string, string> opt in helpDict)
drop.options.Add(new Dropdown.OptionData(opt.Key));
}
@ -693,7 +661,7 @@ Doorstop example:
if (index == 0)
return;
var helpText = helpDict.ElementAt(index);
KeyValuePair<string, string> helpText = helpDict.ElementAt(index);
Input.Text = helpText.Value;
@ -706,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.

View File

@ -1,13 +1,5 @@
using Mono.CSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using System.Text;
using UnityExplorer.CSConsole.Lexers;
using UniverseLib;
using UniverseLib.Utility;
namespace UnityExplorer.CSConsole
{
@ -22,17 +14,15 @@ namespace UnityExplorer.CSConsole
public class LexerBuilder
{
#region Core and initialization
public const char WHITESPACE = ' ';
public readonly HashSet<char> IndentOpenChars = new HashSet<char> { '{', '(' };
public readonly HashSet<char> IndentCloseChars = new HashSet<char> { '}', ')' };
public readonly HashSet<char> IndentOpenChars = new() { '{', '(' };
public readonly HashSet<char> IndentCloseChars = new() { '}', ')' };
private readonly Lexer[] lexers;
private readonly HashSet<char> delimiters = new HashSet<char>();
private readonly HashSet<char> delimiters = new();
private readonly StringLexer stringLexer = new StringLexer();
private readonly CommentLexer commentLexer = new CommentLexer();
private readonly StringLexer stringLexer = new();
private readonly CommentLexer commentLexer = new();
public LexerBuilder()
{
@ -45,7 +35,7 @@ namespace UnityExplorer.CSConsole
new KeywordLexer(),
};
foreach (var matcher in lexers)
foreach (Lexer matcher in lexers)
{
foreach (char c in matcher.Delimiters)
{
@ -55,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>
@ -97,13 +85,13 @@ namespace UnityExplorer.CSConsole
currentStartIdx = startIdx;
currentEndIdx = endIdx;
var sb = new StringBuilder();
StringBuilder sb = new();
for (int i = 0; i < leadingLines; i++)
sb.Append('\n');
int lastUnhighlighted = startIdx;
foreach (var match in GetMatches())
foreach (MatchInfo match in GetMatches())
{
// append non-highlighted text between last match and this
for (int i = lastUnhighlighted; i < match.startIndex; i++)
@ -130,7 +118,7 @@ namespace UnityExplorer.CSConsole
}
// check caretIdx to determine inStringOrComment state
if (caretIdx >= match.startIndex && (caretIdx <= (matchEndIdx+1) || (caretIdx >= input.Length && matchEndIdx >= input.Length - 1)))
if (caretIdx >= match.startIndex && (caretIdx <= (matchEndIdx + 1) || (caretIdx >= input.Length && matchEndIdx >= input.Length - 1)))
caretInStringOrComment = match.isStringOrComment;
}
@ -158,7 +146,7 @@ namespace UnityExplorer.CSConsole
bool anyMatch = false;
int startIndex = CommittedIndex + 1;
foreach (var lexer in lexers)
foreach (Lexer lexer in lexers)
{
if (lexer.TryMatchCurrent(this))
{

View File

@ -1,8 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UnityExplorer.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public class CommentLexer : Lexer
{
@ -13,7 +9,7 @@ namespace UnityExplorer.CSConsole.Lexers
}
// forest green
protected override Color HighlightColor => new Color(0.34f, 0.65f, 0.29f, 1.0f);
protected override Color HighlightColor => new(0.34f, 0.65f, 0.29f, 1.0f);
public override bool TryMatchCurrent(LexerBuilder lexer)
{

View File

@ -1,15 +1,13 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using System.Text;
namespace UnityExplorer.CSConsole.Lexers
{
public class KeywordLexer : Lexer
{
// system blue
protected override Color HighlightColor => new Color(0.33f, 0.61f, 0.83f, 1.0f);
protected override Color HighlightColor => new(0.33f, 0.61f, 0.83f, 1.0f);
public static readonly HashSet<string> keywords = new HashSet<string>
public static readonly HashSet<string> keywords = new()
{
// reserved keywords
"abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue",
@ -28,15 +26,15 @@ namespace UnityExplorer.CSConsole.Lexers
public override bool TryMatchCurrent(LexerBuilder lexer)
{
var prev = lexer.Previous;
var first = lexer.Current;
char prev = lexer.Previous;
char first = lexer.Current;
// check for keywords
if (lexer.IsDelimiter(prev, true) && char.IsLetter(first))
{
// can be a keyword...
var sb = new StringBuilder();
StringBuilder sb = new();
sb.Append(lexer.Current);
while (!lexer.EndOfInput && char.IsLetter(lexer.PeekNext()))
sb.Append(lexer.Current);

View File

@ -1,10 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UniverseLib;
using UniverseLib.Utility;
namespace UnityExplorer.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public abstract class Lexer
{

View File

@ -1,11 +1,9 @@
using UnityEngine;
namespace UnityExplorer.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public class NumberLexer : Lexer
{
// Maroon
protected override Color HighlightColor => new Color(0.58f, 0.33f, 0.33f, 1.0f);
protected override Color HighlightColor => new(0.58f, 0.33f, 0.33f, 1.0f);
private bool IsNumeric(char c) => char.IsNumber(c) || c == '.';

View File

@ -1,14 +1,11 @@
using System.Collections.Generic;
using UnityEngine;
namespace UnityExplorer.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public class StringLexer : Lexer
{
public override IEnumerable<char> Delimiters => new[] { '"', '\'', };
// orange
protected override Color HighlightColor => new Color(0.79f, 0.52f, 0.32f, 1.0f);
protected override Color HighlightColor => new(0.79f, 0.52f, 0.32f, 1.0f);
public override bool TryMatchCurrent(LexerBuilder lexer)
{

View File

@ -1,21 +1,16 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace UnityExplorer.CSConsole.Lexers
namespace UnityExplorer.CSConsole.Lexers
{
public class SymbolLexer : Lexer
{
// silver
protected override Color HighlightColor => new Color(0.6f, 0.6f, 0.6f);
protected override Color HighlightColor => new(0.6f, 0.6f, 0.6f);
// all symbols are delimiters
public override IEnumerable<char> Delimiters => symbols.Where(it => it != '.'); // '.' is not a delimiter, only a separator.
public static bool IsSymbol(char c) => symbols.Contains(c);
public static readonly HashSet<char> symbols = new HashSet<char>
public static readonly HashSet<char> symbols = new()
{
'[', '{', '(', // open
']', '}', ')', // close
@ -33,13 +28,7 @@ namespace UnityExplorer.CSConsole.Lexers
if (IsSymbol(lexer.Current))
{
do
{
lexer.Commit();
lexer.PeekNext();
}
while (IsSymbol(lexer.Current));
lexer.Commit();
return true;
}

View File

@ -1,9 +1,5 @@
using Mono.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using UnityExplorer.Config;
// Thanks to ManlyMarco for this
@ -11,14 +7,17 @@ namespace UnityExplorer.CSConsole
{
public class ScriptEvaluator : Evaluator, IDisposable
{
private static readonly HashSet<string> StdLib = new(StringComparer.InvariantCultureIgnoreCase)
{
"mscorlib", "System.Core", "System", "System.Xml"
};
internal TextWriter _textWriter;
internal static StreamReportPrinter _reportPrinter;
private static readonly HashSet<string> StdLib = new(StringComparer.InvariantCultureIgnoreCase)
{
"mscorlib",
"System.Core",
"System",
"System.Xml"
};
public ScriptEvaluator(TextWriter tw) : base(BuildContext(tw))
{
_textWriter = tw;
@ -45,9 +44,20 @@ namespace UnityExplorer.CSConsole
private void Reference(Assembly asm)
{
var name = asm.GetName().Name;
if (name == "completions")
string name = asm.GetName().Name;
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);
}
@ -55,7 +65,7 @@ namespace UnityExplorer.CSConsole
{
_reportPrinter = new StreamReportPrinter(tw);
var settings = new CompilerSettings
CompilerSettings settings = new()
{
Version = LanguageVersion.Experimental,
GenerateDebugInfo = false,

View File

@ -1,14 +1,8 @@
using HarmonyLib;
using Mono.CSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.Runtime;
using UnityExplorer.UI.Panels;
using UniverseLib;
namespace UnityExplorer.CSConsole
{
@ -29,16 +23,16 @@ namespace UnityExplorer.CSConsole
public static void Inspect(Type type)
=> InspectorManager.Inspect(type);
public static Coroutine Start(IEnumerator ienumerator)
public static Coroutine Start(IEnumerator ienumerator)
=> RuntimeHelper.StartCoroutine(ienumerator);
public static void Stop(Coroutine coro)
=> RuntimeHelper.StopCoroutine(coro);
public static void Copy(object obj)
public static void Copy(object obj)
=> ClipboardPanel.Copy(obj);
public static object Paste()
public static object Paste()
=> ClipboardPanel.Current;
public static void GetUsing()
@ -46,7 +40,7 @@ namespace UnityExplorer.CSConsole
public static void GetVars()
{
var vars = Evaluator.GetVars()?.Trim();
string vars = Evaluator.GetVars()?.Trim();
if (string.IsNullOrEmpty(vars))
ExplorerCore.LogWarning("No variables seem to be defined!");
else
@ -59,12 +53,12 @@ namespace UnityExplorer.CSConsole
.GetValue(Evaluator) is CompilationSourceFile sourceFile
&& sourceFile.Containers.Any())
{
var sb = new StringBuilder();
StringBuilder sb = new();
sb.Append($"There are {sourceFile.Containers.Count} defined classes:");
foreach (TypeDefinition type in sourceFile.Containers.Where(it => it is TypeDefinition))
{
sb.Append($"\n\n{type.MemberName.Name}:");
foreach (var member in type.Members)
foreach (MemberCore member in type.Members)
sb.Append($"\n\t- {member.AttributeTargets}: \"{member.MemberName.Name}\" ({member.ModFlags})");
}
Log(sb.ToString());

View File

@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Config;
using UnityExplorer.CacheObject.Views;
namespace UnityExplorer.CacheObject
{

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityExplorer.Inspectors;
using UniverseLib.Utility;
using UnityExplorer.Inspectors;
namespace UnityExplorer.CacheObject
{
@ -52,7 +46,7 @@ namespace UnityExplorer.CacheObject
Arguments = CtorInfo.GetParameters();
ctorReturnType = CtorInfo.DeclaringType;
}
if (ctorReturnType.IsGenericTypeDefinition)
GenericArguments = ctorReturnType.GetGenericArguments();
}

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityExplorer.Inspectors;
using UnityExplorer.Inspectors;
namespace UnityExplorer.CacheObject
{
@ -31,7 +26,7 @@ namespace UnityExplorer.CacheObject
{
try
{
var ret = FieldInfo.GetValue(DeclaringInstance);
object ret = FieldInfo.GetValue(DeclaringInstance);
LastException = null;
return ret;
}

View File

@ -1,11 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.Views;
using UniverseLib;
using UniverseLib.Utility;
namespace UnityExplorer.CacheObject
{
@ -41,7 +35,7 @@ namespace UnityExplorer.CacheObject
this.DictKey = key;
this.DisplayedKey = key.TryCast();
var type = DisplayedKey.GetType();
Type type = DisplayedKey.GetType();
if (ParseUtility.CanParse(type))
{
KeyInputWanted = true;
@ -60,7 +54,7 @@ namespace UnityExplorer.CacheObject
{
base.SetDataToCell(cell);
var kvpCell = cell as CacheKeyValuePairCell;
CacheKeyValuePairCell kvpCell = cell as CacheKeyValuePairCell;
kvpCell.NameLabel.text = $"{DictIndex}:";
kvpCell.HiddenNameLabel.Text = "";

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.Views;
namespace UnityExplorer.CacheObject
@ -25,7 +21,7 @@ namespace UnityExplorer.CacheObject
{
base.SetDataToCell(cell);
var listCell = cell as CacheListEntryCell;
CacheListEntryCell listCell = cell as CacheListEntryCell;
listCell.NameLabel.text = $"{ListIndex}:";
listCell.HiddenNameLabel.Text = "";

View File

@ -1,21 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityExplorer.Runtime;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Inspectors;
using UniverseLib.UI.Models;
using UnityExplorer.UI;
using UniverseLib;
using UniverseLib.UI;
using UnityExplorer.UI.Widgets;
using UniverseLib.Utility;
using UniverseLib.UI.ObjectPool;
using System.Collections;
using HarmonyLib;
namespace UnityExplorer.CacheObject
{
@ -38,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),
};
@ -105,7 +91,7 @@ namespace UnityExplorer.CacheObject
protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell objectcell)
{
var cell = objectcell as CacheMemberCell;
CacheMemberCell cell = objectcell as CacheMemberCell;
cell.EvaluateHolder.SetActive(!ShouldAutoEvaluate);
if (!ShouldAutoEvaluate)

View File

@ -1,14 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using HarmonyLib;
using UnityExplorer.Inspectors;
using UnityExplorer.Runtime;
using UniverseLib;
using HarmonyLib;
using HarmonyLib.Tools;
namespace UnityExplorer.CacheObject
{
@ -75,8 +67,8 @@ namespace UnityExplorer.CacheObject
return sorted;
}
static void TryCacheMember<T>(MemberInfo member, List<T> list, HashSet<string> cachedSigs,
Type declaringType, ReflectionInspector inspector, bool ignorePropertyMethodInfos = true)
static void TryCacheMember<T>(MemberInfo member, List<T> list, HashSet<string> cachedSigs,
Type declaringType, ReflectionInspector inspector, bool ignorePropertyMethodInfos = true)
where T : CacheMember
{
try

View File

@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityExplorer.Inspectors;
using UniverseLib;
using UniverseLib.Utility;
using UnityExplorer.Inspectors;
namespace UnityExplorer.CacheObject
{
@ -18,7 +11,7 @@ namespace UnityExplorer.CacheObject
public override bool ShouldAutoEvaluate => false;
public CacheMethod (MethodInfo mi)
public CacheMethod(MethodInfo mi)
{
this.MethodInfo = mi;
}
@ -36,14 +29,14 @@ namespace UnityExplorer.CacheObject
{
try
{
var methodInfo = MethodInfo;
MethodInfo methodInfo = MethodInfo;
if (methodInfo.IsGenericMethod)
methodInfo = MethodInfo.MakeGenericMethod(Evaluator.TryParseGenericArguments());
object ret;
if (HasArguments)
ret = methodInfo.Invoke(DeclaringInstance, Evaluator.TryParseArguments());
else
else
ret = methodInfo.Invoke(DeclaringInstance, ArgumentUtility.EmptyArgs);
LastException = null;
return ret;

View File

@ -1,19 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Runtime;
using System.Collections;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.Views;
using UniverseLib.UI.Models;
using UnityExplorer.UI;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.Utility;
using UniverseLib.UI.ObjectPool;
namespace UnityExplorer.CacheObject
@ -36,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)
{
@ -65,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;
@ -94,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
@ -134,22 +123,22 @@ namespace UnityExplorer.CacheObject
protected virtual void ProcessOnEvaluate()
{
var prevState = State;
ValueState prevState = State;
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());
}
@ -171,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))
@ -197,7 +186,7 @@ namespace UnityExplorer.CacheObject
protected string GetValueLabel()
{
string label = "";
string label = string.Empty;
switch (State)
{
@ -214,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}] ";
@ -238,7 +227,7 @@ namespace UnityExplorer.CacheObject
break;
case ValueState.Dictionary:
if (!LastValueWasNull)
if (!valueIsNull)
{
if (Value is IDictionary iDict)
label = $"[{iDict.Count}] ";
@ -276,9 +265,9 @@ namespace UnityExplorer.CacheObject
if (cell.CopyButton != null)
{
bool hasEvaluated = State != ValueState.NotEvaluated && State != ValueState.Exception;
cell.CopyButton.Component.gameObject.SetActive(hasEvaluated);
cell.PasteButton.Component.gameObject.SetActive(hasEvaluated && this.CanWrite);
bool canCopy = State != ValueState.NotEvaluated && State != ValueState.Exception;
cell.CopyButton.Component.gameObject.SetActive(canCopy);
cell.PasteButton.Component.gameObject.SetActive(canCopy && this.CanWrite);
}
if (!evaluated)
@ -299,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));
@ -309,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;
}
@ -341,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);
@ -356,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;
}
@ -365,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));
args.subContentButtonActive
&& (!valueIsNull || State == ValueState.String || State == ValueState.Exception));
}
// CacheObjectCell Apply
@ -381,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);
}
@ -474,12 +463,12 @@ namespace UnityExplorer.CacheObject
public Color valueColor;
public bool valueActive, valueRichText, typeLabelActive, toggleActive, inputActive, applyActive, inspectActive, subContentButtonActive;
public ValueStateArgs(bool valueActive = true,
bool valueRichText = true,
public ValueStateArgs(bool valueActive = true,
bool valueRichText = true,
Color? valueColor = null,
bool typeLabelActive = false,
bool toggleActive = false,
bool inputActive = false,
bool typeLabelActive = false,
bool toggleActive = false,
bool inputActive = false,
bool applyActive = false,
bool inspectActive = false,
bool subContentButtonActive = false)

View File

@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityExplorer.Inspectors;
using UnityExplorer.Runtime;
using UnityExplorer.Inspectors;
namespace UnityExplorer.CacheObject
{

View File

@ -1,9 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.CacheObject;
using System.Collections;
using UnityExplorer.CacheObject.Views;
namespace UnityExplorer.CacheObject
@ -33,7 +28,7 @@ namespace UnityExplorer.CacheObject
return;
}
var entry = (CacheObjectBase)cachedEntries[index];
CacheObjectBase entry = (CacheObjectBase)cachedEntries[index];
if (entry.CellView != null && entry.CellView != cell)
entry.UnlinkFromView();

View File

@ -1,14 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
using UniverseLib.UI;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib;
namespace UnityExplorer.CacheObject.IValues
{
@ -32,9 +23,9 @@ namespace UnityExplorer.CacheObject.IValues
applyButton.Component.gameObject.SetActive(owner.CanWrite);
foreach (var slider in sliders)
foreach (Slider slider in sliders)
slider.interactable = owner.CanWrite;
foreach (var input in inputs)
foreach (InputFieldRef input in inputs)
input.Component.readOnly = !owner.CanWrite;
}
@ -54,7 +45,7 @@ namespace UnityExplorer.CacheObject.IValues
inputs[1].Text = c32.g.ToString();
inputs[2].Text = c32.b.ToString();
inputs[3].Text = c32.a.ToString();
foreach (var slider in sliders)
foreach (Slider slider in sliders)
slider.maxValue = 255;
}
else
@ -65,7 +56,7 @@ namespace UnityExplorer.CacheObject.IValues
inputs[1].Text = EditedColor.g.ToString();
inputs[2].Text = EditedColor.b.ToString();
inputs[3].Text = EditedColor.a.ToString();
foreach (var slider in sliders)
foreach (Slider slider in sliders)
slider.maxValue = 1;
}
@ -156,12 +147,12 @@ namespace UnityExplorer.CacheObject.IValues
// hori group
var horiGroup = UIFactory.CreateHorizontalGroup(UIRoot, "ColorEditor", false, false, true, true, 5,
GameObject horiGroup = UIFactory.CreateHorizontalGroup(UIRoot, "ColorEditor", false, false, true, true, 5,
default, new Color(1, 1, 1, 0), TextAnchor.MiddleLeft);
// sliders / inputs
var grid = UIFactory.CreateGridGroup(horiGroup, "Grid", new Vector2(140, 25), new Vector2(2, 2), new Color(1, 1, 1, 0));
GameObject grid = UIFactory.CreateGridGroup(horiGroup, "Grid", new Vector2(140, 25), new Vector2(2, 2), new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(grid, minWidth: 580, minHeight: 25, flexibleWidth: 0);
for (int i = 0; i < 4; i++)
@ -175,7 +166,7 @@ namespace UnityExplorer.CacheObject.IValues
// image of color
var imgObj = UIFactory.CreateUIObject("ColorImageHelper", horiGroup);
GameObject imgObj = UIFactory.CreateUIObject("ColorImageHelper", horiGroup);
UIFactory.SetLayoutElement(imgObj, minHeight: 25, minWidth: 50, flexibleWidth: 50);
colorImage = imgObj.AddComponent<Image>();
@ -184,18 +175,18 @@ namespace UnityExplorer.CacheObject.IValues
internal void AddEditorRow(int index, GameObject groupObj)
{
var row = UIFactory.CreateHorizontalGroup(groupObj, "EditorRow_" + fieldNames[index],
GameObject row = UIFactory.CreateHorizontalGroup(groupObj, "EditorRow_" + fieldNames[index],
false, true, true, true, 5, default, new Color(1, 1, 1, 0));
var label = UIFactory.CreateLabel(row, "RowLabel", $"{fieldNames[index]}:", TextAnchor.MiddleRight, Color.cyan);
Text label = UIFactory.CreateLabel(row, "RowLabel", $"{fieldNames[index]}:", TextAnchor.MiddleRight, Color.cyan);
UIFactory.SetLayoutElement(label.gameObject, minWidth: 17, flexibleWidth: 0, minHeight: 25);
var input = UIFactory.CreateInputField(row, "Input", "...");
InputFieldRef input = UIFactory.CreateInputField(row, "Input", "...");
UIFactory.SetLayoutElement(input.UIRoot, minWidth: 40, minHeight: 25, flexibleHeight: 0);
inputs[index] = input;
input.OnValueChanged += (string val) => { OnInputChanged(val, index); };
var sliderObj = UIFactory.CreateSlider(row, "Slider", out Slider slider);
GameObject sliderObj = UIFactory.CreateSlider(row, "Slider", out Slider slider);
sliders[index] = slider;
UIFactory.SetLayoutElement(sliderObj, minHeight: 25, minWidth: 70, flexibleWidth: 999, flexibleHeight: 0);
slider.minValue = 0;

View File

@ -1,21 +1,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject;
using System.Collections;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Inspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility;
namespace UnityExplorer.CacheObject.IValues
{
@ -32,7 +19,7 @@ namespace UnityExplorer.CacheObject.IValues
public IDictionary RefIDictionary;
public int ItemCount => cachedEntries.Count;
private readonly List<CacheKeyValuePair> cachedEntries = new List<CacheKeyValuePair>();
private readonly List<CacheKeyValuePair> cachedEntries = new();
public ScrollPool<CacheKeyValuePairCell> DictScrollPool { get; private set; }
@ -61,7 +48,7 @@ namespace UnityExplorer.CacheObject.IValues
{
RefIDictionary = null;
foreach (var entry in cachedEntries)
foreach (CacheKeyValuePair entry in cachedEntries)
{
entry.UnlinkFromView();
entry.ReleasePooledObjects();
@ -80,7 +67,7 @@ namespace UnityExplorer.CacheObject.IValues
}
else
{
var type = value.GetActualType();
Type type = value.GetActualType();
ReflectionUtility.TryGetEntryTypes(type, out KeysType, out ValuesType);
CacheEntries(value);
@ -124,7 +111,7 @@ namespace UnityExplorer.CacheObject.IValues
{
for (int i = cachedEntries.Count - 1; i >= idx; i--)
{
var cache = cachedEntries[i];
CacheKeyValuePair cache = cachedEntries[i];
if (cache.CellView != null)
cache.UnlinkFromView();
@ -153,7 +140,7 @@ namespace UnityExplorer.CacheObject.IValues
RefIDictionary[key] = value;
var entry = cachedEntries[keyIndex];
CacheKeyValuePair entry = cachedEntries[keyIndex];
entry.SetValueFromSource(value);
if (entry.CellView != null)
entry.SetDataToCell(entry.CellView);
@ -177,12 +164,12 @@ namespace UnityExplorer.CacheObject.IValues
public override void SetLayout()
{
var minHeight = 5f;
float minHeight = 5f;
KeyTitleLayout.minWidth = AdjustedWidth * 0.44f;
ValueTitleLayout.minWidth = AdjustedWidth * 0.55f;
foreach (var cell in DictScrollPool.CellPool)
foreach (CacheKeyValuePairCell cell in DictScrollPool.CellPool)
{
SetCellLayout(cell);
if (cell.Enabled)
@ -194,7 +181,7 @@ namespace UnityExplorer.CacheObject.IValues
private void SetCellLayout(CacheObjectCell objcell)
{
var cell = objcell as CacheKeyValuePairCell;
CacheKeyValuePairCell cell = objcell as CacheKeyValuePairCell;
cell.KeyGroupLayout.minWidth = cell.AdjustedWidth * 0.44f;
cell.RightGroupLayout.minWidth = cell.AdjustedWidth * 0.55f;
@ -221,15 +208,15 @@ namespace UnityExplorer.CacheObject.IValues
// key / value titles
var titleGroup = UIFactory.CreateUIObject("TitleGroup", UIRoot);
GameObject titleGroup = UIFactory.CreateUIObject("TitleGroup", UIRoot);
UIFactory.SetLayoutElement(titleGroup, minHeight: 25, flexibleWidth: 9999, flexibleHeight: 0);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(titleGroup, false, true, true, true, padLeft: 65, padRight: 0, childAlignment: TextAnchor.LowerLeft);
var keyTitle = UIFactory.CreateLabel(titleGroup, "KeyTitle", "Keys", TextAnchor.MiddleLeft);
Text keyTitle = UIFactory.CreateLabel(titleGroup, "KeyTitle", "Keys", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(keyTitle.gameObject, minWidth: 100, flexibleWidth: 0);
KeyTitleLayout = keyTitle.GetComponent<LayoutElement>();
var valueTitle = UIFactory.CreateLabel(titleGroup, "ValueTitle", "Values", TextAnchor.MiddleLeft);
Text valueTitle = UIFactory.CreateLabel(titleGroup, "ValueTitle", "Values", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(valueTitle.gameObject, minWidth: 100, flexibleWidth: 0);
ValueTitleLayout = valueTitle.GetComponent<LayoutElement>();

View File

@ -1,17 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
using System.Collections.Specialized;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.Utility;
namespace UnityExplorer.CacheObject.IValues
{
@ -110,7 +101,7 @@ namespace UnityExplorer.CacheObject.IValues
{
try
{
List<string> values = new List<string>();
List<string> values = new();
for (int i = 0; i < CurrentValues.Count; i++)
{
if (flagToggles[i].isOn)
@ -138,11 +129,11 @@ namespace UnityExplorer.CacheObject.IValues
new Color(0.06f, 0.06f, 0.06f));
UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleHeight: 9999, flexibleWidth: 9999);
var hori = UIFactory.CreateUIObject("Hori", UIRoot);
GameObject hori = UIFactory.CreateUIObject("Hori", UIRoot);
UIFactory.SetLayoutElement(hori, minHeight: 25, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(hori, false, false, true, true, 2);
var applyButton = UIFactory.CreateButton(hori, "ApplyButton", "Apply", new Color(0.2f, 0.27f, 0.2f));
ButtonRef applyButton = UIFactory.CreateButton(hori, "ApplyButton", "Apply", new Color(0.2f, 0.27f, 0.2f));
UIFactory.SetLayoutElement(applyButton.Component.gameObject, minHeight: 25, minWidth: 100);
applyButton.OnClick += OnApplyClicked;
@ -192,11 +183,11 @@ namespace UnityExplorer.CacheObject.IValues
private void AddToggleRow()
{
var row = UIFactory.CreateUIObject("ToggleRow", toggleHolder);
GameObject row = UIFactory.CreateUIObject("ToggleRow", toggleHolder);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(row, false, false, true, true, 2);
UIFactory.SetLayoutElement(row, minHeight: 25, flexibleWidth: 9999);
var toggleObj = UIFactory.CreateToggle(row, "ToggleObj", out Toggle toggle, out Text toggleText);
GameObject toggleObj = UIFactory.CreateToggle(row, "ToggleObj", out Toggle toggle, out Text toggleText);
UIFactory.SetLayoutElement(toggleObj, minHeight: 25, flexibleWidth: 9999);
flagToggles.Add(toggle);
@ -205,7 +196,7 @@ namespace UnityExplorer.CacheObject.IValues
#region Enum cache
internal static readonly Dictionary<string, OrderedDictionary> enumCache = new Dictionary<string, OrderedDictionary>();
internal static readonly Dictionary<string, OrderedDictionary> enumCache = new();
internal static OrderedDictionary GetEnumValues(Type enumType)
{
@ -213,13 +204,13 @@ namespace UnityExplorer.CacheObject.IValues
if (!enumCache.ContainsKey(enumType.AssemblyQualifiedName))
{
var dict = new OrderedDictionary();
var addedNames = new HashSet<string>();
OrderedDictionary dict = new();
HashSet<string> addedNames = new();
int i = 0;
foreach (var value in Enum.GetValues(enumType))
foreach (object value in Enum.GetValues(enumType))
{
var name = value.ToString();
string name = value.ToString();
if (addedNames.Contains(name))
continue;
addedNames.Add(name);

View File

@ -1,21 +1,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject;
using System.Collections;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Inspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility;
namespace UnityExplorer.CacheObject.IValues
{
@ -60,7 +47,7 @@ namespace UnityExplorer.CacheObject.IValues
{
RefIList = null;
foreach (var entry in cachedEntries)
foreach (CacheListEntry entry in cachedEntries)
{
entry.UnlinkFromView();
entry.ReleasePooledObjects();
@ -73,9 +60,9 @@ namespace UnityExplorer.CacheObject.IValues
public override void SetLayout()
{
var minHeight = 5f;
float minHeight = 5f;
foreach (var cell in ListScrollPool.CellPool)
foreach (CacheListEntryCell cell in ListScrollPool.CellPool)
{
if (cell.Enabled)
minHeight += cell.Rect.rect.height;
@ -102,7 +89,7 @@ namespace UnityExplorer.CacheObject.IValues
}
else
{
var type = value.GetActualType();
Type type = value.GetActualType();
ReflectionUtility.TryGetEntryType(type, out EntryType);
CacheEntries(value);
@ -132,7 +119,7 @@ namespace UnityExplorer.CacheObject.IValues
while (enumerator.MoveNext())
{
var entry = enumerator.Current;
object entry = enumerator.Current;
// If list count increased, create new cache entries
CacheListEntry cache;
@ -155,7 +142,7 @@ namespace UnityExplorer.CacheObject.IValues
{
for (int i = cachedEntries.Count - 1; i >= idx; i--)
{
var cache = cachedEntries[i];
CacheListEntry cache = cachedEntries[i];
if (cache.CellView != null)
cache.UnlinkFromView();
@ -174,7 +161,7 @@ namespace UnityExplorer.CacheObject.IValues
{
try
{
var type = value.GetType();
Type type = value.GetType();
if (type.GetInterfaces().Any(it => it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IList<>)))
IsWritableGenericIList = !(bool)type.GetProperty("IsReadOnly").GetValue(value, null);
else
@ -184,7 +171,7 @@ namespace UnityExplorer.CacheObject.IValues
{
// Find the "this[int index]" property.
// It might be a private implementation.
foreach (var prop in type.GetProperties(ReflectionUtility.FLAGS))
foreach (PropertyInfo prop in type.GetProperties(ReflectionUtility.FLAGS))
{
if ((prop.Name == "Item"
|| (prop.Name.StartsWith("System.Collections.Generic.IList<") && prop.Name.EndsWith(">.Item")))
@ -226,7 +213,7 @@ namespace UnityExplorer.CacheObject.IValues
genericIndexer.SetValue(CurrentOwner.Value, value, new object[] { index });
}
var entry = cachedEntries[index];
CacheListEntry entry = cachedEntries[index];
entry.SetValueFromSource(value);
if (entry.CellView != null)

View File

@ -1,18 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Config;
using UnityExplorer.CacheObject;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI;
using UnityExplorer.Config;
using UniverseLib.UI;
using UniverseLib;
using UniverseLib.UI.Models;
using UniverseLib.Utility;
namespace UnityExplorer.CacheObject.IValues
{
@ -88,7 +76,7 @@ namespace UnityExplorer.CacheObject.IValues
return;
}
var path = IOUtility.EnsureValidFilePath(SaveFilePath.Text);
string path = IOUtility.EnsureValidFilePath(SaveFilePath.Text);
if (File.Exists(path))
File.Delete(path);
@ -110,10 +98,10 @@ namespace UnityExplorer.CacheObject.IValues
UIFactory.CreateLabel(SaveFileRow, "Info", "<color=red>String is too long! Save to file if you want to see the full string.</color>",
TextAnchor.MiddleLeft);
var horizRow = UIFactory.CreateUIObject("Horiz", SaveFileRow);
GameObject horizRow = UIFactory.CreateUIObject("Horiz", SaveFileRow);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(horizRow, false, false, true, true, 4);
var saveButton = UIFactory.CreateButton(horizRow, "SaveButton", "Save file");
ButtonRef saveButton = UIFactory.CreateButton(horizRow, "SaveButton", "Save file");
UIFactory.SetLayoutElement(saveButton.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 0);
saveButton.OnClick += OnSaveFileClicked;

View File

@ -1,14 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.ObjectPool;
using UniverseLib.UI.ObjectPool;
namespace UnityExplorer.CacheObject.IValues
{

View File

@ -1,16 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.Utility;
namespace UnityExplorer.CacheObject.IValues
{
@ -31,7 +20,7 @@ namespace UnityExplorer.CacheObject.IValues
public void SetValue(object instance, string input, int fieldIndex)
{
var field = Fields[fieldIndex];
FieldInfo field = Fields[fieldIndex];
object val;
if (field.FieldType == typeof(string))
@ -51,8 +40,8 @@ namespace UnityExplorer.CacheObject.IValues
public string GetValue(object instance, int fieldIndex)
{
var field = Fields[fieldIndex];
var value = field.GetValue(instance);
FieldInfo field = Fields[fieldIndex];
object value = field.GetValue(instance);
return ParseUtility.ToStringForInput(value, field.FieldType);
}
}
@ -67,12 +56,12 @@ namespace UnityExplorer.CacheObject.IValues
if (!type.IsValueType || string.IsNullOrEmpty(type.AssemblyQualifiedName) || type.FullName == SYSTEM_VOID)
return false;
if (typeSupportCache.TryGetValue(type.AssemblyQualifiedName, out var info))
if (typeSupportCache.TryGetValue(type.AssemblyQualifiedName, out StructInfo info))
return info.IsSupported;
var supported = false;
bool supported = false;
var fields = type.GetFields(INSTANCE_FLAGS);
FieldInfo[] fields = type.GetFields(INSTANCE_FLAGS);
if (fields.Length > 0)
{
if (fields.Any(it => !ParseUtility.CanParse(it.FieldType)))
@ -100,9 +89,9 @@ namespace UnityExplorer.CacheObject.IValues
private Type lastStructType;
private ButtonRef applyButton;
private readonly List<GameObject> fieldRows = new List<GameObject>();
private readonly List<InputFieldRef> inputFields = new List<InputFieldRef>();
private readonly List<Text> labels = new List<Text>();
private readonly List<GameObject> fieldRows = new();
private readonly List<InputFieldRef> inputFields = new();
private readonly List<Text> labels = new();
public override void OnBorrowed(CacheObjectBase owner)
{
@ -117,7 +106,7 @@ namespace UnityExplorer.CacheObject.IValues
{
RefInstance = value;
var type = RefInstance.GetType();
Type type = RefInstance.GetType();
if (type != lastStructType)
{
@ -177,21 +166,21 @@ namespace UnityExplorer.CacheObject.IValues
private void AddEditorRow()
{
var row = UIFactory.CreateUIObject("HoriGroup", UIRoot);
GameObject row = UIFactory.CreateUIObject("HoriGroup", UIRoot);
//row.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
UIFactory.SetLayoutElement(row, minHeight: 25, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(row, false, false, true, true, 8, childAlignment: TextAnchor.MiddleLeft);
fieldRows.Add(row);
var label = UIFactory.CreateLabel(row, "Label", "notset", TextAnchor.MiddleLeft);
Text label = UIFactory.CreateLabel(row, "Label", "notset", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(label.gameObject, minHeight: 25, minWidth: 50, flexibleWidth: 0);
label.horizontalOverflow = HorizontalWrapMode.Wrap;
labels.Add(label);
var input = UIFactory.CreateInputField(row, "InputField", "...");
InputFieldRef input = UIFactory.CreateInputField(row, "InputField", "...");
UIFactory.SetLayoutElement(input.UIRoot, minHeight: 25, minWidth: 200);
var fitter = input.UIRoot.AddComponent<ContentSizeFitter>();
ContentSizeFitter fitter = input.UIRoot.AddComponent<ContentSizeFitter>();
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
input.Component.lineType = InputField.LineType.MultiLineNewline;

View File

@ -1,13 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.Utility;
using UniverseLib.UI;
namespace UnityExplorer.CacheObject.Views
{
@ -32,7 +23,7 @@ namespace UnityExplorer.CacheObject.Views
// horizontal group
var horiGroup = UIFactory.CreateUIObject("RightHoriGroup", UIRoot);
GameObject horiGroup = UIFactory.CreateUIObject("RightHoriGroup", UIRoot);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(horiGroup, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
UIFactory.SetLayoutElement(horiGroup, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800);
@ -48,7 +39,7 @@ namespace UnityExplorer.CacheObject.Views
// Bool and number value interaction
var toggleObj = UIFactory.CreateToggle(horiGroup, "Toggle", out Toggle, out ToggleText);
GameObject toggleObj = UIFactory.CreateToggle(horiGroup, "Toggle", out Toggle, out ToggleText);
UIFactory.SetLayoutElement(toggleObj, minWidth: 70, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
ToggleText.color = SignatureHighlighter.KeywordBlue;
Toggle.onValueChanged.AddListener(ToggleClicked);
@ -77,7 +68,7 @@ namespace UnityExplorer.CacheObject.Views
SubContentHolder.SetActive(false);
// Bottom separator
var separator = UIFactory.CreateUIObject("BottomSeperator", UIRoot);
GameObject separator = UIFactory.CreateUIObject("BottomSeperator", UIRoot);
UIFactory.SetLayoutElement(separator, minHeight: 1, flexibleHeight: 0, flexibleWidth: 9999);
separator.AddComponent<Image>().color = Color.black;

View File

@ -1,13 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.Inspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
using UnityExplorer.CacheObject.IValues;
using UniverseLib.UI;
using UniverseLib.UI.Models;
@ -24,8 +15,8 @@ namespace UnityExplorer.CacheObject.Views
public InputFieldRef KeyInputField;
public Text KeyInputTypeLabel;
public static Color EvenColor = new Color(0.07f, 0.07f, 0.07f);
public static Color OddColor = new Color(0.063f, 0.063f, 0.063f);
public static Color EvenColor = new(0.07f, 0.07f, 0.07f);
public static Color OddColor = new(0.063f, 0.063f, 0.063f);
public int AdjustedWidth => (int)Rect.rect.width - 70;
@ -40,7 +31,7 @@ namespace UnityExplorer.CacheObject.Views
public override GameObject CreateContent(GameObject parent)
{
var root = base.CreateContent(parent);
GameObject root = base.CreateContent(parent);
Image = root.AddComponent<Image>();
@ -53,7 +44,7 @@ namespace UnityExplorer.CacheObject.Views
this.RightGroupLayout.minWidth = AdjustedWidth * 0.55f;
// Key area
var keyGroup = UIFactory.CreateUIObject("KeyHolder", root.transform.Find("HoriGroup").gameObject);
GameObject keyGroup = UIFactory.CreateUIObject("KeyHolder", root.transform.Find("HoriGroup").gameObject);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(keyGroup, false, false, true, true, 2, 0, 0, 4, 4, childAlignment: TextAnchor.MiddleLeft);
KeyGroupLayout = UIFactory.SetLayoutElement(keyGroup, minHeight: 30, minWidth: (int)(AdjustedWidth * 0.44f), flexibleWidth: 0);

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.IValues;
namespace UnityExplorer.CacheObject.Views
{
@ -13,12 +7,12 @@ namespace UnityExplorer.CacheObject.Views
public Image Image { get; private set; }
public InteractiveList ListOwner => Occupant.Owner as InteractiveList;
public static Color EvenColor = new Color(0.12f, 0.12f, 0.12f);
public static Color OddColor = new Color(0.1f, 0.1f, 0.1f);
public static Color EvenColor = new(0.12f, 0.12f, 0.12f);
public static Color OddColor = new(0.1f, 0.1f, 0.1f);
public override GameObject CreateContent(GameObject parent)
{
var root = base.CreateContent(parent);
GameObject root = base.CreateContent(parent);
Image = root.AddComponent<Image>();

View File

@ -1,12 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI;
using UniverseLib.UI;
using UniverseLib.UI.Models;
namespace UnityExplorer.CacheObject.Views

View File

@ -1,15 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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
{
@ -116,7 +108,7 @@ namespace UnityExplorer.CacheObject.Views
UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600);
UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var horiRow = UIFactory.CreateUIObject("HoriGroup", UIRoot);
GameObject horiRow = UIFactory.CreateUIObject("HoriGroup", UIRoot);
UIFactory.SetLayoutElement(horiRow, minHeight: 29, flexibleHeight: 150, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(horiRow, false, false, true, true, 5, 2, childAlignment: TextAnchor.UpperLeft);
horiRow.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
@ -129,7 +121,7 @@ namespace UnityExplorer.CacheObject.Views
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(NameLabel.gameObject, true, true, true, true);
HiddenNameLabel = UIFactory.CreateInputField(NameLabel.gameObject, "HiddenNameLabel", "");
var hiddenRect = HiddenNameLabel.Component.GetComponent<RectTransform>();
RectTransform hiddenRect = HiddenNameLabel.Component.GetComponent<RectTransform>();
hiddenRect.anchorMin = Vector2.zero;
hiddenRect.anchorMax = Vector2.one;
HiddenNameLabel.Component.readOnly = true;
@ -150,7 +142,7 @@ namespace UnityExplorer.CacheObject.Views
// Right horizontal group
var rightHoriGroup = UIFactory.CreateUIObject("RightHoriGroup", RightGroupContent);
GameObject rightHoriGroup = UIFactory.CreateUIObject("RightHoriGroup", RightGroupContent);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(rightHoriGroup, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
UIFactory.SetLayoutElement(rightHoriGroup, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800);
@ -166,7 +158,7 @@ namespace UnityExplorer.CacheObject.Views
// Bool and number value interaction
var toggleObj = UIFactory.CreateToggle(rightHoriGroup, "Toggle", out Toggle, out ToggleText);
GameObject toggleObj = UIFactory.CreateToggle(rightHoriGroup, "Toggle", out Toggle, out ToggleText);
UIFactory.SetLayoutElement(toggleObj, minWidth: 70, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
ToggleText.color = SignatureHighlighter.KeywordBlue;
Toggle.onValueChanged.AddListener(ToggleClicked);
@ -194,8 +186,8 @@ namespace UnityExplorer.CacheObject.Views
// Copy and Paste buttons
var buttonHolder = UIFactory.CreateHorizontalGroup(rightHoriGroup, "CopyPasteButtons", false, false, true, true, 4,
bgColor: new(1,1,1,0), childAlignment: TextAnchor.MiddleLeft);
GameObject buttonHolder = UIFactory.CreateHorizontalGroup(rightHoriGroup, "CopyPasteButtons", false, false, true, true, 4,
bgColor: new(1, 1, 1, 0), childAlignment: TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(buttonHolder, minWidth: 60, flexibleWidth: 0);
CopyButton = UIFactory.CreateButton(buttonHolder, "CopyButton", "Copy", new Color(0.13f, 0.13f, 0.13f, 1f));
@ -219,7 +211,7 @@ namespace UnityExplorer.CacheObject.Views
SubContentHolder.SetActive(false);
// Bottom separator
var separator = UIFactory.CreateUIObject("BottomSeperator", UIRoot);
GameObject separator = UIFactory.CreateUIObject("BottomSeperator", UIRoot);
UIFactory.SetLayoutElement(separator, minHeight: 1, flexibleHeight: 0, flexibleWidth: 9999);
separator.AddComponent<Image>().color = Color.black;

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UnityExplorer.Config
namespace UnityExplorer.Config
{
public class ConfigElement<T> : IConfigElement
{

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UnityExplorer.Config
namespace UnityExplorer.Config
{
public abstract class ConfigHandler
{

View File

@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.UI;
using UnityExplorer.UI;
namespace UnityExplorer.Config
{
@ -20,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; }
@ -58,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)
@ -77,58 +73,68 @@ 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);
Target_Display = new ConfigElement<int>("Target Display",
Hide_On_Startup = new("Hide On Startup",
"Should UnityExplorer be hidden on startup?",
false);
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);
Hide_On_Startup = new ConfigElement<bool>("Hide On Startup",
"Should UnityExplorer be hidden on startup?",
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);
UI_MouseInspect_Keybind = new("UI Mouse-Inspect Keybind",
"Optional keybind to begin a UI_mode Mouse Inspect.",
UI_MouseInspect_Keybind = new("UI Mouse-Inspect Keybind",
"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;'",

View File

@ -1,6 +1,4 @@
using System;
namespace UnityExplorer.Config
namespace UnityExplorer.Config
{
public interface IConfigElement
{

View File

@ -1,12 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.UI;
using Tomlet;
using Tomlet;
using Tomlet.Models;
using UnityExplorer.UI;
namespace UnityExplorer.Config
{
@ -49,9 +43,12 @@ namespace UnityExplorer.Config
return false;
TomlDocument document = TomlParser.ParseFile(CONFIG_PATH);
foreach (var key in document.Keys)
foreach (string key in document.Keys)
{
var panelKey = (UIManager.Panels)Enum.Parse(typeof(UIManager.Panels), key);
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);
}
@ -69,8 +66,8 @@ namespace UnityExplorer.Config
if (UIManager.Initializing)
return;
var tomlDocument = TomlDocument.CreateEmpty();
foreach (var entry in ConfigManager.InternalConfigs)
TomlDocument tomlDocument = TomlDocument.CreateEmpty();
foreach (KeyValuePair<string, IConfigElement> entry in ConfigManager.InternalConfigs)
tomlDocument.Put(entry.Key, entry.Value.BoxedValue as string, false);
File.WriteAllText(CONFIG_PATH, tomlDocument.SerializedValue);

View File

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.UI;
#if CPP
#if UNHOLLOWER
using UnhollowerRuntimeLib;
#else
using Il2CppInterop.Runtime.Injection;
#endif
#endif
namespace UnityExplorer
@ -14,7 +14,7 @@ namespace UnityExplorer
internal static ExplorerBehaviour Instance { get; private set; }
#if CPP
public ExplorerBehaviour(IntPtr ptr) : base(ptr) { }
public ExplorerBehaviour(System.IntPtr ptr) : base(ptr) { }
#endif
internal static void Setup()
@ -33,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 { }
}
}
}

View File

@ -1,13 +1,17 @@
using System;
using System.IO;
using UnityEngine;
using UnityExplorer.CacheObject;
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
@ -15,7 +19,7 @@ namespace UnityExplorer
public static class ExplorerCore
{
public const string NAME = "UnityExplorer";
public const string VERSION = "4.7.0";
public const string VERSION = "4.9.0";
public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer";
@ -58,8 +62,6 @@ namespace UnityExplorer
// Default delay is 1 second which is usually enough.
static void LateInit()
{
Log($"Setting up late core features...");
SceneHandler.Init();
Log($"Creating UI...");
@ -67,71 +69,19 @@ namespace UnityExplorer
UIManager.InitUI();
Log($"{NAME} {VERSION} ({Universe.Context}) initialized.");
// InspectorManager.Inspect(typeof(Tests.TestClass));
}
internal static void Update()
{
// check master toggle
if (InputManager.GetKeyDown(ConfigManager.Master_Toggle.Value))
{
UIManager.ShowMenu = !UIManager.ShowMenu;
UIManager.Update();
}
// Can be removed eventually. For migration from <4.7.0
static void CheckLegacyExplorerFolder()
{
string legacyPath = Path.Combine(Loader.ExplorerFolderDestination, "UnityExplorer");
if (Directory.Exists(legacyPath))
{
LogWarning($"Attempting to migrate old 'UnityExplorer/' folder to 'sinai-dev-UnityExplorer/'...");
// If new folder doesn't exist yet, let's just use Move().
if (!Directory.Exists(ExplorerFolder))
{
try
{
Directory.Move(legacyPath, ExplorerFolder);
Log("Migrated successfully.");
}
catch (Exception ex)
{
LogWarning($"Exception migrating folder: {ex}");
}
}
else // We have to merge
{
try
{
CopyAll(new(legacyPath), new(ExplorerFolder));
Directory.Delete(legacyPath, true);
Log("Migrated successfully.");
}
catch (Exception ex)
{
LogWarning($"Exception migrating folder: {ex}");
}
}
}
}
public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
// Check if the target directory exists, if not, create it.
if (!Directory.Exists(target.FullName))
Directory.CreateDirectory(target.FullName);
// Copy each file into it's new directory.
foreach (FileInfo fi in source.GetFiles())
fi.MoveTo(Path.Combine(target.ToString(), fi.Name));
// Copy each subdirectory using recursion.
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}
#region LOGGING
@ -177,5 +127,63 @@ namespace UnityExplorer
}
#endregion
#region LEGACY FOLDER MIGRATION
// Can be removed eventually. For migration from <4.7.0
static void CheckLegacyExplorerFolder()
{
string legacyPath = Path.Combine(Loader.ExplorerFolderDestination, "UnityExplorer");
if (Directory.Exists(legacyPath))
{
LogWarning($"Attempting to migrate old 'UnityExplorer/' folder to 'sinai-dev-UnityExplorer/'...");
// If new folder doesn't exist yet, let's just use Move().
if (!Directory.Exists(ExplorerFolder))
{
try
{
Directory.Move(legacyPath, ExplorerFolder);
Log("Migrated successfully.");
}
catch (Exception ex)
{
LogWarning($"Exception migrating folder: {ex}");
}
}
else // We have to merge
{
try
{
CopyAll(new(legacyPath), new(ExplorerFolder));
Directory.Delete(legacyPath, true);
Log("Migrated successfully.");
}
catch (Exception ex)
{
LogWarning($"Exception migrating folder: {ex}");
}
}
}
}
public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
{
Directory.CreateDirectory(target.FullName);
// Copy each file into it's new directory.
foreach (FileInfo fi in source.GetFiles())
fi.MoveTo(Path.Combine(target.ToString(), fi.Name));
// Copy each subdirectory using recursion.
foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
{
DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
CopyAll(diSourceSubDir, nextTargetSubDir);
}
}
#endregion
}
}

View File

@ -1,14 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView;
namespace UnityExplorer.Hooks
@ -23,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()
@ -51,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;

View File

@ -1,12 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UniverseLib.UI;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView;
namespace UnityExplorer.Hooks
@ -29,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)
@ -53,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;
}

333
src/Hooks/HookCreator.cs Normal file
View File

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

View File

@ -1,13 +1,7 @@
using System;
using System.CodeDom.Compiler;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using HarmonyLib;
using HarmonyLib;
using Mono.CSharp;
using System.Text;
using UnityExplorer.CSConsole;
using UniverseLib;
namespace UnityExplorer.Hooks
{
@ -15,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;");
@ -29,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);
@ -60,15 +56,15 @@ namespace UnityExplorer.Hooks
{
Unpatch();
StringBuilder codeBuilder = new();
try
{
patchProcessor = ExplorerCore.Harmony.CreateProcessor(TargetMethod);
// Dynamically compile the patch method
var codeBuilder = new StringBuilder();
codeBuilder.AppendLine($"public class DynamicPatch_{DateTime.Now.Ticks}");
codeBuilder.AppendLine($"static class DynamicPatch_{DateTime.Now.Ticks}");
codeBuilder.AppendLine("{");
codeBuilder.AppendLine(patchSource);
codeBuilder.AppendLine("}");
@ -80,11 +76,11 @@ namespace UnityExplorer.Hooks
// TODO: Publicize MCS to avoid this reflection
// Get the most recent Patch type in the source file
var typeContainer = ((CompilationSourceFile)fi_sourceFile.GetValue(scriptEvaluator))
TypeContainer typeContainer = ((CompilationSourceFile)fi_sourceFile.GetValue(scriptEvaluator))
.Containers
.Last(it => it.MemberName.Name.StartsWith("DynamicPatch_"));
// Get the TypeSpec from the TypeDefinition, then get its "MetaInfo" (System.Type)
var patchClass = ((TypeSpec)pi_Definition.GetValue((Class)typeContainer, null)).GetMetaInfo();
Type patchClass = ((TypeSpec)pi_Definition.GetValue((Class)typeContainer, null)).GetMetaInfo();
// Create the harmony patches as defined
@ -108,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)
{
var codeBuilder = new StringBuilder();
// Arguments
StringBuilder codeBuilder = new();
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");
var parameters = targetMethod.GetParameters();
ParameterInfo[] parameters = targetMethod.GetParameters();
int paramIdx = 0;
foreach (var param in parameters)
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
var logMessage = new StringBuilder();
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 (var param in parameters)
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();
}

90
src/Hooks/HookList.cs Normal file
View File

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

View File

@ -1,231 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Text;
using HarmonyLib;
using UnityEngine;
using UnityExplorer.Runtime;
using UnityExplorer.CSConsole;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UniverseLib;
using UniverseLib.UI.Widgets;
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 HashSet<string>();
private readonly OrderedDictionary currentHooks = new OrderedDictionary();
// adding hooks
private readonly List<MethodInfo> currentAddEligableMethods = new List<MethodInfo>();
private readonly List<MethodInfo> filteredEligableMethods = new List<MethodInfo>();
// hook editor
private readonly LexerBuilder Lexer = new LexerBuilder();
private HookInstance currentEditedHook;
// ~~~~~~~~~~~ Main Current Hooks window ~~~~~~~~~~~
public void EnableOrDisableHookClicked(int index)
{
var hook = (HookInstance)currentHooks[index];
hook.TogglePatch();
Panel.HooksScrollPool.Refresh(true, false);
}
public void DeleteHookClicked(int index)
{
var 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);
var 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;
var 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)
{
var 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 (var 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)
{
var sig = method.FullDescription();
if (hookedSignatures.Contains(sig))
return;
var hook = new HookInstance(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 (var 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;
var method = this.filteredEligableMethods[index];
cell.MethodNameLabel.text = SignatureHighlighter.HighlightMethod(method);
var 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()
{
var 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);
}
}
}
}

View File

@ -1,35 +1,25 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UniverseLib.Input;
using UnityExplorer.UI;
using UniverseLib.UI.Models;
using System.Collections;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI.Widgets;
using UniverseLib.UI;
using UniverseLib;
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;
private readonly List<GameObject> cachedChildren = new List<GameObject>();
private readonly List<GameObject> cachedChildren = new();
public ComponentList ComponentList;
private ScrollPool<ComponentCell> componentScroll;
@ -41,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());
}
@ -77,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();
}
@ -93,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();
@ -118,26 +108,26 @@ 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;
}
private readonly List<Component> componentEntries = new List<Component>();
private readonly HashSet<int> compInstanceIDs = new HashSet<int>();
private readonly List<Behaviour> behaviourEntries = new List<Behaviour>();
private readonly List<bool> behaviourEnabledStates = new List<bool>();
private readonly List<Component> componentEntries = new();
private readonly HashSet<int> compInstanceIDs = new();
private readonly List<Behaviour> behaviourEntries = new();
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();
@ -149,13 +139,13 @@ namespace UnityExplorer.Inspectors
}
// Check if we actually need to refresh the component cells or not.
var comps = GOTarget.GetComponents<Component>();
var behaviours = GOTarget.GetComponents<Behaviour>();
IEnumerable<Component> comps = Target.GetComponents<Component>();
IEnumerable<Behaviour> behaviours = Target.GetComponents<Behaviour>();
bool needRefresh = false;
int count = 0;
foreach (var comp in comps)
foreach (Component comp in comps)
{
if (!comp)
continue;
@ -173,7 +163,7 @@ namespace UnityExplorer.Inspectors
else
{
count = 0;
foreach (var behaviour in behaviours)
foreach (Behaviour behaviour in behaviours)
{
if (!behaviour)
continue;
@ -194,19 +184,35 @@ namespace UnityExplorer.Inspectors
componentEntries.Clear();
compInstanceIDs.Clear();
foreach (var comp in comps)
foreach (Component comp in comps)
{
if (!comp) continue;
if (!comp)
continue;
componentEntries.Add(comp);
compInstanceIDs.Add(comp.GetInstanceID());
}
behaviourEntries.Clear();
behaviourEnabledStates.Clear();
foreach (var behaviour in behaviours)
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);
}
@ -217,8 +223,8 @@ namespace UnityExplorer.Inspectors
private void OnAddChildClicked(string input)
{
var newObject = new GameObject(input);
newObject.transform.parent = GOTarget.transform;
GameObject newObject = new(input);
newObject.transform.parent = Target.transform;
TransformTree.RefreshData(true, false, true, false);
}
@ -229,7 +235,7 @@ namespace UnityExplorer.Inspectors
{
try
{
RuntimeHelper.AddComponent<Component>(GOTarget, type);
RuntimeHelper.AddComponent<Component>(Target, type);
UpdateComponents();
}
catch (Exception ex)
@ -250,14 +256,14 @@ namespace UnityExplorer.Inspectors
UIRoot = UIFactory.CreateVerticalGroup(parent, "GameObjectInspector", true, false, true, true, 5,
new Vector4(4, 4, 4, 4), new Color(0.065f, 0.065f, 0.065f));
var scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out var scrollbar,
GameObject scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out AutoSliderScrollbar scrollbar,
new Color(0.065f, 0.065f, 0.065f));
UIFactory.SetLayoutElement(scrollObj, minHeight: 250, preferredHeight: 300, flexibleHeight: 0, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2);
// Construct GO Controls
GOControls = new GameObjectControls(this);
Controls = new GameObjectControls(this);
ConstructLists();
@ -268,27 +274,27 @@ namespace UnityExplorer.Inspectors
private void ConstructLists()
{
var listHolder = UIFactory.CreateUIObject("ListHolders", UIRoot);
GameObject listHolder = UIFactory.CreateUIObject("ListHolders", UIRoot);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(listHolder, false, true, true, true, 8, 2, 2, 2, 2);
UIFactory.SetLayoutElement(listHolder, minHeight: 150, flexibleWidth: 9999, flexibleHeight: 9999);
// Left group (Children)
var leftGroup = UIFactory.CreateUIObject("ChildrenGroup", listHolder);
GameObject leftGroup = UIFactory.CreateUIObject("ChildrenGroup", listHolder);
UIFactory.SetLayoutElement(leftGroup, flexibleWidth: 9999, flexibleHeight: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(leftGroup, false, false, true, true, 2);
var childrenLabel = UIFactory.CreateLabel(leftGroup, "ChildListTitle", "Children", TextAnchor.MiddleCenter, default, false, 16);
Text childrenLabel = UIFactory.CreateLabel(leftGroup, "ChildListTitle", "Children", TextAnchor.MiddleCenter, default, false, 16);
UIFactory.SetLayoutElement(childrenLabel.gameObject, flexibleWidth: 9999);
// Add Child
var addChildRow = UIFactory.CreateUIObject("AddChildRow", leftGroup);
GameObject addChildRow = UIFactory.CreateUIObject("AddChildRow", leftGroup);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(addChildRow, false, false, true, true, 2);
addChildInput = UIFactory.CreateInputField(addChildRow, "AddChildInput", "Enter a name...");
UIFactory.SetLayoutElement(addChildInput.Component.gameObject, minHeight: 25, preferredWidth: 9999);
var addChildButton = UIFactory.CreateButton(addChildRow, "AddChildButton", "Add Child");
ButtonRef addChildButton = UIFactory.CreateButton(addChildRow, "AddChildButton", "Add Child");
UIFactory.SetLayoutElement(addChildButton.Component.gameObject, minHeight: 25, minWidth: 80);
addChildButton.OnClick += () => { OnAddChildClicked(addChildInput.Text); };
@ -296,35 +302,31 @@ 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)
var rightGroup = UIFactory.CreateUIObject("ComponentGroup", listHolder);
GameObject rightGroup = UIFactory.CreateUIObject("ComponentGroup", listHolder);
UIFactory.SetLayoutElement(rightGroup, flexibleWidth: 9999, flexibleHeight: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(rightGroup, false, false, true, true, 2);
var compLabel = UIFactory.CreateLabel(rightGroup, "CompListTitle", "Components", TextAnchor.MiddleCenter, default, false, 16);
Text compLabel = UIFactory.CreateLabel(rightGroup, "CompListTitle", "Components", TextAnchor.MiddleCenter, default, false, 16);
UIFactory.SetLayoutElement(compLabel.gameObject, flexibleWidth: 9999);
// Add Comp
var addCompRow = UIFactory.CreateUIObject("AddCompRow", rightGroup);
GameObject addCompRow = UIFactory.CreateUIObject("AddCompRow", rightGroup);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(addCompRow, false, false, true, true, 2);
addCompInput = UIFactory.CreateInputField(addCompRow, "AddCompInput", "Enter a Component type...");
UIFactory.SetLayoutElement(addCompInput.Component.gameObject, minHeight: 25, preferredWidth: 9999);
var addCompButton = UIFactory.CreateButton(addCompRow, "AddCompButton", "Add Comp");
ButtonRef addCompButton = UIFactory.CreateButton(addCompRow, "AddCompButton", "Add Comp");
UIFactory.SetLayoutElement(addCompButton.Component.gameObject, minHeight: 25, minWidth: 80);
addCompButton.OnClick += () => { OnAddComponentClicked(addCompInput.Text); };
// comp autocompleter
new TypeCompleter(typeof(Component), addCompInput);
new TypeCompleter(typeof(Component), addCompInput, false, false, false);
// Component List
@ -333,8 +335,10 @@ namespace UnityExplorer.Inspectors
UIFactory.SetLayoutElement(compObj, flexibleHeight: 9999);
UIFactory.SetLayoutElement(compContent, flexibleHeight: 9999);
ComponentList = new ComponentList(componentScroll, GetComponentEntries);
ComponentList.Parent = this;
ComponentList = new ComponentList(componentScroll, GetComponentEntries)
{
Parent = this
};
componentScroll.Initialize(ComponentList);
}

View File

@ -1,697 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UniverseLib.Input;
using UnityExplorer.UI;
using UniverseLib.UI;
using UniverseLib;
using UnityExplorer.UI.Panels;
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
var name = input.Split('/').Last();
var allObjects = RuntimeHelper.FindObjectsOfTypeAll(typeof(GameObject));
var shortList = new List<GameObject>();
foreach (var obj in allObjects)
if (obj.name == name) shortList.Add(obj.TryCast<GameObject>());
foreach (var go in shortList)
{
var 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()
{
var panel = UIManager.GetPanel<UI.Panels.ObjectExplorerPanel>(UIManager.Panels.ObjectExplorer);
panel.SceneExplorer.JumpToTransform(this.Parent.GOTarget.transform);
}
private void OnLayerDropdownChanged(int value)
{
GOTarget.layer = value;
UpdateGameObjectInfo(false, true);
}
private void OnFlagsDropdownChanged(int value)
{
try
{
var 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()
{
var 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)
{
var 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;
}
var 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()
{
var 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)
var 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;
var 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
var titleRow = UIFactory.CreateUIObject("TitleRow", topInfoHolder);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(titleRow, false, false, true, true, 5);
var 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)
var 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
var activeToggleObj = UIFactory.CreateToggle(secondRow, "ActiveSelf", out ActiveSelfToggle, out ActiveSelfText);
UIFactory.SetLayoutElement(activeToggleObj, minHeight: 25, minWidth: 100);
ActiveSelfText.text = "ActiveSelf";
ActiveSelfToggle.onValueChanged.AddListener(OnActiveSelfToggled);
// isStatic
var 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
var 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
var 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
var 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
var 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)
var 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
var explorerBtn = UIFactory.CreateButton(thirdrow, "ExploreBtn", "Show in Explorer", new Color(0.15f, 0.15f, 0.15f));
UIFactory.SetLayoutElement(explorerBtn.Component.gameObject, minHeight: 25, minWidth: 100);
explorerBtn.ButtonText.fontSize = 12;
explorerBtn.OnClick += OnExploreButtonClicked;
// Scene
var sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50);
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
var layerLabel = UIFactory.CreateLabel(thirdrow, "LayerLabel", "Layer:", TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50);
var 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 (var name in layerToNames)
LayerDropdown.options.Add(new Dropdown.OptionData(name));
LayerDropdown.value = 0;
LayerDropdown.RefreshShownValue();
// Flags
var flagsLabel = UIFactory.CreateLabel(thirdrow, "FlagsLabel", "Flags:", TextAnchor.MiddleRight, Color.grey);
UIFactory.SetLayoutElement(flagsLabel.gameObject, minHeight: 25, minWidth: 50);
var 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 (var 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++)
{
var 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>();
var names = Enum.GetValues(typeof(HideFlags));
foreach (HideFlags value in names)
{
hideFlagsValues.Add(value.ToString(), value);
}
}
#endregion
#region Transform Controls UI Construction
private void ConstructTransformControls()
{
var 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)
{
var 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);
var titleLabel = UIFactory.CreateLabel(rowObj, "PositionLabel", title, TextAnchor.MiddleRight, Color.grey);
UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 25, minWidth: 110);
var 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); });
var control = new TransformControl(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)
{
var label = UIFactory.CreateLabel(parent, "Label_" + title, title + ":", TextAnchor.MiddleRight, Color.grey);
UIFactory.SetLayoutElement(label.gameObject, minHeight: 25, minWidth: 30);
var sliderObj = UIFactory.CreateSlider(parent, "Slider_" + title, out var slider);
UIFactory.SetLayoutElement(sliderObj, minHeight: 25, minWidth: 120, flexibleWidth: 0);
slider.m_FillImage.color = Color.clear;
slider.minValue = -1;
slider.maxValue = 1;
var sliderControl = new VectorSlider(axis, slider, control);
slider.onValueChanged.AddListener((float val) =>
{
OnVectorSliderChanged(sliderControl, val);
});
return sliderControl;
}
#endregion
}
}

View File

@ -1,13 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Panels;
using UniverseLib.UI;
using UnityExplorer.UI.Panels;
using UniverseLib.UI.ObjectPool;
namespace UnityExplorer.Inspectors
@ -16,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; }
@ -31,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);

View File

@ -1,18 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject;
using UnityExplorer.Inspectors;
using UniverseLib.UI.Models;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.ObjectPool;
using UniverseLib.Utility;
namespace UnityExplorer
{
@ -27,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;
@ -40,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 (var inspector in Inspectors)
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);
@ -80,7 +85,7 @@ namespace UnityExplorer
}
}
internal static void CloseAllTabs()
public static void CloseAllTabs()
{
if (Inspectors.Any())
{
@ -93,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
{
var inspector = Pool<T>.Borrow();
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);
@ -119,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;
@ -164,7 +168,7 @@ namespace UnityExplorer
{
PanelWidth = width;
foreach (var obj in Inspectors)
foreach (InspectorBase obj in Inspectors)
{
if (obj is ReflectionInspector inspector)
{

View File

@ -1,15 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI;
using UniverseLib;
using UnityExplorer.UI.Panels;
using UniverseLib.UI.ObjectPool;
namespace UnityExplorer.Inspectors

View File

@ -1,19 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UniverseLib.Input;
using UnityExplorer.Runtime;
using UnityExplorer.Config;
using UnityExplorer.Inspectors.MouseInspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UniverseLib;
using UniverseLib.Input;
using UniverseLib.UI;
using UniverseLib.Utility;
using UnityExplorer.Config;
using UniverseLib.UI.Panels;
namespace UnityExplorer.Inspectors
{
@ -23,7 +14,7 @@ namespace UnityExplorer.Inspectors
UI
}
public class MouseInspector : UIPanel
public class MouseInspector : PanelBase
{
public static MouseInspector Instance { get; private set; }
@ -44,22 +35,21 @@ 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;
internal Text mousePosLabel;
public MouseInspector()
public MouseInspector(UIBase owner) : base(owner)
{
Instance = this;
worldInspector = new WorldInspector();
@ -84,11 +74,12 @@ namespace UnityExplorer.Inspectors
CurrentInspector.OnBeginMouseInspect();
PanelDragger.ForceEnd();
PanelManager.ForceEndResize();
UIManager.NavBarRect.gameObject.SetActive(false);
UIManager.PanelHolder.SetActive(false);
UIManager.UiBase.Panels.PanelHolder.SetActive(false);
UIManager.UiBase.SetOnTop();
UIRoot.SetActive(true);
SetActive(true);
}
internal void ClearHitData()
@ -106,9 +97,9 @@ namespace UnityExplorer.Inspectors
Inspecting = false;
UIManager.NavBarRect.gameObject.SetActive(true);
UIManager.PanelHolder.SetActive(true);
UIManager.UiBase.Panels.PanelHolder.SetActive(true);
var drop = InspectorPanel.Instance.MouseInspectDropdown;
Dropdown drop = InspectorPanel.Instance.MouseInspectDropdown;
if (drop.transform.Find("Dropdown List") is Transform list)
drop.DestroyDropdownList(list.gameObject);
@ -119,18 +110,12 @@ 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 (InputManager.GetKeyDown(ConfigManager.UI_MouseInspect_Keybind.Value))
Instance.StartInspect(MouseInspectMode.UI);
if (ConfigManager.World_MouseInspect_Keybind.Value != KeyCode.None)
{
if (InputManager.GetKeyDown(ConfigManager.World_MouseInspect_Keybind.Value))
Instance.StartInspect(MouseInspectMode.World);
}
if (Inspecting)
UpdateInspect();
@ -152,7 +137,7 @@ namespace UnityExplorer.Inspectors
return;
}
var mousePos = InputManager.MousePosition;
Vector3 mousePos = InputManager.MousePosition;
if (mousePos != lastMousePos)
UpdatePosition(mousePos);
@ -181,34 +166,36 @@ namespace UnityExplorer.Inspectors
mousePos.y -= 10;
// calculate and set our UI position
var inversePos = inspectorUIBase.RootObject.transform.InverseTransformPoint(mousePos);
Vector3 inversePos = inspectorUIBase.RootObject.transform.InverseTransformPoint(mousePos);
UIRoot.transform.localPosition = new Vector3(inversePos.x, inversePos.y, 0);
}
// UI Construction
protected internal override void DoSetDefaultPosAndAnchors()
public override void SetDefaultSizeAndPosition()
{
base.SetDefaultSizeAndPosition();
Rect.anchorMin = Vector2.zero;
Rect.anchorMax = Vector2.zero;
Rect.pivot = new Vector2(0.5f, 1);
Rect.sizeDelta = new Vector2(700, 150);
}
public override void ConstructPanelContent()
protected override void ConstructPanelContent()
{
// hide title bar
this.TitleBar.SetActive(false);
this.UIRoot.transform.SetParent(UIManager.UIRoot.transform, false);
var inspectContent = UIFactory.CreateVerticalGroup(this.uiContent, "InspectContent", true, true, true, true, 3, new Vector4(2, 2, 2, 2));
GameObject inspectContent = UIFactory.CreateVerticalGroup(this.ContentRoot, "InspectContent", true, true, true, true, 3, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(inspectContent, flexibleWidth: 9999, flexibleHeight: 9999);
// Title text
var title = UIFactory.CreateLabel(inspectContent,
Text title = UIFactory.CreateLabel(inspectContent,
"InspectLabel",
"<b>Mouse Inspector</b> (press <b>ESC</b> to cancel)",
"<b>Mouse Inspector</b> (press <b>ESC</b> to cancel)",
TextAnchor.MiddleCenter);
UIFactory.SetLayoutElement(title.gameObject, flexibleWidth: 9999);
@ -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);
}
}
}

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace UnityExplorer.Inspectors.MouseInspectors
namespace UnityExplorer.Inspectors.MouseInspectors
{
public abstract class MouseInspectorBase
{

View File

@ -1,29 +1,21 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UniverseLib;
using UniverseLib.Input;
namespace UnityExplorer.Inspectors.MouseInspectors
{
public class UiInspector : MouseInspectorBase
{
public static readonly List<GameObject> LastHitObjects = new List<GameObject>();
public static readonly List<GameObject> LastHitObjects = new();
private static GraphicRaycaster[] graphicRaycasters;
private static readonly List<GameObject> currentHitObjects = new List<GameObject>();
private static readonly List<GameObject> currentHitObjects = new();
private static readonly List<Graphic> wasDisabledGraphics = new List<Graphic>();
private static readonly List<CanvasGroup> wasDisabledCanvasGroups = new List<CanvasGroup>();
private static readonly List<GameObject> objectsAddedCastersTo = new List<GameObject>();
private static readonly List<Graphic> wasDisabledGraphics = new();
private static readonly List<CanvasGroup> wasDisabledCanvasGroups = new();
private static readonly List<GameObject> objectsAddedCastersTo = new();
public override void OnBeginMouseInspect()
{
@ -46,7 +38,7 @@ namespace UnityExplorer.Inspectors.MouseInspectors
IEnumerator SetPanelActiveCoro()
{
yield return null;
var panel = UIManager.GetPanel<MouseInspectorResultsPanel>(UIManager.Panels.UIInspectorResults);
MouseInspectorResultsPanel panel = UIManager.GetPanel<MouseInspectorResultsPanel>(UIManager.Panels.UIInspectorResults);
panel.SetActive(true);
panel.ShowResults();
}
@ -55,28 +47,28 @@ namespace UnityExplorer.Inspectors.MouseInspectors
{
currentHitObjects.Clear();
var ped = new PointerEventData(null)
PointerEventData ped = new(null)
{
position = mousePos
};
foreach (var gr in graphicRaycasters)
foreach (GraphicRaycaster gr in graphicRaycasters)
{
if (!gr || !gr.canvas)
continue;
var list = new List<RaycastResult>();
List<RaycastResult> list = new();
RuntimeHelper.GraphicRaycast(gr, ped, list);
if (list.Count > 0)
{
foreach (var hit in list)
foreach (RaycastResult hit in list)
{
if (hit.gameObject)
currentHitObjects.Add(hit.gameObject);
}
}
}
if (currentHitObjects.Any())
MouseInspector.Instance.objNameLabel.text = $"Click to view UI Objects under mouse: {currentHitObjects.Count}";
else
@ -85,9 +77,9 @@ namespace UnityExplorer.Inspectors.MouseInspectors
private static void SetupUIRaycast()
{
foreach (var obj in RuntimeHelper.FindObjectsOfTypeAll(typeof(Canvas)))
foreach (UnityEngine.Object obj in RuntimeHelper.FindObjectsOfTypeAll(typeof(Canvas)))
{
var canvas = obj.TryCast<Canvas>();
Canvas canvas = obj.TryCast<Canvas>();
if (!canvas || !canvas.enabled || !canvas.gameObject.activeInHierarchy)
continue;
if (!canvas.GetComponent<GraphicRaycaster>())
@ -99,7 +91,7 @@ namespace UnityExplorer.Inspectors.MouseInspectors
}
// recache Graphic Raycasters each time we start
var casters = RuntimeHelper.FindObjectsOfTypeAll(typeof(GraphicRaycaster));
UnityEngine.Object[] casters = RuntimeHelper.FindObjectsOfTypeAll(typeof(GraphicRaycaster));
graphicRaycasters = new GraphicRaycaster[casters.Length];
for (int i = 0; i < casters.Length; i++)
{
@ -107,9 +99,9 @@ namespace UnityExplorer.Inspectors.MouseInspectors
}
// enable raycastTarget on Graphics
foreach (var obj in RuntimeHelper.FindObjectsOfTypeAll(typeof(Graphic)))
foreach (UnityEngine.Object obj in RuntimeHelper.FindObjectsOfTypeAll(typeof(Graphic)))
{
var graphic = obj.TryCast<Graphic>();
Graphic graphic = obj.TryCast<Graphic>();
if (!graphic || !graphic.enabled || graphic.raycastTarget || !graphic.gameObject.activeInHierarchy)
continue;
graphic.raycastTarget = true;
@ -118,9 +110,9 @@ namespace UnityExplorer.Inspectors.MouseInspectors
}
// enable blocksRaycasts on CanvasGroups
foreach (var obj in RuntimeHelper.FindObjectsOfTypeAll(typeof(CanvasGroup)))
foreach (UnityEngine.Object obj in RuntimeHelper.FindObjectsOfTypeAll(typeof(CanvasGroup)))
{
var canvas = obj.TryCast<CanvasGroup>();
CanvasGroup canvas = obj.TryCast<CanvasGroup>();
if (!canvas || !canvas.gameObject.activeInHierarchy || canvas.blocksRaycasts)
continue;
canvas.blocksRaycasts = true;
@ -131,16 +123,16 @@ namespace UnityExplorer.Inspectors.MouseInspectors
public override void OnEndInspect()
{
foreach (var obj in objectsAddedCastersTo)
foreach (GameObject obj in objectsAddedCastersTo)
{
if (obj.GetComponent<GraphicRaycaster>() is GraphicRaycaster raycaster)
GameObject.Destroy(raycaster);
}
foreach (var graphic in wasDisabledGraphics)
foreach (Graphic graphic in wasDisabledGraphics)
graphic.raycastTarget = false;
foreach (var canvas in wasDisabledCanvasGroups)
foreach (CanvasGroup canvas in wasDisabledCanvasGroups)
canvas.blocksRaycasts = false;
objectsAddedCastersTo.Clear();

View File

@ -1,12 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UniverseLib;
using UniverseLib.Utility;
namespace UnityExplorer.Inspectors.MouseInspectors
namespace UnityExplorer.Inspectors.MouseInspectors
{
public class WorldInspector : MouseInspectorBase
{
@ -45,7 +37,7 @@ namespace UnityExplorer.Inspectors.MouseInspectors
return;
}
var ray = MainCamera.ScreenPointToRay(mousePos);
Ray ray = MainCamera.ScreenPointToRay(mousePos);
Physics.Raycast(ray, out RaycastHit hit, 1000f);
if (hit.transform)

View File

@ -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
@ -107,7 +101,7 @@ namespace UnityExplorer.Inspectors
public override void OnReturnToPool()
{
foreach (var member in members)
foreach (CacheMember member in members)
{
member.UnlinkFromView();
member.ReleasePooledObjects();
@ -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
@ -175,7 +179,7 @@ namespace UnityExplorer.Inspectors
scopeFilterButtons[BindingFlags.Default].Component.gameObject.SetActive(!StaticOnly);
scopeFilterButtons[BindingFlags.Instance].Component.gameObject.SetActive(!StaticOnly);
foreach (var toggle in memberTypeToggles)
foreach (Toggle toggle in memberTypeToggles)
toggle.isOn = true;
refreshWanted = true;
@ -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,24 +223,15 @@ 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;
if (flags != scopeFlagsFilter)
{
var btn = scopeFilterButtons[scopeFlagsFilter].Component;
Button btn = scopeFilterButtons[scopeFlagsFilter].Component;
RuntimeHelper.SetColorBlock(btn, disabledButtonColor, disabledButtonColor * 1.3f);
this.scopeFlagsFilter = flags;
@ -245,21 +240,13 @@ namespace UnityExplorer.Inspectors
}
}
private void OnMemberTypeToggled(MemberFilter flag, bool val)
{
if (!val)
MemberFilter &= ~flag;
else
MemberFilter |= flag;
}
private void FilterMembers()
void FilterMembers()
{
filteredMembers.Clear();
for (int i = 0; i < members.Count; i++)
{
var member = members[i];
CacheMember member = members[i];
if (scopeFlagsFilter != BindingFlags.Default)
{
@ -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,14 +268,14 @@ namespace UnityExplorer.Inspectors
}
}
private void UpdateDisplayedMembers()
void UpdateDisplayedMembers()
{
bool shouldRefresh = false;
foreach (var cell in MemberScrollPool.CellPool)
foreach (CacheMemberCell cell in MemberScrollPool.CellPool)
{
if (!cell.Enabled || cell.Occupant == null)
continue;
var member = cell.MemberOccupant;
CacheMember member = cell.MemberOccupant;
if (member.ShouldAutoEvaluate)
{
shouldRefresh = true;
@ -316,17 +303,17 @@ namespace UnityExplorer.Inspectors
{
CalculateLayouts();
foreach (var cell in MemberScrollPool.CellPool)
foreach (CacheMemberCell cell in MemberScrollPool.CellPool)
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
var 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);
var titleHolder = UIFactory.CreateUIObject("TitleHolder", topRow);
GameObject titleHolder = UIFactory.CreateUIObject("TitleHolder", topRow);
UIFactory.SetLayoutElement(titleHolder, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999);
NameText = UIFactory.CreateLabel(titleHolder, "VisibleTitle", "NotSet", TextAnchor.MiddleLeft);
var 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");
var 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);
var copyButton = UIFactory.CreateButton(topRow, "CopyButton", "Copy to Clipboard", new Color(0.2f, 0.2f, 0.2f, 1));
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
var memberBorder = UIFactory.CreateVerticalGroup(mainContentHolder, "ScrollPoolHolder", false, false, true, true, padding: new Vector4(2, 2, 2, 2),
bgColor: new Color(0.05f, 0.05f, 0.05f));
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,29 +489,29 @@ namespace UnityExplorer.Inspectors
// First row
private void ConstructFirstRow(GameObject parent)
void ConstructFirstRow(GameObject parent)
{
var rowObj = UIFactory.CreateUIObject("FirstRow", parent);
GameObject rowObj = UIFactory.CreateUIObject("FirstRow", parent);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(rowObj, true, true, true, true, 5, 2, 2, 2, 2);
UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
var nameLabel = UIFactory.CreateLabel(rowObj, "NameFilterLabel", "Filter names:", TextAnchor.MiddleLeft, Color.grey);
Text nameLabel = UIFactory.CreateLabel(rowObj, "NameFilterLabel", "Filter names:", TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(nameLabel.gameObject, minHeight: 25, minWidth: 90, flexibleWidth: 0);
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); };
var spacer = UIFactory.CreateUIObject("Spacer", rowObj);
GameObject spacer = UIFactory.CreateUIObject("Spacer", rowObj);
UIFactory.SetLayoutElement(spacer, minWidth: 25);
// Update button and toggle
var updateButton = UIFactory.CreateButton(rowObj, "UpdateButton", "Update displayed values", new Color(0.22f, 0.28f, 0.22f));
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;
var toggleObj = UIFactory.CreateToggle(rowObj, "AutoUpdateToggle", out autoUpdateToggle, out Text toggleText);
GameObject toggleObj = UIFactory.CreateToggle(rowObj, "AutoUpdateToggle", out autoUpdateToggle, out Text toggleText);
UIFactory.SetLayoutElement(toggleObj, minWidth: 125, minHeight: 25);
autoUpdateToggle.isOn = false;
toggleText.text = "Auto-update";
@ -441,21 +519,21 @@ namespace UnityExplorer.Inspectors
// Second row
private void ConstructSecondRow(GameObject parent)
void ConstructSecondRow(GameObject parent)
{
var rowObj = UIFactory.CreateUIObject("SecondRow", parent);
GameObject rowObj = UIFactory.CreateUIObject("SecondRow", parent);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(rowObj, false, false, true, true, 5, 2, 2, 2, 2);
UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
// Scope buttons
var scopeLabel = UIFactory.CreateLabel(rowObj, "ScopeLabel", "Scope:", TextAnchor.MiddleLeft, Color.grey);
Text scopeLabel = UIFactory.CreateLabel(rowObj, "ScopeLabel", "Scope:", TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(scopeLabel.gameObject, minHeight: 25, minWidth: 60, flexibleWidth: 0);
AddScopeFilterButton(rowObj, BindingFlags.Default, true);
AddScopeFilterButton(rowObj, BindingFlags.Instance);
AddScopeFilterButton(rowObj, BindingFlags.Static);
var spacer = UIFactory.CreateUIObject("Spacer", rowObj);
GameObject spacer = UIFactory.CreateUIObject("Spacer", rowObj);
UIFactory.SetLayoutElement(spacer, minWidth: 15);
// Member type toggles
@ -466,21 +544,21 @@ 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();
var color = setAsActive ? enabledButtonColor : disabledButtonColor;
Color color = setAsActive ? enabledButtonColor : disabledButtonColor;
var button = UIFactory.CreateButton(parent, "Filter_" + flags, lbl, color);
ButtonRef button = UIFactory.CreateButton(parent, "Filter_" + flags, lbl, color);
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)
{
var toggleObj = UIFactory.CreateToggle(parent, "Toggle_" + type, out Toggle toggle, out Text toggleText);
GameObject toggleObj = UIFactory.CreateToggle(parent, "Toggle_" + type, out Toggle toggle, out Text toggleText);
UIFactory.SetLayoutElement(toggleObj, minHeight: 25, minWidth: width);
string color = type switch
{

View File

@ -1,9 +1,5 @@
#if BIE
using BepInEx.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.Config;
namespace UnityExplorer.Loader.BIE
@ -21,7 +17,7 @@ namespace UnityExplorer.Loader.BIE
public override void RegisterConfigElement<T>(ConfigElement<T> config)
{
var entry = Config.Bind(CTG_NAME, config.Name, config.Value, config.Description);
ConfigEntry<T> entry = Config.Bind(CTG_NAME, config.Name, config.Value, config.Description);
entry.SettingChanged += (object o, EventArgs e) =>
{
@ -47,13 +43,13 @@ namespace UnityExplorer.Loader.BIE
public override void LoadConfig()
{
foreach (var entry in ConfigManager.ConfigElements)
foreach (KeyValuePair<string, IConfigElement> entry in ConfigManager.ConfigElements)
{
var key = entry.Key;
var def = new ConfigDefinition(CTG_NAME, key);
string key = entry.Key;
ConfigDefinition def = new(CTG_NAME, key);
if (Config.ContainsKey(def) && Config[def] is ConfigEntryBase configEntry)
{
var config = entry.Value;
IConfigElement config = entry.Value;
config.BoxedValue = configEntry.BoxedValue;
}
}
@ -61,7 +57,7 @@ namespace UnityExplorer.Loader.BIE
public override void SaveConfig()
{
// not required
Config.Save();
}
}
}

View File

@ -2,19 +2,10 @@
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityExplorer.Config;
using UniverseLib.Input;
using UnityExplorer.Loader.BIE;
#if CPP
using BepInEx.IL2CPP;
using UnhollowerRuntimeLib;
#endif
namespace UnityExplorer
@ -37,15 +28,21 @@ 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;
public Harmony HarmonyInstance => s_harmony;
private static readonly Harmony s_harmony = new(ExplorerCore.GUID);
public string ExplorerFolderName => ExplorerCore.DEFAULT_EXPLORER_FOLDER_NAME;
public string ExplorerFolderDestination => Paths.PluginPath;

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.Config;
using UnityExplorer.Config;
namespace UnityExplorer
{

View File

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

View File

@ -36,7 +36,7 @@ namespace UnityExplorer.Loader.Standalone
protected override void CheckExplorerFolder()
{
if (explorerFolderDest == null)
explorerFolderDest = Application.dataPath;
explorerFolderDest = Path.GetDirectoryName(Application.dataPath);
}
}
}

View File

@ -1,17 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets.ButtonList;
using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility;
namespace UnityExplorer.ObjectExplorer
{
@ -35,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;
@ -73,7 +68,7 @@ namespace UnityExplorer.ObjectExplorer
//var type = ReflectionUtility.GetTypeByName(desiredTypeInput);
if (ReflectionUtility.GetTypeByName(desiredTypeInput) is Type cachedType)
{
var type = cachedType;
Type type = cachedType;
lastTypeCanHaveGameObject = typeof(Component).IsAssignableFrom(type) || type == typeof(GameObject);
sceneFilterRow.SetActive(lastTypeCanHaveGameObject);
childFilterRow.SetActive(lastTypeCanHaveGameObject);
@ -99,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;
@ -135,7 +134,7 @@ namespace UnityExplorer.ObjectExplorer
string text;
if (context == SearchContext.Class)
{
var type = currentResults[index] as Type;
Type type = currentResults[index] as Type;
text = $"{SignatureHighlighter.Parse(type, true)} <color=grey><i>({type.Assembly.GetName().Name})</i></color>";
}
else
@ -164,14 +163,14 @@ namespace UnityExplorer.ObjectExplorer
// Search context row
var contextGroup = UIFactory.CreateHorizontalGroup(uiRoot, "SearchContextRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
GameObject contextGroup = UIFactory.CreateHorizontalGroup(uiRoot, "SearchContextRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(contextGroup, minHeight: 25, flexibleHeight: 0);
var contextLbl = UIFactory.CreateLabel(contextGroup, "SearchContextLabel", "Searching for:", TextAnchor.MiddleLeft);
Text contextLbl = UIFactory.CreateLabel(contextGroup, "SearchContextLabel", "Searching for:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(contextLbl.gameObject, minWidth: 110, flexibleWidth: 0);
var contextDropObj = UIFactory.CreateDropdown(contextGroup, "ContextDropdown", out Dropdown contextDrop, null, 14, OnContextDropdownChanged);
foreach (var name in Enum.GetNames(typeof(SearchContext)))
GameObject contextDropObj = UIFactory.CreateDropdown(contextGroup, "ContextDropdown", out Dropdown contextDrop, null, 14, OnContextDropdownChanged);
foreach (string name in Enum.GetNames(typeof(SearchContext)))
contextDrop.options.Add(new Dropdown.OptionData(name));
UIFactory.SetLayoutElement(contextDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
@ -180,13 +179,15 @@ namespace UnityExplorer.ObjectExplorer
classInputRow = UIFactory.CreateHorizontalGroup(uiRoot, "ClassRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(classInputRow, minHeight: 25, flexibleHeight: 0);
var unityClassLbl = UIFactory.CreateLabel(classInputRow, "ClassLabel", "Class filter:", TextAnchor.MiddleLeft);
Text unityClassLbl = UIFactory.CreateLabel(classInputRow, "ClassLabel", "Class filter:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(unityClassLbl.gameObject, minWidth: 110, flexibleWidth: 0);
var classInputField = UIFactory.CreateInputField(classInputRow, "ClassInput", "...");
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);
@ -196,11 +197,11 @@ namespace UnityExplorer.ObjectExplorer
childFilterRow = UIFactory.CreateHorizontalGroup(uiRoot, "ChildFilterRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(childFilterRow, minHeight: 25, flexibleHeight: 0);
var childLbl = UIFactory.CreateLabel(childFilterRow, "ChildLabel", "Child filter:", TextAnchor.MiddleLeft);
Text childLbl = UIFactory.CreateLabel(childFilterRow, "ChildLabel", "Child filter:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(childLbl.gameObject, minWidth: 110, flexibleWidth: 0);
var childDropObj = UIFactory.CreateDropdown(childFilterRow, "ChildFilterDropdown", out Dropdown childDrop, null, 14, OnChildFilterDropChanged);
foreach (var name in Enum.GetNames(typeof(ChildFilter)))
GameObject childDropObj = UIFactory.CreateDropdown(childFilterRow, "ChildFilterDropdown", out Dropdown childDrop, null, 14, OnChildFilterDropChanged);
foreach (string name in Enum.GetNames(typeof(ChildFilter)))
childDrop.options.Add(new Dropdown.OptionData(name));
UIFactory.SetLayoutElement(childDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
@ -211,11 +212,11 @@ namespace UnityExplorer.ObjectExplorer
sceneFilterRow = UIFactory.CreateHorizontalGroup(uiRoot, "SceneFilterRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(sceneFilterRow, minHeight: 25, flexibleHeight: 0);
var sceneLbl = UIFactory.CreateLabel(sceneFilterRow, "SceneLabel", "Scene filter:", TextAnchor.MiddleLeft);
Text sceneLbl = UIFactory.CreateLabel(sceneFilterRow, "SceneLabel", "Scene filter:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(sceneLbl.gameObject, minWidth: 110, flexibleWidth: 0);
var sceneDropObj = UIFactory.CreateDropdown(sceneFilterRow, "SceneFilterDropdown", out Dropdown sceneDrop, null, 14, OnSceneFilterDropChanged);
foreach (var name in Enum.GetNames(typeof(SceneFilter)))
GameObject sceneDropObj = UIFactory.CreateDropdown(sceneFilterRow, "SceneFilterDropdown", out Dropdown sceneDrop, null, 14, OnSceneFilterDropChanged);
foreach (string name in Enum.GetNames(typeof(SceneFilter)))
{
if (!SceneHandler.DontDestroyExists && name == "DontDestroyOnLoad")
continue;
@ -230,7 +231,7 @@ namespace UnityExplorer.ObjectExplorer
nameInputRow = UIFactory.CreateHorizontalGroup(uiRoot, "NameRow", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(nameInputRow, minHeight: 25, flexibleHeight: 0);
var nameLbl = UIFactory.CreateLabel(nameInputRow, "NameFilterLabel", "Name contains:", TextAnchor.MiddleLeft);
Text nameLbl = UIFactory.CreateLabel(nameInputRow, "NameFilterLabel", "Name contains:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(nameLbl.gameObject, minWidth: 110, flexibleWidth: 0);
nameInputField = UIFactory.CreateInputField(nameInputRow, "NameFilterInput", "...");
@ -238,13 +239,13 @@ namespace UnityExplorer.ObjectExplorer
// Search button
var searchButton = UIFactory.CreateButton(uiRoot, "SearchButton", "Search");
ButtonRef searchButton = UIFactory.CreateButton(uiRoot, "SearchButton", "Search");
UIFactory.SetLayoutElement(searchButton.Component.gameObject, minHeight: 25, flexibleHeight: 0);
searchButton.OnClick += DoSearch;
// Results count label
var resultsCountRow = UIFactory.CreateHorizontalGroup(uiRoot, "ResultsCountRow", true, true, true, true);
GameObject resultsCountRow = UIFactory.CreateHorizontalGroup(uiRoot, "ResultsCountRow", true, true, true, true);
UIFactory.SetLayoutElement(resultsCountRow, minHeight: 25, flexibleHeight: 0);
resultsLabel = UIFactory.CreateLabel(resultsCountRow, "ResultsLabel", "0 results", TextAnchor.MiddleCenter);

View File

@ -1,20 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI;
using UniverseLib;
using System.Collections;
using UniverseLib.Utility;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
namespace UnityExplorer.ObjectExplorer
{
@ -76,7 +66,7 @@ namespace UnityExplorer.ObjectExplorer
this.Parent.SetTab(0);
// select the transform's scene
var go = transform.gameObject;
GameObject go = transform.gameObject;
if (SceneHandler.SelectedScene != go.scene)
{
int idx;
@ -109,7 +99,7 @@ namespace UnityExplorer.ObjectExplorer
if (sceneToDropdownOption.ContainsKey(scene))
{
var opt = sceneToDropdownOption[scene];
Dropdown.OptionData opt = sceneToDropdownOption[scene];
int idx = sceneDropdown.options.IndexOf(opt);
if (sceneDropdown.value != idx)
sceneDropdown.value = idx;
@ -136,7 +126,7 @@ namespace UnityExplorer.ObjectExplorer
sceneToDropdownOption.Clear();
sceneDropdown.options.Clear();
foreach (var scene in loadedScenes)
foreach (Scene scene in loadedScenes)
{
if (sceneToDropdownOption.ContainsKey(scene))
continue;
@ -148,7 +138,7 @@ namespace UnityExplorer.ObjectExplorer
else if (string.IsNullOrEmpty(name))
name = "<untitled>";
var option = new Dropdown.OptionData(name);
Dropdown.OptionData option = new(name);
sceneDropdown.options.Add(option);
sceneToDropdownOption.Add(scene, option);
}
@ -158,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;
@ -167,7 +157,7 @@ namespace UnityExplorer.ObjectExplorer
private void TryLoadScene(LoadSceneMode mode, Dropdown allSceneDrop)
{
var text = allSceneDrop.captionText.text;
string text = allSceneDrop.captionText.text;
if (text == DEFAULT_LOAD_TEXT)
return;
@ -191,18 +181,18 @@ namespace UnityExplorer.ObjectExplorer
// Tool bar (top area)
var toolbar = UIFactory.CreateVerticalGroup(uiRoot, "Toolbar", true, true, true, true, 2, new Vector4(2, 2, 2, 2),
GameObject toolbar = UIFactory.CreateVerticalGroup(uiRoot, "Toolbar", true, true, true, true, 2, new Vector4(2, 2, 2, 2),
new Color(0.15f, 0.15f, 0.15f));
// Scene selector dropdown
var dropRow = UIFactory.CreateHorizontalGroup(toolbar, "DropdownRow", true, true, true, true, 5, default, new Color(1, 1, 1, 0));
GameObject dropRow = UIFactory.CreateHorizontalGroup(toolbar, "DropdownRow", true, true, true, true, 5, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(dropRow, minHeight: 25, flexibleWidth: 9999);
var dropLabel = UIFactory.CreateLabel(dropRow, "SelectorLabel", "Scene:", TextAnchor.MiddleLeft, Color.cyan, false, 15);
Text dropLabel = UIFactory.CreateLabel(dropRow, "SelectorLabel", "Scene:", TextAnchor.MiddleLeft, Color.cyan, false, 15);
UIFactory.SetLayoutElement(dropLabel.gameObject, minHeight: 25, minWidth: 60, flexibleWidth: 0);
var dropdownObj = UIFactory.CreateDropdown(dropRow, "SceneDropdown", out sceneDropdown, "<notset>", 13, OnSceneSelectionDropdownChanged);
GameObject dropdownObj = UIFactory.CreateDropdown(dropRow, "SceneDropdown", out sceneDropdown, "<notset>", 13, OnSceneSelectionDropdownChanged);
UIFactory.SetLayoutElement(dropdownObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
SceneHandler.Update();
@ -211,11 +201,11 @@ namespace UnityExplorer.ObjectExplorer
// Filter row
var filterRow = UIFactory.CreateHorizontalGroup(toolbar, "FilterGroup", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
GameObject filterRow = UIFactory.CreateHorizontalGroup(toolbar, "FilterGroup", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(filterRow, minHeight: 25, flexibleHeight: 0);
//Filter input field
var inputField = UIFactory.CreateInputField(filterRow, "FilterInput", "Search and press enter...");
InputFieldRef inputField = UIFactory.CreateInputField(filterRow, "FilterInput", "Search and press enter...");
inputField.Component.targetGraphic.color = new Color(0.2f, 0.2f, 0.2f);
RuntimeHelper.SetColorBlock(inputField.Component, new Color(0.4f, 0.4f, 0.4f), new Color(0.2f, 0.2f, 0.2f),
new Color(0.08f, 0.08f, 0.08f));
@ -228,11 +218,11 @@ namespace UnityExplorer.ObjectExplorer
refreshRow = UIFactory.CreateHorizontalGroup(toolbar, "RefreshGroup", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(refreshRow, minHeight: 30, flexibleHeight: 0);
var refreshButton = UIFactory.CreateButton(refreshRow, "RefreshButton", "Update");
ButtonRef refreshButton = UIFactory.CreateButton(refreshRow, "RefreshButton", "Update");
UIFactory.SetLayoutElement(refreshButton.Component.gameObject, minWidth: 65, flexibleWidth: 0);
refreshButton.OnClick += UpdateTree;
var refreshToggle = UIFactory.CreateToggle(refreshRow, "RefreshToggle", out Toggle toggle, out Text text);
GameObject refreshToggle = UIFactory.CreateToggle(refreshRow, "RefreshToggle", out Toggle toggle, out Text text);
UIFactory.SetLayoutElement(refreshToggle, flexibleWidth: 9999);
text.text = "Auto-update (1 second)";
text.alignment = TextAnchor.MiddleLeft;
@ -245,24 +235,23 @@ namespace UnityExplorer.ObjectExplorer
// tree labels row
var labelsRow = UIFactory.CreateHorizontalGroup(toolbar, "LabelsRow", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
GameObject labelsRow = UIFactory.CreateHorizontalGroup(toolbar, "LabelsRow", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(labelsRow, minHeight: 30, flexibleHeight: 0);
var nameLabel = UIFactory.CreateLabel(labelsRow, "NameLabel", "Name", TextAnchor.MiddleLeft, color: Color.grey);
Text nameLabel = UIFactory.CreateLabel(labelsRow, "NameLabel", "Name", TextAnchor.MiddleLeft, color: Color.grey);
UIFactory.SetLayoutElement(nameLabel.gameObject, flexibleWidth: 9999, minHeight: 25);
var indexLabel = UIFactory.CreateLabel(labelsRow, "IndexLabel", "Sibling Index", TextAnchor.MiddleLeft, fontSize: 12, color: Color.grey);
Text indexLabel = UIFactory.CreateLabel(labelsRow, "IndexLabel", "Sibling Index", TextAnchor.MiddleLeft, fontSize: 12, color: Color.grey);
UIFactory.SetLayoutElement(indexLabel.gameObject, minWidth: 100, flexibleWidth: 0, minHeight: 25);
// Transform Tree
var scrollPool = UIFactory.CreateScrollPool<TransformCell>(uiRoot, "TransformTree", out GameObject scrollObj,
UniverseLib.UI.Widgets.ScrollView.ScrollPool<TransformCell> scrollPool = UIFactory.CreateScrollPool<TransformCell>(uiRoot, "TransformTree", out GameObject scrollObj,
out GameObject scrollContent, new Color(0.11f, 0.11f, 0.11f));
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;
@ -274,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()
{
@ -294,7 +285,7 @@ namespace UnityExplorer.ObjectExplorer
allSceneDropdown.options.Clear();
allSceneDropdown.options.Add(new Dropdown.OptionData(DEFAULT_LOAD_TEXT));
foreach (var scene in SceneHandler.AllSceneNames)
foreach (string scene in SceneHandler.AllSceneNames)
{
if (string.IsNullOrEmpty(filter) || scene.ContainsIgnoreCase(filter))
allSceneDropdown.options.Add(new Dropdown.OptionData(Path.GetFileNameWithoutExtension(scene)));
@ -308,7 +299,7 @@ namespace UnityExplorer.ObjectExplorer
private void RefreshSceneLoaderButtons()
{
var text = allSceneDropdown.captionText.text;
string text = allSceneDropdown.captionText.text;
if (text == DEFAULT_LOAD_TEXT)
{
loadButton.Component.interactable = false;
@ -328,30 +319,30 @@ namespace UnityExplorer.ObjectExplorer
{
if (SceneHandler.WasAbleToGetScenesInBuild)
{
var sceneLoaderObj = UIFactory.CreateVerticalGroup(uiRoot, "SceneLoader", true, true, true, true);
GameObject sceneLoaderObj = UIFactory.CreateVerticalGroup(uiRoot, "SceneLoader", true, true, true, true);
UIFactory.SetLayoutElement(sceneLoaderObj, minHeight: 25);
// Title
var loaderTitle = UIFactory.CreateLabel(sceneLoaderObj, "SceneLoaderLabel", "Scene Loader", TextAnchor.MiddleLeft, Color.white, true, 14);
Text loaderTitle = UIFactory.CreateLabel(sceneLoaderObj, "SceneLoaderLabel", "Scene Loader", TextAnchor.MiddleLeft, Color.white, true, 14);
UIFactory.SetLayoutElement(loaderTitle.gameObject, minHeight: 25, flexibleHeight: 0);
// Search filter
var searchFilterObj = UIFactory.CreateInputField(sceneLoaderObj, "SearchFilterInput", "Filter scene names...");
InputFieldRef searchFilterObj = UIFactory.CreateInputField(sceneLoaderObj, "SearchFilterInput", "Filter scene names...");
UIFactory.SetLayoutElement(searchFilterObj.UIRoot, minHeight: 25, flexibleHeight: 0);
searchFilterObj.OnValueChanged += RefreshSceneLoaderOptions;
// Dropdown
var allSceneDropObj = UIFactory.CreateDropdown(sceneLoaderObj, "SceneLoaderDropdown", out allSceneDropdown, "", 14, null);
GameObject allSceneDropObj = UIFactory.CreateDropdown(sceneLoaderObj, "SceneLoaderDropdown", out allSceneDropdown, "", 14, null);
UIFactory.SetLayoutElement(allSceneDropObj, minHeight: 25, minWidth: 150, flexibleWidth: 0, flexibleHeight: 0);
RefreshSceneLoaderOptions(string.Empty);
// Button row
var buttonRow = UIFactory.CreateHorizontalGroup(sceneLoaderObj, "LoadButtons", true, true, true, true, 4);
GameObject buttonRow = UIFactory.CreateHorizontalGroup(sceneLoaderObj, "LoadButtons", true, true, true, true, 4);
loadButton = UIFactory.CreateButton(buttonRow, "LoadSceneButton", "Load (Single)", new Color(0.1f, 0.3f, 0.3f));
UIFactory.SetLayoutElement(loadButton.Component.gameObject, minHeight: 25, minWidth: 150);
@ -367,7 +358,7 @@ namespace UnityExplorer.ObjectExplorer
TryLoadScene(LoadSceneMode.Additive, allSceneDropdown);
};
var disabledColor = new Color(0.24f, 0.24f, 0.24f);
Color disabledColor = new(0.24f, 0.24f, 0.24f);
RuntimeHelper.SetColorBlock(loadButton.Component, disabled: disabledColor);
RuntimeHelper.SetColorBlock(loadAdditiveButton.Component, disabled: disabledColor);

View File

@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UniverseLib;
using UnityEngine.SceneManagement;
namespace UnityExplorer.ObjectExplorer
{
@ -65,11 +58,11 @@ namespace UnityExplorer.ObjectExplorer
if (sceneUtil == null)
throw new Exception("This version of Unity does not ship with the 'SceneUtility' class, or it was not unstripped.");
var method = sceneUtil.GetMethod("GetScenePathByBuildIndex", ReflectionUtility.FLAGS);
System.Reflection.MethodInfo method = sceneUtil.GetMethod("GetScenePathByBuildIndex", ReflectionUtility.FLAGS);
int sceneCount = SceneManager.sceneCountInBuildSettings;
for (int i = 0; i < sceneCount; i++)
{
var scenePath = (string)method.Invoke(null, new object[] { i });
string scenePath = (string)method.Invoke(null, new object[] { i });
AllSceneNames.Add(scenePath);
}
@ -85,9 +78,9 @@ namespace UnityExplorer.ObjectExplorer
internal static void Update()
{
// Inspected scene will exist if it's DontDestroyOnLoad or HideAndDontSave
bool inspectedExists =
SelectedScene.HasValue
&& ((DontDestroyExists && SelectedScene.Value.handle == -12)
bool inspectedExists =
SelectedScene.HasValue
&& ((DontDestroyExists && SelectedScene.Value.handle == -12)
|| SelectedScene.Value.handle == -1);
LoadedScenes.Clear();
@ -121,11 +114,11 @@ namespace UnityExplorer.ObjectExplorer
CurrentRootObjects = RuntimeHelper.GetRootGameObjects((Scene)SelectedScene);
else
{
var allObjects = RuntimeHelper.FindObjectsOfTypeAll(typeof(GameObject));
var objects = new List<GameObject>();
foreach (var obj in allObjects)
UnityEngine.Object[] allObjects = RuntimeHelper.FindObjectsOfTypeAll(typeof(GameObject));
List<GameObject> objects = new();
foreach (UnityEngine.Object obj in allObjects)
{
var go = obj.TryCast<GameObject>();
GameObject go = obj.TryCast<GameObject>();
if (go.transform.parent == null && !go.scene.IsValid())
objects.Add(go);
}

View File

@ -1,14 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityExplorer.Runtime;
using UniverseLib;
using UniverseLib.Input;
using UniverseLib.Utility;
using UnityEngine.SceneManagement;
namespace UnityExplorer.ObjectExplorer
{
@ -50,7 +40,7 @@ namespace UnityExplorer.ObjectExplorer
internal static List<object> UnityObjectSearch(string input, string customTypeInput, ChildFilter childFilter, SceneFilter sceneFilter)
{
var results = new List<object>();
List<object> results = new();
Type searchType = null;
if (!string.IsNullOrEmpty(customTypeInput))
@ -69,7 +59,7 @@ namespace UnityExplorer.ObjectExplorer
if (searchType == null)
searchType = typeof(UnityEngine.Object);
var allObjects = RuntimeHelper.FindObjectsOfTypeAll(searchType);
UnityEngine.Object[] allObjects = RuntimeHelper.FindObjectsOfTypeAll(searchType);
// perform filter comparers
@ -79,14 +69,14 @@ namespace UnityExplorer.ObjectExplorer
bool shouldFilterGOs = searchType == typeof(GameObject) || typeof(Component).IsAssignableFrom(searchType);
foreach (var obj in allObjects)
foreach (UnityEngine.Object obj in allObjects)
{
// name check
if (!string.IsNullOrEmpty(nameFilter) && !obj.name.ContainsIgnoreCase(nameFilter))
continue;
GameObject go = null;
var type = obj.GetActualType();
Type type = obj.GetActualType();
if (type == typeof(GameObject))
go = obj.TryCast<GameObject>();
@ -130,15 +120,15 @@ namespace UnityExplorer.ObjectExplorer
internal static List<object> ClassSearch(string input)
{
var list = new List<object>();
List<object> list = new();
var nameFilter = "";
string nameFilter = "";
if (!string.IsNullOrEmpty(input))
nameFilter = input;
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in asm.TryGetTypes())
foreach (Type type in asm.GetTypes())
{
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ContainsIgnoreCase(nameFilter))
continue;
@ -165,30 +155,30 @@ namespace UnityExplorer.ObjectExplorer
internal static List<object> InstanceSearch(string input)
{
var instances = new List<object>();
List<object> instances = new();
var nameFilter = "";
string nameFilter = "";
if (!string.IsNullOrEmpty(input))
nameFilter = input;
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
// Search all non-static, non-enum classes.
foreach (var 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
{
if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ContainsIgnoreCase(nameFilter))
continue;
ReflectionUtility.FindSingleton(instanceNames, type, flags, instances);
}
catch { }
}
}
return instances;
}

View File

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

View File

@ -1,5 +1,4 @@
#if MONO
using UnityEngine;
namespace UnityExplorer.Runtime
{

View File

@ -1,15 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Config;
using UniverseLib;
using UnityExplorer.Config;
namespace UnityExplorer.Runtime
{
@ -20,7 +9,7 @@ namespace UnityExplorer.Runtime
public static UERuntimeHelper Instance;
public static void Init()
{
{
#if CPP
Instance = new Il2CppHelper();
#else
@ -50,10 +39,10 @@ namespace UnityExplorer.Runtime
try
{
var sigs = blacklist.Split(';');
foreach (var sig in sigs)
string[] sigs = blacklist.Split(';');
foreach (string sig in sigs)
{
var s = sig.Trim();
string s = sig.Trim();
if (string.IsNullOrEmpty(s))
continue;
if (!currentBlacklist.Contains(s))
@ -65,7 +54,7 @@ namespace UnityExplorer.Runtime
ExplorerCore.LogWarning($"Exception parsing blacklist string: {ex.ReflectionExToString()}");
}
foreach (var sig in Instance.DefaultReflectionBlacklist)
foreach (string sig in Instance.DefaultReflectionBlacklist)
{
if (!currentBlacklist.Contains(sig))
currentBlacklist.Add(sig);
@ -84,7 +73,7 @@ namespace UnityExplorer.Runtime
if (string.IsNullOrEmpty(member.DeclaringType?.Namespace))
return false;
var sig = $"{member.DeclaringType.FullName}.{member.Name}";
string sig = $"{member.DeclaringType.FullName}.{member.Name}";
return currentBlacklist.Contains(sig);
}

View File

@ -1,16 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityExplorer.CacheObject;
namespace UnityExplorer.Runtime
namespace UnityExplorer.Runtime
{
internal static class UnityCrashPrevention
{
static readonly HarmonyLib.Harmony harmony = new ($"{ExplorerCore.GUID}.crashprevention");
static readonly HarmonyLib.Harmony harmony = new($"{ExplorerCore.GUID}.crashprevention");
internal static void Init()
{
@ -27,7 +19,7 @@ namespace UnityExplorer.Runtime
try
{
harmony.Patch(
HarmonyLib.AccessTools.Method(typeof(T), orig, argTypes),
HarmonyLib.AccessTools.Method(typeof(T), orig, argTypes),
new HarmonyLib.HarmonyMethod(HarmonyLib.AccessTools.Method(typeof(UnityCrashPrevention), prefix)));
}
catch //(Exception ex)

View File

@ -1,16 +1,13 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityExplorer.UI;
using UnityExplorer.CacheObject.IValues;
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
{
@ -74,7 +71,7 @@ namespace UnityExplorer.Tests
{
get
{
var list = new List<object>();
List<object> list = new();
int count = UnityEngine.Random.Range(0, 100);
for (int i = 0; i < count; i++)
list.Add(GetRandomObject());
@ -178,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;
@ -191,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");
@ -209,12 +210,12 @@ namespace UnityExplorer.Tests
IL2CPP_HashTable.Add("key3", "value3");
ExplorerCore.Log($"IL2CPP 3: Il2Cpp IDictionary");
var dict2 = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
Il2CppSystem.Collections.Generic.Dictionary<string, string> dict2 = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
dict2.Add("key1", "value1");
IL2CPP_IDict = dict2.TryCast<Il2CppSystem.Collections.IDictionary>();
ExplorerCore.Log($"IL2CPP 4: Il2Cpp List of Il2Cpp Object");
var list = new Il2CppSystem.Collections.Generic.List<Il2CppSystem.Object>(5);
Il2CppSystem.Collections.Generic.List<Il2CppSystem.Object> list = new Il2CppSystem.Collections.Generic.List<Il2CppSystem.Object>(5);
list.Add("one");
list.Add("two");
IL2CPP_IList = list.TryCast<Il2CppSystem.Collections.IList>();
@ -240,14 +241,14 @@ namespace UnityExplorer.Tests
// boxed enum test
try
{
var cppType = Il2CppType.Of<CameraClearFlags>();
if (cppType != null)
Il2CppSystem.Type cppType = Il2CppType.Of<CameraClearFlags>();
if (cppType is not null)
{
var boxedEnum = Il2CppSystem.Enum.Parse(cppType, "Color");
Il2CppSystem.Object boxedEnum = Il2CppSystem.Enum.Parse(cppType, "Color");
IL2CPP_listOfBoxedObjects.Add(boxedEnum);
}
var structBox = Vector3.one.BoxIl2CppObject();
Il2CppSystem.Object structBox = Vector3.one.BoxIl2CppObject();
IL2CPP_listOfBoxedObjects.Add(structBox);
}
@ -257,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;
@ -265,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";

View File

@ -1,11 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using System.Collections;
using UnityExplorer.Config;
using UniverseLib;
using UniverseLib.Input;
namespace UnityExplorer.UI
@ -45,7 +39,7 @@ namespace UnityExplorer.UI
ConfigManager.Target_Display.Value = 0;
return;
}
}
ActiveDisplayIndex = display;
ActiveDisplay.Activate();
@ -72,7 +66,7 @@ namespace UnityExplorer.UI
yield return null;
yield return null;
foreach (var panel in UIManager.UIPanels.Values)
foreach (Panels.UEPanel panel in UIManager.UIPanels.Values)
{
panel.EnsureValidSize();
panel.EnsureValidPosition();

15
src/UI/ExplorerUIBase.cs Normal file
View File

@ -0,0 +1,15 @@
using UniverseLib.UI;
using UniverseLib.UI.Panels;
namespace UnityExplorer.UI
{
internal class ExplorerUIBase : UIBase
{
public ExplorerUIBase(string id, Action updateMethod) : base(id, updateMethod) { }
protected override PanelManager CreatePanelManager()
{
return new UEPanelManager(this);
}
}
}

View File

@ -1,11 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UniverseLib.Input;
using UniverseLib.UI;
using UniverseLib.UI;
namespace UnityExplorer.UI
{
@ -44,11 +37,10 @@ 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>();
var popupGroup = popupLabel.gameObject.AddComponent<CanvasGroup>();
CanvasGroup popupGroup = popupLabel.gameObject.AddComponent<CanvasGroup>();
popupGroup.blocksRaycasts = false;
}
}

View File

@ -1,35 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.Input;
using UnityExplorer.Runtime;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UniverseLib.UI.Widgets;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets.ButtonList;
using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility;
using UniverseLib.UI.Models;
namespace UnityExplorer.UI.Widgets.AutoComplete
namespace UnityExplorer.UI.Panels
{
// Shared modal panel for "AutoComplete" suggestions.
// A data source implements ISuggestionProvider and uses TakeOwnership and ReleaseOwnership
// for control, and SetSuggestions to set the actual suggestion data.
public class AutoCompleteModal : UIPanel
public class AutoCompleteModal : UEPanel
{
public static AutoCompleteModal Instance => UIManager.GetPanel<AutoCompleteModal>(UIManager.Panels.AutoCompleter);
public override string Name => "AutoCompleter";
public override UIManager.Panels PanelType => UIManager.Panels.AutoCompleter;
public override int MinWidth => -1;
public override int MinHeight => -1;
public override int MinWidth => 100;
public override int MinHeight => 25;
public override Vector2 DefaultAnchorMin => new(MIN_X, 0.4f);
public override Vector2 DefaultAnchorMax => new(0.68f, MAX_Y);
const float MIN_X = 0.42f;
const float MAX_Y = 0.6f;
public override bool CanDragAndResize => true;
public override bool ShouldSaveActiveState => false;
@ -48,10 +42,10 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
public static bool Suggesting(ISuggestionProvider handler) => CurrentHandler == handler && Instance.UIRoot.activeSelf;
public AutoCompleteModal()
public AutoCompleteModal(UIBase owner) : base(owner)
{
OnPanelsReordered += UIPanel_OnPanelsReordered;
OnClickedOutsidePanels += AutoCompleter_OnClickedOutsidePanels;
UIManager.UiBase.Panels.OnPanelsReordered += UIPanel_OnPanelsReordered;
UIManager.UiBase.Panels.OnClickedOutsidePanels += AutoCompleter_OnClickedOutsidePanels;
}
public static void TakeOwnership(ISuggestionProvider provider)
@ -67,15 +61,22 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
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);
@ -84,7 +85,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
base.UIRoot.SetActive(true);
base.UIRoot.transform.SetAsLastSibling();
buttonListDataHandler.RefreshData();
scrollPool.Refresh(true, true);
scrollPool.Refresh(true, jumpToTop);
}
}
@ -184,7 +185,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
private void OnCellClicked(int dataIndex)
{
var suggestion = Suggestions[dataIndex];
Suggestion suggestion = Suggestions[dataIndex];
CurrentHandler.OnSuggestionClicked(suggestion);
}
@ -192,13 +193,19 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
private void SetCell(ButtonCell cell, int index)
{
if (CurrentHandler == null)
{
UIRoot.SetActive(false);
return;
}
if (index < 0 || index >= Suggestions.Count)
{
cell.Disable();
return;
}
var suggestion = Suggestions[index];
Suggestion suggestion = Suggestions[index];
cell.Button.ButtonText.text = suggestion.DisplayText;
if (CurrentHandler.AllowNavigation && index == SelectedIndex && setFirstCell)
@ -223,14 +230,19 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
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)
{
var textGen = input.Component.cachedInputTextGenerator;
if (!input.Component.isFocused)
return;
TextGenerator textGen = input.Component.cachedInputTextGenerator;
int caretIdx = Math.Max(0, Math.Min(textGen.characterCount - 1, input.Component.caretPosition));
// normalize the caret horizontal position
@ -246,6 +258,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
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();
}
@ -267,7 +282,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
if (!this.UIRoot || !this.UIRoot.activeInHierarchy)
return;
if (this.UIRoot.transform.GetSiblingIndex() != UIManager.PanelHolder.transform.childCount - 1)
if (this.UIRoot.transform.GetSiblingIndex() != UIManager.UiBase.Panels.PanelHolder.transform.childCount - 1)
{
if (CurrentHandler != null)
ReleaseOwnership(CurrentHandler);
@ -276,46 +291,36 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
}
}
// UI Construction
const float MIN_X = 0.42f;
const float MAX_Y = 0.6f;
protected internal override void DoSetDefaultPosAndAnchors()
public override void OnFinishResize()
{
Rect.pivot = new Vector2(0f, 1f);
Rect.anchorMin = new Vector2(MIN_X, 0.4f);
Rect.anchorMax = new Vector2(0.68f, MAX_Y);
}
public override void OnFinishResize(RectTransform panel)
{
float xDiff = panel.anchorMin.x - MIN_X;
float yDiff = panel.anchorMax.y - MAX_Y;
float xDiff = Rect.anchorMin.x - MIN_X;
float yDiff = Rect.anchorMax.y - MAX_Y;
if (xDiff != 0 || yDiff != 0)
{
panel.anchorMin = new(MIN_X, panel.anchorMin.y - yDiff);
panel.anchorMax = new(panel.anchorMax.x - xDiff, MAX_Y);
Rect.anchorMin = new(MIN_X, Rect.anchorMin.y - yDiff);
Rect.anchorMax = new(Rect.anchorMax.x - xDiff, MAX_Y);
}
base.OnFinishResize(panel);
base.OnFinishResize();
}
public override void ConstructPanelContent()
// UI Construction
protected override void ConstructPanelContent()
{
// hide the titlebar
this.TitleBar.gameObject.SetActive(false);
buttonListDataHandler = new ButtonListHandler<Suggestion, ButtonCell>(scrollPool, GetEntries, SetCell, ShouldDisplay, OnCellClicked);
scrollPool = UIFactory.CreateScrollPool<ButtonCell>(this.uiContent, "AutoCompleter", out GameObject scrollObj,
scrollPool = UIFactory.CreateScrollPool<ButtonCell>(this.ContentRoot, "AutoCompleter", out GameObject scrollObj,
out GameObject scrollContent);
scrollPool.Initialize(buttonListDataHandler);
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(scrollContent, true, false, true, false);
navigationTipRow = UIFactory.CreateHorizontalGroup(this.uiContent, "BottomRow", true, true, true, true, 0, new Vector4(2, 2, 2, 2));
navigationTipRow = UIFactory.CreateHorizontalGroup(this.ContentRoot, "BottomRow", true, true, true, true, 0, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(navigationTipRow, minHeight: 20, flexibleWidth: 9999);
UIFactory.CreateLabel(navigationTipRow, "HelpText", "Up/Down to select, Enter to use, Esc to close",
TextAnchor.MiddleLeft, Color.grey, false, 13);

View File

@ -1,27 +1,20 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Config;
using System.Collections;
using UnityExplorer.CSConsole;
using UnityExplorer.UI.Widgets;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
namespace UnityExplorer.UI.Panels
{
public class CSConsolePanel : UIPanel
public class CSConsolePanel : UEPanel
{
public override string Name => "C# Console";
public override UIManager.Panels PanelType => UIManager.Panels.CSConsole;
public override int MinWidth => 750;
public override int MinHeight => 300;
public override Vector2 DefaultAnchorMin => new(0.4f, 0.175f);
public override Vector2 DefaultAnchorMax => new(0.85f, 0.925f);
public InputFieldScroller InputScroller { get; private set; }
public InputFieldRef Input => InputScroller.InputField;
@ -41,6 +34,10 @@ namespace UnityExplorer.UI.Panels
public Action<bool> OnAutoIndentToggled;
public Action OnPanelResized;
public CSConsolePanel(UIBase owner) : base(owner)
{
}
private void InvokeOnValueChanged(string value)
{
if (value.Length == UniversalUI.MAX_INPUTFIELD_CHARS)
@ -58,49 +55,41 @@ namespace UnityExplorer.UI.Panels
// UI Construction
public override void OnFinishResize(RectTransform panel)
public override void OnFinishResize()
{
OnPanelResized?.Invoke();
}
protected internal override void DoSetDefaultPosAndAnchors()
{
Rect.localPosition = Vector2.zero;
Rect.pivot = new Vector2(0f, 1f);
Rect.anchorMin = new Vector2(0.4f, 0.175f);
Rect.anchorMax = new Vector2(0.85f, 0.925f);
}
public override void ConstructPanelContent()
protected override void ConstructPanelContent()
{
// Tools Row
var toolsRow = UIFactory.CreateHorizontalGroup(this.uiContent, "ToggleRow", false, false, true, true, 5, new Vector4(8, 8, 10, 5),
GameObject toolsRow = UIFactory.CreateHorizontalGroup(this.ContentRoot, "ToggleRow", false, false, true, true, 5, new Vector4(8, 8, 10, 5),
default, TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(toolsRow, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
// Buttons
var compileButton = UIFactory.CreateButton(toolsRow, "CompileButton", "Compile", new Color(0.33f, 0.5f, 0.33f));
ButtonRef compileButton = UIFactory.CreateButton(toolsRow, "CompileButton", "Compile", new Color(0.33f, 0.5f, 0.33f));
UIFactory.SetLayoutElement(compileButton.Component.gameObject, minHeight: 28, minWidth: 130, flexibleHeight: 0);
compileButton.ButtonText.fontSize = 15;
compileButton.OnClick += () => { OnCompileClicked?.Invoke(); };
var resetButton = UIFactory.CreateButton(toolsRow, "ResetButton", "Reset", new Color(0.33f, 0.33f, 0.33f));
ButtonRef resetButton = UIFactory.CreateButton(toolsRow, "ResetButton", "Reset", new Color(0.33f, 0.33f, 0.33f));
UIFactory.SetLayoutElement(resetButton.Component.gameObject, minHeight: 28, minWidth: 80, flexibleHeight: 0);
resetButton.ButtonText.fontSize = 15;
resetButton.OnClick += () => { OnResetClicked?.Invoke(); };
// Help dropdown
var helpDrop = UIFactory.CreateDropdown(toolsRow, "HelpDropdown", out var dropdown, "Help", 14, null);
GameObject helpDrop = UIFactory.CreateDropdown(toolsRow, "HelpDropdown", out Dropdown dropdown, "Help", 14, null);
UIFactory.SetLayoutElement(helpDrop, minHeight: 25, minWidth: 100);
HelpDropdown = dropdown;
HelpDropdown.onValueChanged.AddListener((int val) => { this.OnHelpDropdownChanged?.Invoke(val); });
// Enable Ctrl+R toggle
var ctrlRToggleObj = UIFactory.CreateToggle(toolsRow, "CtrlRToggle", out var CtrlRToggle, out Text ctrlRToggleText);
GameObject ctrlRToggleObj = UIFactory.CreateToggle(toolsRow, "CtrlRToggle", out Toggle CtrlRToggle, out Text ctrlRToggleText);
UIFactory.SetLayoutElement(ctrlRToggleObj, minWidth: 150, flexibleWidth: 0, minHeight: 25);
ctrlRToggleText.alignment = TextAnchor.UpperLeft;
ctrlRToggleText.text = "Compile on Ctrl+R";
@ -108,7 +97,7 @@ namespace UnityExplorer.UI.Panels
// Enable Suggestions toggle
var suggestToggleObj = UIFactory.CreateToggle(toolsRow, "SuggestionToggle", out var SuggestionsToggle, out Text suggestToggleText);
GameObject suggestToggleObj = UIFactory.CreateToggle(toolsRow, "SuggestionToggle", out Toggle SuggestionsToggle, out Text suggestToggleText);
UIFactory.SetLayoutElement(suggestToggleObj, minWidth: 120, flexibleWidth: 0, minHeight: 25);
suggestToggleText.alignment = TextAnchor.UpperLeft;
suggestToggleText.text = "Suggestions";
@ -116,7 +105,7 @@ namespace UnityExplorer.UI.Panels
// Enable Auto-indent toggle
var autoIndentToggleObj = UIFactory.CreateToggle(toolsRow, "IndentToggle", out var AutoIndentToggle, out Text autoIndentToggleText);
GameObject autoIndentToggleObj = UIFactory.CreateToggle(toolsRow, "IndentToggle", out Toggle AutoIndentToggle, out Text autoIndentToggleText);
UIFactory.SetLayoutElement(autoIndentToggleObj, minWidth: 120, flexibleWidth: 0, minHeight: 25);
autoIndentToggleText.alignment = TextAnchor.UpperLeft;
autoIndentToggleText.text = "Auto-indent";
@ -124,7 +113,7 @@ namespace UnityExplorer.UI.Panels
// Console Input
var inputArea = UIFactory.CreateUIObject("InputGroup", uiContent);
GameObject inputArea = UIFactory.CreateUIObject("InputGroup", ContentRoot);
UIFactory.SetLayoutElement(inputArea, flexibleWidth: 9999, flexibleHeight: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(inputArea, false, true, true, true);
inputArea.AddComponent<Image>().color = Color.white;
@ -132,8 +121,8 @@ namespace UnityExplorer.UI.Panels
// line numbers
var linesHolder = UIFactory.CreateUIObject("LinesHolder", inputArea);
var linesRect = linesHolder.GetComponent<RectTransform>();
GameObject linesHolder = UIFactory.CreateUIObject("LinesHolder", inputArea);
RectTransform linesRect = linesHolder.GetComponent<RectTransform>();
linesRect.pivot = new Vector2(0, 1);
linesRect.anchorMin = new Vector2(0, 0);
linesRect.anchorMax = new Vector2(0, 1);
@ -149,10 +138,10 @@ namespace UnityExplorer.UI.Panels
int fontSize = 16;
var inputObj = UIFactory.CreateScrollInputField(inputArea, "ConsoleInput", ConsoleController.STARTUP_TEXT,
out var inputScroller, fontSize);
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
@ -173,8 +162,8 @@ namespace UnityExplorer.UI.Panels
Input.PlaceholderText.fontSize = fontSize;
// Lexer highlight text overlay
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", InputText.gameObject);
var highlightTextRect = highlightTextObj.GetComponent<RectTransform>();
GameObject highlightTextObj = UIFactory.CreateUIObject("HighlightText", InputText.gameObject);
RectTransform highlightTextRect = highlightTextObj.GetComponent<RectTransform>();
highlightTextRect.pivot = new Vector2(0, 1);
highlightTextRect.anchorMin = Vector2.zero;
highlightTextRect.anchorMax = Vector2.one;

View File

@ -1,29 +1,19 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Config;
using UniverseLib;
using UniverseLib.Input;
using UniverseLib.UI;
using UniverseLib.UI.Widgets;
using UniverseLib.Utility;
using UniverseLib.UI;
namespace UnityExplorer.UI.Panels
{
public class ClipboardPanel : UIPanel
public class ClipboardPanel : UEPanel
{
public static object Current { get; private set; }
public override UIManager.Panels PanelType => UIManager.Panels.Clipboard;
public override string Name => "Clipboard";
public override UIManager.Panels PanelType => UIManager.Panels.Clipboard;
public override int MinWidth => 500;
public override int MinHeight => 95;
public override Vector2 DefaultAnchorMin => new(0.1f, 0.05f);
public override Vector2 DefaultAnchorMax => new(0.4f, 0.15f);
public override bool CanDragAndResize => true;
public override bool NavButtonWanted => true;
public override bool ShouldSaveActiveState => true;
@ -31,6 +21,10 @@ namespace UnityExplorer.UI.Panels
private static Text CurrentPasteLabel;
public ClipboardPanel(UIBase owner) : base(owner)
{
}
public static void Copy(object obj)
{
Current = obj;
@ -41,14 +35,14 @@ namespace UnityExplorer.UI.Panels
public static bool TryPaste(Type targetType, out object paste)
{
paste = Current;
var pasteType = Current?.GetActualType();
Type pasteType = Current?.GetActualType();
if (Current != null && !targetType.IsAssignableFrom(pasteType))
{
Notification.ShowMessage($"Cannot assign '{pasteType.Name}' to '{targetType.Name}'!");
return false;
}
Notification.ShowMessage("Pasted!");
return true;
}
@ -74,35 +68,35 @@ namespace UnityExplorer.UI.Panels
InspectorManager.Inspect(Current);
}
protected internal override void DoSetDefaultPosAndAnchors()
public override void SetDefaultSizeAndPosition()
{
base.SetDefaultSizeAndPosition();
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth);
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
this.Rect.anchorMin = new Vector2(0.1f, 0.05f);
this.Rect.anchorMax = new Vector2(0.4f, 0.15f);
}
public override void ConstructPanelContent()
protected override void ConstructPanelContent()
{
this.UIRoot.GetComponent<Image>().color = new(0.1f, 0.1f, 0.1f);
// Actual panel content
var firstRow = UIFactory.CreateHorizontalGroup(uiContent, "FirstRow", false, false, true, true, 5, new(2,2,2,2), new(1,1,1,0));
GameObject firstRow = UIFactory.CreateHorizontalGroup(ContentRoot, "FirstRow", false, false, true, true, 5, new(2, 2, 2, 2), new(1, 1, 1, 0));
UIFactory.SetLayoutElement(firstRow, minHeight: 25, flexibleWidth: 999);
// Title for "Current Paste:"
var currentPasteTitle = UIFactory.CreateLabel(firstRow, "CurrentPasteTitle", "Current paste:", TextAnchor.MiddleLeft, color: Color.grey);
Text currentPasteTitle = UIFactory.CreateLabel(firstRow, "CurrentPasteTitle", "Current paste:", TextAnchor.MiddleLeft, color: Color.grey);
UIFactory.SetLayoutElement(currentPasteTitle.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
// Clear clipboard button
var clearButton = UIFactory.CreateButton(firstRow, "ClearPasteButton", "Clear Clipboard");
UniverseLib.UI.Models.ButtonRef clearButton = UIFactory.CreateButton(firstRow, "ClearPasteButton", "Clear Clipboard");
UIFactory.SetLayoutElement(clearButton.Component.gameObject, minWidth: 120, minHeight: 25, flexibleWidth: 0);
clearButton.OnClick += () => Copy(null);
// Current Paste info row
var currentPasteHolder = UIFactory.CreateHorizontalGroup(uiContent, "SecondRow", false, false, true, true, 0,
GameObject currentPasteHolder = UIFactory.CreateHorizontalGroup(ContentRoot, "SecondRow", false, false, true, true, 0,
new(2, 2, 2, 2), childAlignment: TextAnchor.UpperCenter);
// Actual current paste info label
@ -111,7 +105,7 @@ namespace UnityExplorer.UI.Panels
UpdateCurrentPasteInfo();
// Inspect button
var inspectButton = UIFactory.CreateButton(currentPasteHolder, "InspectButton", "Inspect");
UniverseLib.UI.Models.ButtonRef inspectButton = UIFactory.CreateButton(currentPasteHolder, "InspectButton", "Inspect");
UIFactory.SetLayoutElement(inspectButton.Component.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 80, flexibleWidth: 0);
inspectButton.OnClick += InspectClipboard;
}

View File

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

View File

@ -1,203 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Config;
using UnityExplorer.Hooks;
using UnityExplorer.Hooks;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView;
namespace UnityExplorer.UI.Panels
{
public class HookManagerPanel : UIPanel
public class HookManagerPanel : UEPanel
{
public static HookManagerPanel Instance { get; private set; }
public enum Pages
{
CurrentHooks,
ClassMethodSelector,
HookSourceEditor
HookSourceEditor,
GenericArgsSelector,
}
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 int MinWidth => 500;
public override int MinHeight => 600;
public override bool ShowByDefault => false;
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;
public Pages CurrentPage { get; private set; } = Pages.ClassMethodSelector;
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; }
private void OnClassInputAddClicked()
public HookManagerPanel(UIBase owner) : base(owner)
{
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 ConstructPanelContent()
public override void SetDefaultSizeAndPosition()
{
// ~~~~~~~~~ Active hooks scroll pool
base.SetDefaultSizeAndPosition();
currentHooksPanel = UIFactory.CreateUIObject("CurrentHooksPanel", this.uiContent);
UIFactory.SetLayoutElement(currentHooksPanel, flexibleHeight: 9999, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(currentHooksPanel, true, true, true, true);
var 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);
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);
var addButton = UIFactory.CreateButton(addRow, "AddButton", "Add Hooks");
UIFactory.SetLayoutElement(addButton.Component.gameObject, minWidth: 100, minHeight: 25);
addButton.OnClick += OnClassInputAddClicked;
var hooksLabel = UIFactory.CreateLabel(currentHooksPanel, "HooksLabel", "Current Hooks", TextAnchor.MiddleCenter);
UIFactory.SetLayoutElement(hooksLabel.gameObject, minHeight: 30, flexibleWidth: 9999);
HooksScrollPool = UIFactory.CreateScrollPool<HookCell>(currentHooksPanel, "HooksScrollPool",
out GameObject hooksScroll, out GameObject hooksContent);
UIFactory.SetLayoutElement(hooksScroll, flexibleHeight: 9999);
HooksScrollPool.Initialize(HookManager.Instance);
// ~~~~~~~~~ Add hooks panel
addHooksPanel = UIFactory.CreateUIObject("AddHooksPanel", this.uiContent);
UIFactory.SetLayoutElement(addHooksPanel, flexibleHeight: 9999, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(addHooksPanel, true, true, true, true);
addHooksLabel = UIFactory.CreateLabel(addHooksPanel, "AddLabel", "NOT SET", TextAnchor.MiddleCenter);
UIFactory.SetLayoutElement(addHooksLabel.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999);
var buttonRow = UIFactory.CreateHorizontalGroup(addHooksPanel, "ButtonRow", false, false, true, true, 5);
UIFactory.SetLayoutElement(buttonRow, minHeight: 25, flexibleWidth: 9999);
var 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.uiContent);
UIFactory.SetLayoutElement(editorPanel, flexibleHeight: 9999, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(editorPanel, true, true, true, true);
var 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);
var editorButtonRow = UIFactory.CreateHorizontalGroup(editorPanel, "ButtonRow", false, false, true, true, 5);
UIFactory.SetLayoutElement(editorButtonRow, minHeight: 25, flexibleWidth: 9999);
var 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;
var 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;
var inputObj = UIFactory.CreateScrollInputField(editorPanel, "EditorInput", "", out var 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
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", EditorInputText.gameObject);
var 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);
}
protected internal override void DoSetDefaultPosAndAnchors()
{
this.Rect.anchorMin = new Vector2(0.5f, 0.5f);
this.Rect.anchorMax = new Vector2(0.5f, 0.5f);
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth);
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
}
protected override void ConstructPanelContent()
{
Instance = this;
hookList = new();
hookCreator = new();
genericArgsHandler = new();
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(ContentRoot, true, false);
// GameObject baseHoriGroup = UIFactory.CreateHorizontalGroup(ContentRoot, "HoriGroup", true, true, true, true);
// UIFactory.SetLayoutElement(baseHoriGroup, flexibleWidth: 9999, flexibleHeight: 9999);
// // Left Group
//GameObject leftGroup = UIFactory.CreateVerticalGroup(ContentRoot, "LeftGroup", true, true, true, true);
UIFactory.SetLayoutElement(ContentRoot.gameObject, minWidth: 300, flexibleWidth: 9999, flexibleHeight: 9999);
hookList.ConstructUI(ContentRoot);
// // Right Group
//GameObject rightGroup = UIFactory.CreateVerticalGroup(ContentRoot, "RightGroup", true, true, true, true);
UIFactory.SetLayoutElement(ContentRoot, minWidth: 300, flexibleWidth: 9999, flexibleHeight: 9999);
hookCreator.ConstructAddHooksView(ContentRoot);
hookCreator.ConstructEditor(ContentRoot);
HookCreator.EditorRoot.SetActive(false);
genericArgsHandler.ConstructUI(ContentRoot);
genericArgsHandler.UIRoot.SetActive(false);
}
}
}

View File

@ -1,27 +1,20 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Config;
using UnityExplorer.Inspectors;
using UnityExplorer.Inspectors;
using UniverseLib.UI;
namespace UnityExplorer.UI.Panels
{
public class InspectorPanel : UIPanel
public class InspectorPanel : UEPanel
{
public static InspectorPanel Instance { get; private set; }
public InspectorPanel() { Instance = this; }
public override string Name => "Inspector";
public override UIManager.Panels PanelType => UIManager.Panels.Inspector;
public override bool ShouldSaveActiveState => false;
public override int MinWidth => 810;
public override int MinHeight => 350;
public override Vector2 DefaultAnchorMin => new(0.35f, 0.175f);
public override Vector2 DefaultAnchorMax => new(0.8f, 0.925f);
public GameObject NavbarHolder;
public Dropdown MouseInspectDropdown;
@ -31,34 +24,31 @@ namespace UnityExplorer.UI.Panels
public static float CurrentPanelWidth => Instance.Rect.rect.width;
public static float CurrentPanelHeight => Instance.Rect.rect.height;
public InspectorPanel(UIBase owner) : base(owner)
{
Instance = this;
}
public override void Update()
{
InspectorManager.Update();
}
public override void OnFinishResize(RectTransform panel)
public override void OnFinishResize()
{
base.OnFinishResize(panel);
base.OnFinishResize();
InspectorManager.PanelWidth = this.Rect.rect.width;
InspectorManager.OnPanelResized(panel.rect.width);
InspectorManager.OnPanelResized(Rect.rect.width);
}
protected internal override void DoSetDefaultPosAndAnchors()
protected override void ConstructPanelContent()
{
Rect.localPosition = Vector2.zero;
Rect.pivot = new Vector2(0f, 1f);
Rect.anchorMin = new Vector2(0.35f, 0.175f);
Rect.anchorMax = new Vector2(0.8f, 0.925f);
}
public override void ConstructPanelContent()
{
var closeHolder = this.TitleBar.transform.Find("CloseHolder").gameObject;
GameObject closeHolder = this.TitleBar.transform.Find("CloseHolder").gameObject;
// Inspect under mouse dropdown on title bar
var mouseDropdown = UIFactory.CreateDropdown(closeHolder, "MouseInspectDropdown", out MouseInspectDropdown, "Mouse Inspect", 14,
GameObject mouseDropdown = UIFactory.CreateDropdown(closeHolder, "MouseInspectDropdown", out MouseInspectDropdown, "Mouse Inspect", 14,
MouseInspector.OnDropdownSelect);
UIFactory.SetLayoutElement(mouseDropdown, minHeight: 25, minWidth: 140);
MouseInspectDropdown.options.Add(new Dropdown.OptionData("Mouse Inspect"));
@ -68,7 +58,7 @@ namespace UnityExplorer.UI.Panels
// add close all button to titlebar
var closeAllBtn = UIFactory.CreateButton(closeHolder.gameObject, "CloseAllBtn", "Close All",
UniverseLib.UI.Models.ButtonRef closeAllBtn = UIFactory.CreateButton(closeHolder.gameObject, "CloseAllBtn", "Close All",
new Color(0.3f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(closeAllBtn.Component.gameObject, minHeight: 25, minWidth: 80);
closeAllBtn.Component.transform.SetSiblingIndex(closeAllBtn.Component.transform.GetSiblingIndex() - 1);
@ -76,19 +66,19 @@ namespace UnityExplorer.UI.Panels
// this.UIRoot.GetComponent<Mask>().enabled = false;
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.uiContent, true, true, true, true, 4, padLeft: 5, padRight: 5);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.ContentRoot, true, true, true, true, 4, padLeft: 5, padRight: 5);
this.NavbarHolder = UIFactory.CreateGridGroup(this.uiContent, "Navbar", new Vector2(200, 22), new Vector2(4, 4),
this.NavbarHolder = UIFactory.CreateGridGroup(this.ContentRoot, "Navbar", new Vector2(200, 22), new Vector2(4, 4),
new Color(0.05f, 0.05f, 0.05f));
//UIFactory.SetLayoutElement(NavbarHolder, flexibleWidth: 9999, minHeight: 0, preferredHeight: 0, flexibleHeight: 9999);
NavbarHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
this.ContentHolder = UIFactory.CreateVerticalGroup(this.uiContent, "ContentHolder", true, true, true, true, 0, default,
this.ContentHolder = UIFactory.CreateVerticalGroup(this.ContentRoot, "ContentHolder", true, true, true, true, 0, default,
new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(ContentHolder, flexibleHeight: 9999);
ContentRect = ContentHolder.GetComponent<RectTransform>();
UIManager.SetPanelActive(PanelType, false);
this.SetActive(false);
}
}
}

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