Compare commits

..

94 Commits
4.7.1 ... 4.8.0

Author SHA1 Message Date
c88182c831 Bump version 2022-05-08 18:06:56 +10:00
02e0102041 Merge branch 'master' of https://github.com/sinai-dev/UnityExplorer 2022-05-07 05:19:46 +10:00
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
ff6c03e1f3 Update README.md 2022-05-06 15:46:49 +10:00
1aedc505b2 Bump UniverseLib 2022-05-05 23:13:51 +10:00
dbe993a7c7 Fix some casts for IL2CPP 2022-05-05 22:18:19 +10:00
5a1676fb84 Update README.md 2022-05-05 19:56:29 +10:00
a7a663aefa Prevent update overwriting input field changes 2022-05-05 19:53:02 +10:00
76c77fb082 Add button to inspect scene of a GameObject 2022-05-05 19:52:25 +10:00
a25017df69 Add wider Texture2DWidget support 2022-05-05 19:52:13 +10:00
a1fab0c4a7 Add support for opening inspected Type in dnSpy 2022-05-05 19:50:52 +10:00
4599747bfe Merge branch 'master' of https://github.com/sinai-dev/UnityExplorer 2022-05-05 02:45:43 +10:00
3856e84c08 Bump version 2022-05-05 02:45:41 +10:00
104288a912 Add support for Cubemaps in Texture2DWidget 2022-05-05 02:45:24 +10:00
41e8a5ae33 Update README.md 2022-05-03 06:10:22 +10:00
ef4bc75d5e Bump version 2022-04-30 20:53:31 +10:00
68b81c6b53 Bump UniverseLib 2022-04-30 20:47:53 +10:00
bd86f09313 Cleanup and refactor GameObjectControls
Split into proper classes, cleanup ugly code
2022-04-30 20:32:31 +10:00
b35d6f5787 Cleanup 2022-04-30 20:31:33 +10:00
b97eada516 Update README.md 2022-04-29 16:56:29 +10:00
0a05848bef Implement control modifier to Home/End jump 2022-04-28 04:10:36 +10:00
6e5610129a Add ILRepack back to build process 2022-04-27 20:13:17 +10:00
acd30880a8 Bump UniverseLib 2022-04-27 03:04:28 +10:00
f54ff89290 Bump UniverseLib 2022-04-25 22:52:24 +10:00
62d565777d Bump UniverseLib and version 2022-04-25 19:39:44 +10:00
870f82ab26 Fix Home jump when line is entirely whitespace 2022-04-25 05:48:13 +10:00
9370c5e0e6 Fix jumpToTop and panel position behaviour 2022-04-25 05:47:57 +10:00
b8cf96438c Correct a comment position 2022-04-24 19:38:17 +10:00
7be7daf4d7 Bump version 2022-04-24 19:24:43 +10:00
8f54415ae0 Remove small logic error with SymbolLexer 2022-04-24 19:23:05 +10:00
aef4e11c01 C# Console: Implement Home and End keys 2022-04-24 19:13:43 +10:00
af7e32ec49 Add a null check 2022-04-24 18:16:13 +10:00
6f44a3376b Bump UniverseLib 2022-04-24 05:58:36 +10:00
3a6b573ac3 Bump version 2022-04-24 05:57:29 +10:00
cbe17927fb Ensure valid panel size after loading save data 2022-04-24 05:57:22 +10:00
15f3f37948 Clean up all objects in editor 2022-04-24 05:56:47 +10:00
de6760e427 Add more convenient editor config serialization 2022-04-24 05:56:36 +10:00
83edd1b9bb Bump editor package 2022-04-24 02:12:57 +10:00
613be34e95 Bump UniverseLib 2022-04-24 02:04:08 +10:00
58c65b9b8b Make TypeCompleter asynchronous 2022-04-24 02:02:34 +10:00
6fcf6a521c Bump version 2022-04-24 02:02:29 +10:00
81a174f865 Remove call to obsolete methods 2022-04-24 01:59:53 +10:00
b5e3cc2ea5 Use separate TypeCompleters for different contexts 2022-04-24 01:59:03 +10:00
14f46ade6a Cancel pending generic when edit button pressed 2022-04-24 01:58:27 +10:00
e92556805b Update BepInExConfigHandler.cs 2022-04-23 01:05:51 +10:00
8662742461 Bump version 2022-04-23 00:19:31 +10:00
63393a9d66 Update README.md 2022-04-22 22:31:36 +10:00
13986f95c1 Update UnityExplorer.STANDALONE.Mono.dll 2022-04-22 22:27:48 +10:00
b47bfa1e83 Remove Mono restriction on generic type eligibility 2022-04-22 22:27:43 +10:00
12c51248fe Update Editor package 2022-04-22 22:20:01 +10:00
9b9cb54a79 Fix a typo 2022-04-22 22:19:43 +10:00
6a28a93e3a Update for obsolete method 2022-04-22 22:11:24 +10:00
32e718faeb Bump UniverseLib 2022-04-22 21:31:30 +10:00
4d46b74d54 Fix references for rename 2022-04-22 21:04:50 +10:00
7e5246cead Recache types when borrowing 2022-04-22 21:04:23 +10:00
abf5267364 Fix HookCreator method filtering 2022-04-22 21:03:51 +10:00
3afee7254c Fix results TypeCompleter issues 2022-04-22 21:03:33 +10:00
1643d4b7dd Allow generic class construction for unbound types 2022-04-22 21:03:11 +10:00
cef8c12d20 Fix TryFocusActiveInspector for classes 2022-04-22 21:02:45 +10:00
5e07847356 Make current hooks view smaller in height 2022-04-22 21:02:08 +10:00
2dc6e386df Fix generated patch code for ref and subclasses 2022-04-22 21:01:47 +10:00
ff882296fd Fix for GenericConstructorWidget, adjust UI 2022-04-22 21:01:09 +10:00
ecc33927ee Make GenericConstructorWidget reusable 2022-04-22 21:00:18 +10:00
6e91f2a792 Hooks: Add support for generic classes and methods 2022-04-22 09:15:51 +10:00
97cb14d6fc HookInstance: Clean up generated patch code 2022-04-22 09:12:38 +10:00
8b861f7c77 Log Panel: Remove a todo 2022-04-22 09:12:22 +10:00
9379e0f813 Fix constraints on AddComponent TypeCompleter 2022-04-22 09:08:49 +10:00
bdda12a040 Remove redundant reference to EvaluateWidget 2022-04-22 09:08:17 +10:00
75bd654a94 TypeCompleter: Allow generics, support shorthand names 2022-04-22 09:07:51 +10:00
f174c7543a C# Console: Fix autocomplete caret deselection 2022-04-22 09:06:52 +10:00
08f2c6035e Bump version 2022-04-20 18:47:23 +10:00
475e24a66a Update editor package 2022-04-20 18:47:19 +10:00
c62b93535d Update position input when Reset button clicked 2022-04-20 18:47:12 +10:00
374d0b3bae Bump UniverseLib 2022-04-20 18:46:48 +10:00
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
495bc41a8d Bump Editor package 2022-04-19 18:06:16 +10:00
9cf62c3250 Bump UniverseLib, fix EventSystem issue 2022-04-19 18:05:55 +10:00
4c9b3115cd Update UnityEditorPackage 2022-04-19 01:23:11 +10:00
ebdce70418 Move instructions 2022-04-19 01:22:25 +10:00
7c0b37440b Update UnityEditorPackage 2022-04-19 01:19:04 +10:00
0d8ab8bf14 Allow FreeCam to run when menu closed 2022-04-19 01:12:33 +10:00
5a3cad9be2 Fix weird Behaviour inheritance issue 2022-04-19 00:57:13 +10:00
70d67f1dad Bump version 2022-04-18 21:39:50 +10:00
469484d129 Add FreeCam panel 2022-04-18 21:39:17 +10:00
c5e262d1c3 Fix UEPanel save data issue 2022-04-18 21:39:11 +10:00
53c8dfcb6d Bump UniverseLib 2022-04-18 21:38:49 +10:00
ae3ac21992 Add test for Il2CppSystem.Array 2022-04-18 19:12:42 +10:00
7765b64748 Make MouseInspector panel just a PanelBase 2022-04-18 19:12:21 +10:00
a5023d03f4 Update to UniverseLib 1.3.4 2022-04-18 19:11:39 +10:00
a5e6b65dee Add UniverseLib to C# Console default usings 2022-04-18 19:10:24 +10:00
c45cd8c1e1 Update editor package 2022-04-14 02:41:18 +10:00
e46e24e1af Fix typo 2022-04-14 02:32:01 +10:00
3d66493f9c Use UniverseLib PanelBase/PanelDragger 2022-04-14 01:25:59 +10:00
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
119 changed files with 4311 additions and 4382 deletions

View File

@ -18,6 +18,12 @@
⚡ 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) ⚡ 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 ## BepInEx
| Release | IL2CPP | Mono | | Release | IL2CPP | Mono |
@ -33,8 +39,8 @@
## MelonLoader ## MelonLoader
| Release | IL2CPP | Mono | | 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.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) | ✖️ | | 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 1. Unzip the release file into a folder
@ -104,7 +110,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. * 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 * 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 * 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 ### C# Console
@ -115,7 +122,7 @@ The inspector is used to see detailed information on objects of any type and man
### Hook Manager ### Hook Manager
* The Hooks panel allows you to hook methods at the click of a button for debugging purposes. * 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. * 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 ### Mouse-Inspect
@ -124,6 +131,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>World</b>: uses Physics.Raycast to look for Colliders
* <b>UI</b>: uses GraphicRaycasters to find UI objects * <b>UI</b>: uses GraphicRaycasters to find UI objects
### 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 ### Clipboard
* The "Clipboard" panel allows you to see your current paste value, or clear it (resets it to `null`) * The "Clipboard" panel allows you to see your current paste value, or clear it (resets it to `null`)

View File

@ -1,6 +1,6 @@
{ {
"name": "com.sinai-dev.unityexplorer", "name": "com.sinai-dev.unityexplorer",
"version": "4.7.0", "version": "4.7.12",
"displayName": "UnityExplorer", "displayName": "UnityExplorer",
"description": "An in-game UI for exploring, debugging and modifying Unity games.", "description": "An in-game UI for exploring, debugging and modifying Unity games.",
"unity": "2017.1", "unity": "2017.1",

View File

@ -1,97 +1,125 @@
# MelonLoader IL2CPP (net6) # ----------- MelonLoader IL2CPP (net6) -----------
dotnet build src\UnityExplorer.sln -c Release_ML_Cpp_net6 dotnet build src\UnityExplorer.sln -c Release_ML_Cpp_net6
# (cleanup and move files)
$Path = "Release\UnityExplorer.MelonLoader.IL2CPP.net6preview" $Path = "Release\UnityExplorer.MelonLoader.IL2CPP.net6preview"
# 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\UnityExplorer.ML.IL2CPP.net6preview.deps.json
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 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 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.dll -Destination $Path\UserLibs -Force
# (create zip archive) # (create zip archive)
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.MelonLoader.IL2CPP.net6preview.zip -Force Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.MelonLoader.IL2CPP.net6preview.zip -Force
# MelonLoader IL2CPP (net472) # ----------- MelonLoader IL2CPP (net472) -----------
dotnet build src\UnityExplorer.sln -c Release_ML_Cpp_net472 dotnet build src\UnityExplorer.sln -c Release_ML_Cpp_net472
# (cleanup and move files)
$Path = "Release\UnityExplorer.MelonLoader.IL2CPP" $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)
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 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 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.dll -Destination $Path\UserLibs -Force
# (create zip archive) # (create zip archive)
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.MelonLoader.IL2CPP.zip -Force Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.MelonLoader.IL2CPP.zip -Force
# MelonLoader Mono # ----------- MelonLoader Mono -----------
dotnet build src\UnityExplorer.sln -c Release_ML_Mono dotnet build src\UnityExplorer.sln -c Release_ML_Mono
# (cleanup and move files)
$Path = "Release\UnityExplorer.MelonLoader.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)
Remove-Item $Path\Tomlet.dll Remove-Item $Path\Tomlet.dll
Remove-Item $Path\mcs.dll
New-Item -Path "$Path" -Name "Mods" -ItemType "directory" -Force 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 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) # (create zip archive)
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.MelonLoader.Mono.zip -Force Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.MelonLoader.Mono.zip -Force
# BepInEx IL2CPP # ----------- BepInEx IL2CPP -----------
dotnet build src\UnityExplorer.sln -c Release_BIE_Cpp dotnet build src\UnityExplorer.sln -c Release_BIE_Cpp
# (cleanup and move files)
$Path = "Release\UnityExplorer.BepInEx.IL2CPP" $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)
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" -ItemType "directory" -Force
New-Item -Path "$Path" -Name "plugins\sinai-dev-UnityExplorer" -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\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 Move-Item -Path $Path\UniverseLib.IL2CPP.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
# (create zip archive) # (create zip archive)
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.BepInEx.IL2CPP.zip -Force Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.BepInEx.IL2CPP.zip -Force
# BepInEx 5 Mono # ----------- BepInEx 5 Mono -----------
dotnet build src\UnityExplorer.sln -c Release_BIE5_Mono dotnet build src\UnityExplorer.sln -c Release_BIE5_Mono
# (cleanup and move files)
$Path = "Release\UnityExplorer.BepInEx5.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)
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" -ItemType "directory" -Force
New-Item -Path "$Path" -Name "plugins\sinai-dev-UnityExplorer" -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\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 Move-Item -Path $Path\UniverseLib.Mono.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
# (create zip archive) # (create zip archive)
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.BepInEx5.Mono.zip -Force Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.BepInEx5.Mono.zip -Force
# BepInEx 6 Mono # ----------- BepInEx 6 Mono -----------
dotnet build src\UnityExplorer.sln -c Release_BIE6_Mono dotnet build src\UnityExplorer.sln -c Release_BIE6_Mono
# (cleanup and move files)
$Path = "Release\UnityExplorer.BepInEx6.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" -ItemType "directory" -Force
New-Item -Path "$Path" -Name "plugins\sinai-dev-UnityExplorer" -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\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 Move-Item -Path $Path\UniverseLib.Mono.dll -Destination $Path\plugins\sinai-dev-UnityExplorer -Force
# (create zip archive) # (create zip archive)
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.BepInEx6.Mono.zip -Force Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.BepInEx6.Mono.zip -Force
# Standalone Mono # ----------- Standalone Mono -----------
dotnet build src\UnityExplorer.sln -c Release_STANDALONE_Mono dotnet build src\UnityExplorer.sln -c Release_STANDALONE_Mono
$Path = "Release\UnityExplorer.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
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.Standalone.Mono.zip -Force Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.Standalone.Mono.zip -Force
# Standalone IL2CPP # ----------- Standalone IL2CPP -----------
dotnet build src\UnityExplorer.sln -c Release_STANDALONE_Cpp dotnet build src\UnityExplorer.sln -c Release_STANDALONE_Cpp
$Path = "Release\UnityExplorer.Standalone.IL2CPP" $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
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.Standalone.IL2CPP.zip -Force Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.Standalone.IL2CPP.zip -Force
# Editor (mono) # ----------- Editor (mono) -----------
$Path1 = "Release\UnityExplorer.Standalone.Mono" $Path1 = "Release\UnityExplorer.Standalone.Mono"
$Path2 = "UnityEditorPackage\Runtime" $Path2 = "UnityEditorPackage\Runtime"
Copy-Item $Path1\UnityExplorer.STANDALONE.Mono.dll -Destination $Path2 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 Copy-Item $Path1\UniverseLib.Mono.dll -Destination $Path2
Compress-Archive -Path UnityEditorPackage\* -CompressionLevel Fastest -DestinationPath Release\UnityExplorer.Editor.zip -Force Compress-Archive -Path UnityEditorPackage\* -CompressionLevel Fastest -DestinationPath Release\UnityExplorer.Editor.zip -Force

BIN
lib/ILRepack.exe Normal file

Binary file not shown.

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

Binary file not shown.

View File

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

View File

@ -1,4 +1,6 @@
using System; using HarmonyLib;
using Mono.CSharp;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -8,45 +10,46 @@ using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
using UniverseLib.Input;
using UnityExplorer.CSConsole;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib; using UniverseLib;
using UniverseLib.Input;
using UniverseLib.Runtime;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib.Utility; using UniverseLib.Utility;
using HarmonyLib;
using UniverseLib.Runtime;
using Mono.CSharp;
namespace UnityExplorer.CSConsole namespace UnityExplorer.CSConsole
{ {
public static class ConsoleController public static class ConsoleController
{ {
public static ScriptEvaluator Evaluator; public static ScriptEvaluator Evaluator { get; private set; }
public static LexerBuilder Lexer; public static LexerBuilder Lexer { get; private set; }
public static CSAutoCompleter Completer; public static CSAutoCompleter Completer { get; private set; }
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 bool SRENotSupported { get; private set; }
public static int LastCaretPosition { 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 EnableCtrlRShortcut { get; private set; } = true;
public static bool EnableAutoIndent { get; private set; } = true; public static bool EnableAutoIndent { get; private set; } = true;
public static bool EnableSuggestions { get; private set; } = true; public static bool EnableSuggestions { get; private set; } = true;
internal static string ScriptsFolder => Path.Combine(ExplorerCore.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",
"System.Linq", "System.Linq",
@ -54,17 +57,17 @@ namespace UnityExplorer.CSConsole
"System.Collections", "System.Collections",
"System.Collections.Generic", "System.Collections.Generic",
"UnityEngine", "UnityEngine",
"UniverseLib",
#if CPP #if CPP
"UnhollowerBaseLib", "UnhollowerBaseLib",
"UnhollowerRuntimeLib", "UnhollowerRuntimeLib",
#endif #endif
}; };
const int CSCONSOLE_LINEHEIGHT = 18;
public static void Init() public static void Init()
{ {
InitEventSystemPropertyHandlers();
// Make sure console is supported on this platform
try try
{ {
ResetConsole(false); ResetConsole(false);
@ -99,11 +102,11 @@ namespace UnityExplorer.CSConsole
if (!Directory.Exists(ScriptsFolder)) if (!Directory.Exists(ScriptsFolder))
Directory.CreateDirectory(ScriptsFolder); Directory.CreateDirectory(ScriptsFolder);
var startupPath = Path.Combine(ScriptsFolder, "startup.cs"); string startupPath = Path.Combine(ScriptsFolder, "startup.cs");
if (File.Exists(startupPath)) if (File.Exists(startupPath))
{ {
ExplorerCore.Log($"Executing startup script from '{startupPath}'..."); ExplorerCore.Log($"Executing startup script from '{startupPath}'...");
var text = File.ReadAllText(startupPath); string text = File.ReadAllText(startupPath);
Input.Text = text; Input.Text = text;
Evaluate(); Evaluate();
} }
@ -114,31 +117,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 #region Evaluating
private static void GenerateTextWriter() static void GenerateTextWriter()
{ {
evaluatorOutput = new StringBuilder(); evaluatorOutput = new StringBuilder();
evaluatorStringWriter = new StringWriter(evaluatorOutput); evaluatorStringWriter = new StringWriter(evaluatorOutput);
@ -161,7 +143,7 @@ namespace UnityExplorer.CSConsole
}; };
usingDirectives = new HashSet<string>(); usingDirectives = new HashSet<string>();
foreach (var use in DefaultUsing) foreach (string use in DefaultUsing)
AddUsing(use); AddUsing(use);
if (logSuccess) if (logSuccess)
@ -208,7 +190,7 @@ namespace UnityExplorer.CSConsole
{ {
object ret = null; object ret = null;
repl.Invoke(ref ret); repl.Invoke(ref ret);
var result = ret?.ToString(); string result = ret?.ToString();
if (!string.IsNullOrEmpty(result)) if (!string.IsNullOrEmpty(result))
ExplorerCore.Log($"Invoked REPL, result: {ret}"); ExplorerCore.Log($"Invoked REPL, result: {ret}");
else else
@ -224,7 +206,7 @@ namespace UnityExplorer.CSConsole
// The compiled code was not REPL, so it was a using directive or it defined classes. // The compiled code was not REPL, so it was a using directive or it defined classes.
string output = Evaluator._textWriter.ToString(); string output = Evaluator._textWriter.ToString();
var outputSplit = output.Split('\n'); string[] outputSplit = output.Split('\n');
if (outputSplit.Length >= 2) if (outputSplit.Length >= 2)
output = outputSplit[outputSplit.Length - 2]; output = outputSplit[outputSplit.Length - 2];
evaluatorOutput.Clear(); evaluatorOutput.Clear();
@ -250,16 +232,48 @@ namespace UnityExplorer.CSConsole
#endregion #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 if (!settingCaretCoroutine && EnableSuggestions)
private static void OnInputChanged(string value) {
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) if (SRENotSupported)
return; return;
@ -286,7 +300,7 @@ namespace UnityExplorer.CSConsole
DoAutoIndent(); DoAutoIndent();
} }
var inStringOrComment = HighlightVisibleInput(); HighlightVisibleInput(out bool inStringOrComment);
if (!settingCaretCoroutine) if (!settingCaretCoroutine)
{ {
@ -302,40 +316,27 @@ namespace UnityExplorer.CSConsole
UpdateCaret(out _); UpdateCaret(out _);
} }
private static float timeOfLastCtrlR; static void OnToggleAutoIndent(bool value)
public static void Update()
{ {
if (SRENotSupported) EnableAutoIndent = value;
return;
UpdateCaret(out bool caretMoved);
if (!settingCaretCoroutine && EnableSuggestions)
{
if (AutoCompleteModal.CheckEscape(Completer))
{
OnAutocompleteEscaped();
return;
} }
if (caretMoved) static void OnToggleCtrlRShortcut(bool value)
AutoCompleteModal.Instance.ReleaseOwnership(Completer);
}
if (EnableCtrlRShortcut
&& (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
&& InputManager.GetKeyDown(KeyCode.R)
&& timeOfLastCtrlR.OccuredEarlierThanDefault())
{ {
timeOfLastCtrlR = Time.realtimeSinceStartup; EnableCtrlRShortcut = value;
Evaluate(Panel.Input.Text);
}
} }
private const int CSCONSOLE_LINEHEIGHT = 18; static void OnToggleSuggestions(bool value)
{
EnableSuggestions = value;
}
private static void UpdateCaret(out bool caretMoved) #endregion
#region Caret position
static void UpdateCaret(out bool caretMoved)
{ {
int prevCaret = LastCaretPosition; int prevCaret = LastCaretPosition;
caretMoved = false; caretMoved = false;
@ -359,12 +360,12 @@ namespace UnityExplorer.CSConsole
// If caret moved, ensure caret is visible in the viewport // If caret moved, ensure caret is visible in the viewport
if (caretMoved) if (caretMoved)
{ {
var charInfo = Input.TextGenerator.characters[LastCaretPosition]; UICharInfo charInfo = Input.TextGenerator.characters[LastCaretPosition];
var charTop = charInfo.cursorPos.y; float charTop = charInfo.cursorPos.y;
var charBot = charTop - CSCONSOLE_LINEHEIGHT; float charBot = charTop - CSCONSOLE_LINEHEIGHT;
var viewportMin = Input.Transform.rect.height - Input.Transform.anchoredPosition.y - (Input.Transform.rect.height * 0.5f); float viewportMin = Input.Transform.rect.height - Input.Transform.anchoredPosition.y - (Input.Transform.rect.height * 0.5f);
var viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height; float viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
float diff = 0f; float diff = 0f;
if (charTop > viewportMin) if (charTop > viewportMin)
@ -374,118 +375,101 @@ namespace UnityExplorer.CSConsole
if (Math.Abs(diff) > 1) if (Math.Abs(diff) > 1)
{ {
var rect = Input.Transform; RectTransform rect = Input.Transform;
rect.anchoredPosition = new Vector2(rect.anchoredPosition.x, rect.anchoredPosition.y - diff); 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; settingCaretCoroutine = true;
Input.Component.readOnly = true; Input.Component.readOnly = true;
RuntimeHelper.StartCoroutine(SetCaretCoroutine(caretPosition)); RuntimeHelper.StartCoroutine(DoSetCaretCoroutine(caretPosition));
} }
static void InitEventSystemPropertyHandlers() static IEnumerator DoSetCaretCoroutine(int caretPosition)
{ {
try Color color = Input.Component.selectionColor;
{
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.a = 0f; color.a = 0f;
Input.Component.selectionColor = color; Input.Component.selectionColor = color;
try { SetCurrentSelectedGameObject(CursorUnlocker.CurrentEventSystem, null); } EventSystemHelper.SetSelectionGuard(false);
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 ~~~~~~~~~
Input.Component.Select(); Input.Component.Select();
yield return null; // ~~~~~~~ YIELD FRAME ~~~~~~~~~
Input.Component.caretPosition = caretPosition; Input.Component.caretPosition = caretPosition;
Input.Component.selectionFocusPosition = caretPosition; Input.Component.selectionFocusPosition = caretPosition;
LastCaretPosition = Input.Component.caretPosition; LastCaretPosition = Input.Component.caretPosition;
color.a = defaultInputFieldAlpha; color.a = DefaultInputFieldAlpha;
Input.Component.selectionColor = color; Input.Component.selectionColor = color;
Input.Component.readOnly = false; Input.Component.readOnly = false;
settingCaretCoroutine = 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 #region Lexer Highlighting
/// <summary> private static void HighlightVisibleInput(out bool inStringOrComment)
/// Returns true if caret is inside string or comment, false otherwise
/// </summary>
private static bool HighlightVisibleInput()
{ {
inStringOrComment = false;
if (string.IsNullOrEmpty(Input.Text)) if (string.IsNullOrEmpty(Input.Text))
{ {
Panel.HighlightText.text = ""; Panel.HighlightText.text = "";
Panel.LineNumberText.text = "1"; Panel.LineNumberText.text = "1";
return false; return;
} }
// Calculate the visible lines // Calculate the visible lines
@ -495,12 +479,12 @@ namespace UnityExplorer.CSConsole
// the top and bottom position of the viewport in relation to the text height // the top and bottom position of the viewport in relation to the text height
// they need the half-height adjustment to normalize against the 'line.topY' value. // they need the half-height adjustment to normalize against the 'line.topY' value.
var viewportMin = Input.Transform.rect.height - Input.Transform.anchoredPosition.y - (Input.Transform.rect.height * 0.5f); float viewportMin = Input.Transform.rect.height - Input.Transform.anchoredPosition.y - (Input.Transform.rect.height * 0.5f);
var viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height; float viewportMax = viewportMin - Panel.InputScroller.ViewportRect.rect.height;
for (int i = 0; i < Input.TextGenerator.lineCount; i++) for (int i = 0; i < Input.TextGenerator.lineCount; i++)
{ {
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 not set the top line yet, and top of line is below the viewport top
if (topLine == -1 && line.topY <= viewportMin) if (topLine == -1 && line.topY <= viewportMin)
topLine = i; topLine = i;
@ -520,7 +504,7 @@ namespace UnityExplorer.CSConsole
// Highlight the visible text with the LexerBuilder // 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 // Set the line numbers
@ -534,7 +518,7 @@ namespace UnityExplorer.CSConsole
realStartLine++; realStartLine++;
char lastPrev = '\n'; char lastPrev = '\n';
var sb = new StringBuilder(); StringBuilder sb = new();
// append leading new lines for spacing (no point rendering line numbers we cant see) // append leading new lines for spacing (no point rendering line numbers we cant see)
for (int i = 0; i < topLine; i++) for (int i = 0; i < topLine; i++)
@ -558,7 +542,7 @@ namespace UnityExplorer.CSConsole
Panel.LineNumberText.text = sb.ToString(); Panel.LineNumberText.text = sb.ToString();
return ret; return;
} }
#endregion #endregion
@ -598,13 +582,11 @@ namespace UnityExplorer.CSConsole
#region Auto indenting #region Auto indenting
private static int prevContentLen = 0;
private static void DoAutoIndent() 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) if (inc == 1)
{ {
@ -623,7 +605,7 @@ namespace UnityExplorer.CSConsole
} }
} }
prevContentLen = Input.Text.Length; previousContentLength = Input.Text.Length;
} }
#endregion #endregion
@ -631,8 +613,6 @@ namespace UnityExplorer.CSConsole
#region "Help" interaction #region "Help" interaction
private static bool SRENotSupported;
private static void DisableConsole(Exception ex) private static void DisableConsole(Exception ex)
{ {
SRENotSupported = true; SRENotSupported = true;
@ -676,7 +656,7 @@ Doorstop example:
public static void SetupHelpInteraction() public static void SetupHelpInteraction()
{ {
var drop = Panel.HelpDropdown; Dropdown drop = Panel.HelpDropdown;
helpDict.Add("Help", ""); helpDict.Add("Help", "");
helpDict.Add("Usings", HELP_USINGS); helpDict.Add("Usings", HELP_USINGS);
@ -684,7 +664,7 @@ Doorstop example:
helpDict.Add("Classes", HELP_CLASSES); helpDict.Add("Classes", HELP_CLASSES);
helpDict.Add("Coroutines", HELP_COROUTINES); 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)); drop.options.Add(new Dropdown.OptionData(opt.Key));
} }
@ -693,7 +673,7 @@ Doorstop example:
if (index == 0) if (index == 0)
return; return;
var helpText = helpDict.ElementAt(index); KeyValuePair<string, string> helpText = helpDict.ElementAt(index);
Input.Text = helpText.Value; Input.Text = helpText.Value;
@ -706,7 +686,7 @@ Doorstop example:
// It is recommended to use the Log panel (or a console log window) while using this tool. // It is recommended to use the Log panel (or a console log window) while using this tool.
// Use the Help dropdown to see detailed examples of how to use the console. // 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. internal const string HELP_USINGS = @"// You can add a using directive to any namespace, but you must compile for it to take effect.
// It will remain in effect until you Reset the console. // It will remain in effect until you Reset the console.

View File

@ -1,12 +1,7 @@
using Mono.CSharp; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CSConsole.Lexers; using UnityExplorer.CSConsole.Lexers;
using UniverseLib;
using UniverseLib.Utility; using UniverseLib.Utility;
namespace UnityExplorer.CSConsole namespace UnityExplorer.CSConsole
@ -22,17 +17,15 @@ namespace UnityExplorer.CSConsole
public class LexerBuilder public class LexerBuilder
{ {
#region Core and initialization
public const char WHITESPACE = ' '; public const char WHITESPACE = ' ';
public readonly HashSet<char> IndentOpenChars = new HashSet<char> { '{', '(' }; public readonly HashSet<char> IndentOpenChars = new() { '{', '(' };
public readonly HashSet<char> IndentCloseChars = new HashSet<char> { '}', ')' }; public readonly HashSet<char> IndentCloseChars = new() { '}', ')' };
private readonly Lexer[] lexers; 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 StringLexer stringLexer = new();
private readonly CommentLexer commentLexer = new CommentLexer(); private readonly CommentLexer commentLexer = new();
public LexerBuilder() public LexerBuilder()
{ {
@ -45,7 +38,7 @@ namespace UnityExplorer.CSConsole
new KeywordLexer(), new KeywordLexer(),
}; };
foreach (var matcher in lexers) foreach (Lexer matcher in lexers)
{ {
foreach (char c in matcher.Delimiters) foreach (char c in matcher.Delimiters)
{ {
@ -55,8 +48,6 @@ namespace UnityExplorer.CSConsole
} }
} }
#endregion
/// <summary>The last committed index for a match or no-match. Starts at -1 for a new parse.</summary> /// <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; } public int CommittedIndex { get; private set; }
/// <summary>The index of the character we are currently parsing, at minimum it will be CommittedIndex + 1.</summary> /// <summary>The index of the character we are currently parsing, at minimum it will be CommittedIndex + 1.</summary>
@ -97,13 +88,13 @@ namespace UnityExplorer.CSConsole
currentStartIdx = startIdx; currentStartIdx = startIdx;
currentEndIdx = endIdx; currentEndIdx = endIdx;
var sb = new StringBuilder(); StringBuilder sb = new();
for (int i = 0; i < leadingLines; i++) for (int i = 0; i < leadingLines; i++)
sb.Append('\n'); sb.Append('\n');
int lastUnhighlighted = startIdx; int lastUnhighlighted = startIdx;
foreach (var match in GetMatches()) foreach (MatchInfo match in GetMatches())
{ {
// append non-highlighted text between last match and this // append non-highlighted text between last match and this
for (int i = lastUnhighlighted; i < match.startIndex; i++) for (int i = lastUnhighlighted; i < match.startIndex; i++)
@ -130,7 +121,7 @@ namespace UnityExplorer.CSConsole
} }
// check caretIdx to determine inStringOrComment state // 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; caretInStringOrComment = match.isStringOrComment;
} }
@ -158,7 +149,7 @@ namespace UnityExplorer.CSConsole
bool anyMatch = false; bool anyMatch = false;
int startIndex = CommittedIndex + 1; int startIndex = CommittedIndex + 1;
foreach (var lexer in lexers) foreach (Lexer lexer in lexers)
{ {
if (lexer.TryMatchCurrent(this)) if (lexer.TryMatchCurrent(this))
{ {

View File

@ -1,6 +1,4 @@
using System.Collections.Generic; using UnityEngine;
using System.Linq;
using UnityEngine;
namespace UnityExplorer.CSConsole.Lexers namespace UnityExplorer.CSConsole.Lexers
{ {
@ -13,7 +11,7 @@ namespace UnityExplorer.CSConsole.Lexers
} }
// forest green // 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) public override bool TryMatchCurrent(LexerBuilder lexer)
{ {

View File

@ -7,9 +7,9 @@ namespace UnityExplorer.CSConsole.Lexers
public class KeywordLexer : Lexer public class KeywordLexer : Lexer
{ {
// system blue // 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 // reserved keywords
"abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue",
@ -28,15 +28,15 @@ namespace UnityExplorer.CSConsole.Lexers
public override bool TryMatchCurrent(LexerBuilder lexer) public override bool TryMatchCurrent(LexerBuilder lexer)
{ {
var prev = lexer.Previous; char prev = lexer.Previous;
var first = lexer.Current; char first = lexer.Current;
// check for keywords // check for keywords
if (lexer.IsDelimiter(prev, true) && char.IsLetter(first)) if (lexer.IsDelimiter(prev, true) && char.IsLetter(first))
{ {
// can be a keyword... // can be a keyword...
var sb = new StringBuilder(); StringBuilder sb = new();
sb.Append(lexer.Current); sb.Append(lexer.Current);
while (!lexer.EndOfInput && char.IsLetter(lexer.PeekNext())) while (!lexer.EndOfInput && char.IsLetter(lexer.PeekNext()))
sb.Append(lexer.Current); sb.Append(lexer.Current);

View File

@ -1,7 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
using UniverseLib;
using UniverseLib.Utility; using UniverseLib.Utility;
namespace UnityExplorer.CSConsole.Lexers namespace UnityExplorer.CSConsole.Lexers

View File

@ -5,7 +5,7 @@ namespace UnityExplorer.CSConsole.Lexers
public class NumberLexer : Lexer public class NumberLexer : Lexer
{ {
// Maroon // 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 == '.'; private bool IsNumeric(char c) => char.IsNumber(c) || c == '.';

View File

@ -8,7 +8,7 @@ namespace UnityExplorer.CSConsole.Lexers
public override IEnumerable<char> Delimiters => new[] { '"', '\'', }; public override IEnumerable<char> Delimiters => new[] { '"', '\'', };
// orange // 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) public override bool TryMatchCurrent(LexerBuilder lexer)
{ {

View File

@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
namespace UnityExplorer.CSConsole.Lexers namespace UnityExplorer.CSConsole.Lexers
@ -8,14 +7,14 @@ namespace UnityExplorer.CSConsole.Lexers
public class SymbolLexer : Lexer public class SymbolLexer : Lexer
{ {
// silver // 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 // all symbols are delimiters
public override IEnumerable<char> Delimiters => symbols.Where(it => it != '.'); // '.' is not a delimiter, only a separator. public override IEnumerable<char> Delimiters => symbols.Where(it => it != '.'); // '.' is not a delimiter, only a separator.
public static bool IsSymbol(char c) => symbols.Contains(c); public static bool IsSymbol(char c) => symbols.Contains(c);
public static readonly HashSet<char> symbols = new HashSet<char> public static readonly HashSet<char> symbols = new()
{ {
'[', '{', '(', // open '[', '{', '(', // open
']', '}', ')', // close ']', '}', ')', // close
@ -32,14 +31,8 @@ namespace UnityExplorer.CSConsole.Lexers
return false; return false;
if (IsSymbol(lexer.Current)) if (IsSymbol(lexer.Current))
{
do
{ {
lexer.Commit(); lexer.Commit();
lexer.PeekNext();
}
while (IsSymbol(lexer.Current));
return true; return true;
} }

View File

@ -3,7 +3,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Text;
// Thanks to ManlyMarco for this // Thanks to ManlyMarco for this
@ -13,7 +12,10 @@ namespace UnityExplorer.CSConsole
{ {
private static readonly HashSet<string> StdLib = new(StringComparer.InvariantCultureIgnoreCase) private static readonly HashSet<string> StdLib = new(StringComparer.InvariantCultureIgnoreCase)
{ {
"mscorlib", "System.Core", "System", "System.Xml" "mscorlib",
"System.Core",
"System",
"System.Xml"
}; };
internal TextWriter _textWriter; internal TextWriter _textWriter;
@ -45,7 +47,7 @@ namespace UnityExplorer.CSConsole
private void Reference(Assembly asm) private void Reference(Assembly asm)
{ {
var name = asm.GetName().Name; string name = asm.GetName().Name;
if (name == "completions") if (name == "completions")
return; return;
ReferenceAssembly(asm); ReferenceAssembly(asm);
@ -55,7 +57,7 @@ namespace UnityExplorer.CSConsole
{ {
_reportPrinter = new StreamReportPrinter(tw); _reportPrinter = new StreamReportPrinter(tw);
var settings = new CompilerSettings CompilerSettings settings = new()
{ {
Version = LanguageVersion.Experimental, Version = LanguageVersion.Experimental,
GenerateDebugInfo = false, GenerateDebugInfo = false,

View File

@ -2,11 +2,9 @@
using Mono.CSharp; using Mono.CSharp;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.Runtime;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UniverseLib; using UniverseLib;
@ -46,7 +44,7 @@ namespace UnityExplorer.CSConsole
public static void GetVars() public static void GetVars()
{ {
var vars = Evaluator.GetVars()?.Trim(); string vars = Evaluator.GetVars()?.Trim();
if (string.IsNullOrEmpty(vars)) if (string.IsNullOrEmpty(vars))
ExplorerCore.LogWarning("No variables seem to be defined!"); ExplorerCore.LogWarning("No variables seem to be defined!");
else else
@ -59,12 +57,12 @@ namespace UnityExplorer.CSConsole
.GetValue(Evaluator) is CompilationSourceFile sourceFile .GetValue(Evaluator) is CompilationSourceFile sourceFile
&& sourceFile.Containers.Any()) && sourceFile.Containers.Any())
{ {
var sb = new StringBuilder(); StringBuilder sb = new();
sb.Append($"There are {sourceFile.Containers.Count} defined classes:"); sb.Append($"There are {sourceFile.Containers.Count} defined classes:");
foreach (TypeDefinition type in sourceFile.Containers.Where(it => it is TypeDefinition)) foreach (TypeDefinition type in sourceFile.Containers.Where(it => it is TypeDefinition))
{ {
sb.Append($"\n\n{type.MemberName.Name}:"); 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})"); sb.Append($"\n\t- {member.AttributeTargets}: \"{member.MemberName.Name}\" ({member.ModFlags})");
} }
Log(sb.ToString()); Log(sb.ToString());

View File

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

View File

@ -1,8 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using UniverseLib.Utility; using UniverseLib.Utility;

View File

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

View File

@ -1,7 +1,4 @@
using System; 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 UnityExplorer.CacheObject.Views;
using UniverseLib; using UniverseLib;
@ -41,7 +38,7 @@ namespace UnityExplorer.CacheObject
this.DictKey = key; this.DictKey = key;
this.DisplayedKey = key.TryCast(); this.DisplayedKey = key.TryCast();
var type = DisplayedKey.GetType(); Type type = DisplayedKey.GetType();
if (ParseUtility.CanParse(type)) if (ParseUtility.CanParse(type))
{ {
KeyInputWanted = true; KeyInputWanted = true;
@ -60,7 +57,7 @@ namespace UnityExplorer.CacheObject
{ {
base.SetDataToCell(cell); base.SetDataToCell(cell);
var kvpCell = cell as CacheKeyValuePairCell; CacheKeyValuePairCell kvpCell = cell as CacheKeyValuePairCell;
kvpCell.NameLabel.text = $"{DictIndex}:"; kvpCell.NameLabel.text = $"{DictIndex}:";
kvpCell.HiddenNameLabel.Text = ""; kvpCell.HiddenNameLabel.Text = "";

View File

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

View File

@ -1,21 +1,12 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.Runtime;
using UnityExplorer.CacheObject.Views; using UnityExplorer.CacheObject.Views;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using UniverseLib.UI.Models;
using UnityExplorer.UI;
using UniverseLib;
using UniverseLib.UI;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
using UniverseLib.Utility; using UniverseLib;
using UniverseLib.UI.ObjectPool; using UniverseLib.UI.ObjectPool;
using System.Collections; using UniverseLib.Utility;
using HarmonyLib;
namespace UnityExplorer.CacheObject namespace UnityExplorer.CacheObject
{ {
@ -38,8 +29,8 @@ namespace UnityExplorer.CacheObject
this.Owner = inspector; this.Owner = inspector;
this.NameLabelText = this switch this.NameLabelText = this switch
{ {
CacheMethod => SignatureHighlighter.HighlightMethod(member as MethodInfo), CacheMethod => SignatureHighlighter.ParseMethod(member as MethodInfo),
CacheConstructor => SignatureHighlighter.HighlightConstructor(member as ConstructorInfo), CacheConstructor => SignatureHighlighter.ParseConstructor(member as ConstructorInfo),
_ => SignatureHighlighter.Parse(member.DeclaringType, false, member), _ => SignatureHighlighter.Parse(member.DeclaringType, false, member),
}; };
@ -105,7 +96,7 @@ namespace UnityExplorer.CacheObject
protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell objectcell) protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell objectcell)
{ {
var cell = objectcell as CacheMemberCell; CacheMemberCell cell = objectcell as CacheMemberCell;
cell.EvaluateHolder.SetActive(!ShouldAutoEvaluate); cell.EvaluateHolder.SetActive(!ShouldAutoEvaluate);
if (!ShouldAutoEvaluate) if (!ShouldAutoEvaluate)

View File

@ -1,14 +1,11 @@
using System; using HarmonyLib;
using System.Collections; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using UnityExplorer.Runtime; using UnityExplorer.Runtime;
using UniverseLib; using UniverseLib;
using HarmonyLib;
using HarmonyLib.Tools;
namespace UnityExplorer.CacheObject namespace UnityExplorer.CacheObject
{ {

View File

@ -1,10 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using UniverseLib;
using UniverseLib.Utility; using UniverseLib.Utility;
namespace UnityExplorer.CacheObject namespace UnityExplorer.CacheObject
@ -18,7 +14,7 @@ namespace UnityExplorer.CacheObject
public override bool ShouldAutoEvaluate => false; public override bool ShouldAutoEvaluate => false;
public CacheMethod (MethodInfo mi) public CacheMethod(MethodInfo mi)
{ {
this.MethodInfo = mi; this.MethodInfo = mi;
} }
@ -36,7 +32,7 @@ namespace UnityExplorer.CacheObject
{ {
try try
{ {
var methodInfo = MethodInfo; MethodInfo methodInfo = MethodInfo;
if (methodInfo.IsGenericMethod) if (methodInfo.IsGenericMethod)
methodInfo = MethodInfo.MakeGenericMethod(Evaluator.TryParseGenericArguments()); methodInfo = MethodInfo.MakeGenericMethod(Evaluator.TryParseGenericArguments());

View File

@ -1,20 +1,12 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Runtime;
using UnityExplorer.CacheObject.IValues; using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.Views; using UnityExplorer.CacheObject.Views;
using UniverseLib.UI.Models;
using UnityExplorer.UI;
using UniverseLib; using UniverseLib;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.Utility;
using UniverseLib.UI.ObjectPool; using UniverseLib.UI.ObjectPool;
using UniverseLib.Utility;
namespace UnityExplorer.CacheObject namespace UnityExplorer.CacheObject
{ {
@ -36,28 +28,31 @@ namespace UnityExplorer.CacheObject
public abstract class CacheObjectBase public abstract class CacheObjectBase
{ {
public ICacheObjectController Owner { get; set; } public ICacheObjectController Owner { get; set; }
public CacheObjectCell CellView { get; internal set; } public CacheObjectCell CellView { get; internal set; }
public object Value { get; protected set; } public object Value { get; protected set; }
public Type FallbackType { get; protected set; } public Type FallbackType { get; protected set; }
public bool LastValueWasNull { get; private set; } public ValueState State { get; set; }
public Exception LastException { get; protected set; }
public ValueState State = ValueState.NotEvaluated; bool valueIsNull;
public Type LastValueType; Type currentValueType;
// InteractiveValues
public InteractiveValue IValue { get; private set; } public InteractiveValue IValue { get; private set; }
public Type CurrentIValueType { get; private set; } public Type CurrentIValueType { get; private set; }
public bool SubContentShowWanted { get; private set; } public bool SubContentShowWanted { get; private set; }
// UI
public string NameLabelText { get; protected set; } public string NameLabelText { get; protected set; }
public string NameLabelTextRaw { get; protected set; } public string NameLabelTextRaw { get; protected set; }
public string ValueLabelText { get; protected set; } public string ValueLabelText { get; protected set; }
// Abstract
public abstract bool ShouldAutoEvaluate { get; } public abstract bool ShouldAutoEvaluate { get; }
public abstract bool HasArguments { get; } public abstract bool HasArguments { get; }
public abstract bool CanWrite { 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) public virtual void SetFallbackType(Type fallbackType)
{ {
@ -65,17 +60,6 @@ namespace UnityExplorer.CacheObject
this.ValueLabelText = GetValueLabel(); 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) public virtual void SetView(CacheObjectCell cellView)
{ {
this.CellView = cellView; this.CellView = cellView;
@ -94,6 +78,15 @@ namespace UnityExplorer.CacheObject
this.IValue.UIRoot.transform.SetParent(InactiveIValueHolder.transform, false); 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 // Updating and applying values
// The only method which sets the CacheObjectBase.Value // The only method which sets the CacheObjectBase.Value
@ -134,22 +127,22 @@ namespace UnityExplorer.CacheObject
protected virtual void ProcessOnEvaluate() protected virtual void ProcessOnEvaluate()
{ {
var prevState = State; ValueState prevState = State;
if (LastException != null) if (LastException != null)
{ {
LastValueWasNull = true; valueIsNull = true;
LastValueType = FallbackType; currentValueType = FallbackType;
State = ValueState.Exception; State = ValueState.Exception;
} }
else if (Value.IsNullOrDestroyed()) else if (Value.IsNullOrDestroyed())
{ {
LastValueWasNull = true; valueIsNull = true;
State = GetStateForType(FallbackType); State = GetStateForType(FallbackType);
} }
else else
{ {
LastValueWasNull = false; valueIsNull = false;
State = GetStateForType(Value.GetActualType()); State = GetStateForType(Value.GetActualType());
} }
@ -171,10 +164,10 @@ namespace UnityExplorer.CacheObject
public ValueState GetStateForType(Type type) public ValueState GetStateForType(Type type)
{ {
if (LastValueType == type && (State != ValueState.Exception || LastException != null)) if (currentValueType == type && (State != ValueState.Exception || LastException != null))
return State; return State;
LastValueType = type; currentValueType = type;
if (type == typeof(bool)) if (type == typeof(bool))
return ValueState.Boolean; return ValueState.Boolean;
else if (type.IsPrimitive || type == typeof(decimal)) else if (type.IsPrimitive || type == typeof(decimal))
@ -197,7 +190,7 @@ namespace UnityExplorer.CacheObject
protected string GetValueLabel() protected string GetValueLabel()
{ {
string label = ""; string label = string.Empty;
switch (State) switch (State)
{ {
@ -214,19 +207,19 @@ namespace UnityExplorer.CacheObject
// and valuestruct also doesnt want it if we can parse it // and valuestruct also doesnt want it if we can parse it
case ValueState.ValueStruct: case ValueState.ValueStruct:
if (ParseUtility.CanParse(LastValueType)) if (ParseUtility.CanParse(currentValueType))
return null; return null;
break; break;
// string wants it trimmed to max 200 chars // string wants it trimmed to max 200 chars
case ValueState.String: case ValueState.String:
if (!LastValueWasNull) if (!valueIsNull)
return $"\"{ToStringUtility.PruneString(Value as string, 200, 5)}\""; return $"\"{ToStringUtility.PruneString(Value as string, 200, 5)}\"";
break; break;
// try to prefix the count of the collection for lists and dicts // try to prefix the count of the collection for lists and dicts
case ValueState.Collection: case ValueState.Collection:
if (!LastValueWasNull) if (!valueIsNull)
{ {
if (Value is IList iList) if (Value is IList iList)
label = $"[{iList.Count}] "; label = $"[{iList.Count}] ";
@ -238,7 +231,7 @@ namespace UnityExplorer.CacheObject
break; break;
case ValueState.Dictionary: case ValueState.Dictionary:
if (!LastValueWasNull) if (!valueIsNull)
{ {
if (Value is IDictionary iDict) if (Value is IDictionary iDict)
label = $"[{iDict.Count}] "; label = $"[{iDict.Count}] ";
@ -276,9 +269,9 @@ namespace UnityExplorer.CacheObject
if (cell.CopyButton != null) if (cell.CopyButton != null)
{ {
bool hasEvaluated = State != ValueState.NotEvaluated && State != ValueState.Exception; bool canCopy = State != ValueState.NotEvaluated && State != ValueState.Exception;
cell.CopyButton.Component.gameObject.SetActive(hasEvaluated); cell.CopyButton.Component.gameObject.SetActive(canCopy);
cell.PasteButton.Component.gameObject.SetActive(hasEvaluated && this.CanWrite); cell.PasteButton.Component.gameObject.SetActive(canCopy && this.CanWrite);
} }
if (!evaluated) if (!evaluated)
@ -299,7 +292,7 @@ namespace UnityExplorer.CacheObject
SetValueState(cell, new(false, typeLabelActive: true, inputActive: true, applyActive: CanWrite)); SetValueState(cell, new(false, typeLabelActive: true, inputActive: true, applyActive: CanWrite));
break; break;
case ValueState.String: case ValueState.String:
if (LastValueWasNull) if (valueIsNull)
SetValueState(cell, new(true, subContentButtonActive: true)); SetValueState(cell, new(true, subContentButtonActive: true));
else else
SetValueState(cell, new(true, false, SignatureHighlighter.StringOrange, subContentButtonActive: true)); SetValueState(cell, new(true, false, SignatureHighlighter.StringOrange, subContentButtonActive: true));
@ -309,17 +302,17 @@ namespace UnityExplorer.CacheObject
break; break;
case ValueState.Color: case ValueState.Color:
case ValueState.ValueStruct: case ValueState.ValueStruct:
if (ParseUtility.CanParse(LastValueType)) if (ParseUtility.CanParse(currentValueType))
SetValueState(cell, new(false, false, null, true, false, true, CanWrite, true, true)); SetValueState(cell, new(false, false, null, true, false, true, CanWrite, true, true));
else else
SetValueState(cell, new(true, inspectActive: true, subContentButtonActive: true)); SetValueState(cell, new(true, inspectActive: true, subContentButtonActive: true));
break; break;
case ValueState.Collection: case ValueState.Collection:
case ValueState.Dictionary: case ValueState.Dictionary:
SetValueState(cell, new(true, inspectActive: !LastValueWasNull, subContentButtonActive: !LastValueWasNull)); SetValueState(cell, new(true, inspectActive: !valueIsNull, subContentButtonActive: !valueIsNull));
break; break;
case ValueState.Unsupported: case ValueState.Unsupported:
SetValueState(cell, new (true, inspectActive: !LastValueWasNull)); SetValueState(cell, new(true, inspectActive: !valueIsNull));
break; break;
} }
@ -341,7 +334,7 @@ namespace UnityExplorer.CacheObject
// Type label (for primitives) // Type label (for primitives)
cell.TypeLabel.gameObject.SetActive(args.typeLabelActive); cell.TypeLabel.gameObject.SetActive(args.typeLabelActive);
if (args.typeLabelActive) if (args.typeLabelActive)
cell.TypeLabel.text = SignatureHighlighter.Parse(LastValueType, false); cell.TypeLabel.text = SignatureHighlighter.Parse(currentValueType, false);
// toggle for bools // toggle for bools
cell.Toggle.gameObject.SetActive(args.toggleActive); cell.Toggle.gameObject.SetActive(args.toggleActive);
@ -356,7 +349,7 @@ namespace UnityExplorer.CacheObject
cell.InputField.UIRoot.SetActive(args.inputActive); cell.InputField.UIRoot.SetActive(args.inputActive);
if (args.inputActive) if (args.inputActive)
{ {
cell.InputField.Text = ParseUtility.ToStringForInput(Value, LastValueType); cell.InputField.Text = ParseUtility.ToStringForInput(Value, currentValueType);
cell.InputField.Component.readOnly = !CanWrite; cell.InputField.Component.readOnly = !CanWrite;
} }
@ -365,12 +358,12 @@ namespace UnityExplorer.CacheObject
// Inspect button only if last value not null. // Inspect button only if last value not null.
if (cell.InspectButton != 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 // set subcontent button if needed, and for null strings and exceptions
cell.SubContentButton.Component.gameObject.SetActive( cell.SubContentButton.Component.gameObject.SetActive(
args.subContentButtonActive args.subContentButtonActive
&& (!LastValueWasNull || State == ValueState.String || State == ValueState.Exception)); && (!valueIsNull || State == ValueState.String || State == ValueState.Exception));
} }
// CacheObjectCell Apply // CacheObjectCell Apply
@ -381,7 +374,7 @@ namespace UnityExplorer.CacheObject
SetUserValue(this.CellView.Toggle.isOn); SetUserValue(this.CellView.Toggle.isOn);
else 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); SetUserValue(value);
} }

View File

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

View File

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

View File

@ -1,11 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib; using UniverseLib;
@ -32,9 +27,9 @@ namespace UnityExplorer.CacheObject.IValues
applyButton.Component.gameObject.SetActive(owner.CanWrite); applyButton.Component.gameObject.SetActive(owner.CanWrite);
foreach (var slider in sliders) foreach (Slider slider in sliders)
slider.interactable = owner.CanWrite; slider.interactable = owner.CanWrite;
foreach (var input in inputs) foreach (InputFieldRef input in inputs)
input.Component.readOnly = !owner.CanWrite; input.Component.readOnly = !owner.CanWrite;
} }
@ -54,7 +49,7 @@ namespace UnityExplorer.CacheObject.IValues
inputs[1].Text = c32.g.ToString(); inputs[1].Text = c32.g.ToString();
inputs[2].Text = c32.b.ToString(); inputs[2].Text = c32.b.ToString();
inputs[3].Text = c32.a.ToString(); inputs[3].Text = c32.a.ToString();
foreach (var slider in sliders) foreach (Slider slider in sliders)
slider.maxValue = 255; slider.maxValue = 255;
} }
else else
@ -65,7 +60,7 @@ namespace UnityExplorer.CacheObject.IValues
inputs[1].Text = EditedColor.g.ToString(); inputs[1].Text = EditedColor.g.ToString();
inputs[2].Text = EditedColor.b.ToString(); inputs[2].Text = EditedColor.b.ToString();
inputs[3].Text = EditedColor.a.ToString(); inputs[3].Text = EditedColor.a.ToString();
foreach (var slider in sliders) foreach (Slider slider in sliders)
slider.maxValue = 1; slider.maxValue = 1;
} }
@ -156,12 +151,12 @@ namespace UnityExplorer.CacheObject.IValues
// hori group // 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); default, new Color(1, 1, 1, 0), TextAnchor.MiddleLeft);
// sliders / inputs // 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); UIFactory.SetLayoutElement(grid, minWidth: 580, minHeight: 25, flexibleWidth: 0);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -175,7 +170,7 @@ namespace UnityExplorer.CacheObject.IValues
// image of color // image of color
var imgObj = UIFactory.CreateUIObject("ColorImageHelper", horiGroup); GameObject imgObj = UIFactory.CreateUIObject("ColorImageHelper", horiGroup);
UIFactory.SetLayoutElement(imgObj, minHeight: 25, minWidth: 50, flexibleWidth: 50); UIFactory.SetLayoutElement(imgObj, minHeight: 25, minWidth: 50, flexibleWidth: 50);
colorImage = imgObj.AddComponent<Image>(); colorImage = imgObj.AddComponent<Image>();
@ -184,18 +179,18 @@ namespace UnityExplorer.CacheObject.IValues
internal void AddEditorRow(int index, GameObject groupObj) 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)); 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); 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); UIFactory.SetLayoutElement(input.UIRoot, minWidth: 40, minHeight: 25, flexibleHeight: 0);
inputs[index] = input; inputs[index] = input;
input.OnValueChanged += (string val) => { OnInputChanged(val, index); }; 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; sliders[index] = slider;
UIFactory.SetLayoutElement(sliderObj, minHeight: 25, minWidth: 70, flexibleWidth: 999, flexibleHeight: 0); UIFactory.SetLayoutElement(sliderObj, minHeight: 25, minWidth: 70, flexibleWidth: 999, flexibleHeight: 0);
slider.minValue = 0; slider.minValue = 0;

View File

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

View File

@ -2,13 +2,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.CacheObject; using UnityExplorer.UI.Panels;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib.Utility; using UniverseLib.Utility;
@ -110,7 +107,7 @@ namespace UnityExplorer.CacheObject.IValues
{ {
try try
{ {
List<string> values = new List<string>(); List<string> values = new();
for (int i = 0; i < CurrentValues.Count; i++) for (int i = 0; i < CurrentValues.Count; i++)
{ {
if (flagToggles[i].isOn) if (flagToggles[i].isOn)
@ -138,11 +135,11 @@ namespace UnityExplorer.CacheObject.IValues
new Color(0.06f, 0.06f, 0.06f)); new Color(0.06f, 0.06f, 0.06f));
UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleHeight: 9999, flexibleWidth: 9999); 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.SetLayoutElement(hori, minHeight: 25, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(hori, false, false, true, true, 2); 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); UIFactory.SetLayoutElement(applyButton.Component.gameObject, minHeight: 25, minWidth: 100);
applyButton.OnClick += OnApplyClicked; applyButton.OnClick += OnApplyClicked;
@ -192,11 +189,11 @@ namespace UnityExplorer.CacheObject.IValues
private void AddToggleRow() 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.SetLayoutGroup<HorizontalLayoutGroup>(row, false, false, true, true, 2);
UIFactory.SetLayoutElement(row, minHeight: 25, flexibleWidth: 9999); 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); UIFactory.SetLayoutElement(toggleObj, minHeight: 25, flexibleWidth: 9999);
flagToggles.Add(toggle); flagToggles.Add(toggle);
@ -205,7 +202,7 @@ namespace UnityExplorer.CacheObject.IValues
#region Enum cache #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) internal static OrderedDictionary GetEnumValues(Type enumType)
{ {
@ -213,13 +210,13 @@ namespace UnityExplorer.CacheObject.IValues
if (!enumCache.ContainsKey(enumType.AssemblyQualifiedName)) if (!enumCache.ContainsKey(enumType.AssemblyQualifiedName))
{ {
var dict = new OrderedDictionary(); OrderedDictionary dict = new();
var addedNames = new HashSet<string>(); HashSet<string> addedNames = new();
int i = 0; 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)) if (addedNames.Contains(name))
continue; continue;
addedNames.Add(name); addedNames.Add(name);

View File

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

View File

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

View File

@ -1,13 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; 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 namespace UnityExplorer.CacheObject.IValues

View File

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

View File

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

View File

@ -1,13 +1,6 @@
using System; using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.CacheObject.IValues; using UnityExplorer.CacheObject.IValues;
using UnityExplorer.Inspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
@ -24,8 +17,8 @@ namespace UnityExplorer.CacheObject.Views
public InputFieldRef KeyInputField; public InputFieldRef KeyInputField;
public Text KeyInputTypeLabel; public Text KeyInputTypeLabel;
public static Color EvenColor = new Color(0.07f, 0.07f, 0.07f); public static Color EvenColor = new(0.07f, 0.07f, 0.07f);
public static Color OddColor = new Color(0.063f, 0.063f, 0.063f); public static Color OddColor = new(0.063f, 0.063f, 0.063f);
public int AdjustedWidth => (int)Rect.rect.width - 70; public int AdjustedWidth => (int)Rect.rect.width - 70;
@ -40,7 +33,7 @@ namespace UnityExplorer.CacheObject.Views
public override GameObject CreateContent(GameObject parent) public override GameObject CreateContent(GameObject parent)
{ {
var root = base.CreateContent(parent); GameObject root = base.CreateContent(parent);
Image = root.AddComponent<Image>(); Image = root.AddComponent<Image>();
@ -53,7 +46,7 @@ namespace UnityExplorer.CacheObject.Views
this.RightGroupLayout.minWidth = AdjustedWidth * 0.55f; this.RightGroupLayout.minWidth = AdjustedWidth * 0.55f;
// Key area // 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); 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); KeyGroupLayout = UIFactory.SetLayoutElement(keyGroup, minHeight: 30, minWidth: (int)(AdjustedWidth * 0.44f), flexibleWidth: 0);

View File

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

View File

@ -1,11 +1,5 @@
using System; using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;

View File

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

View File

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

View File

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

View File

@ -1,9 +1,5 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.UI; using UnityExplorer.UI;
@ -20,17 +16,17 @@ namespace UnityExplorer.Config
// Actual UE Settings // Actual UE Settings
public static ConfigElement<KeyCode> Master_Toggle; 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<bool> Hide_On_Startup;
public static ConfigElement<float> Startup_Delay_Time; public static ConfigElement<float> Startup_Delay_Time;
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<string> Reflection_Signature_Blacklist; public static ConfigElement<string> Reflection_Signature_Blacklist;
public static ConfigElement<UIManager.VerticalAnchor> Main_Navbar_Anchor;
public static ConfigElement<KeyCode> World_MouseInspect_Keybind; public static ConfigElement<KeyCode> World_MouseInspect_Keybind;
public static ConfigElement<KeyCode> UI_MouseInspect_Keybind; public static ConfigElement<KeyCode> UI_MouseInspect_Keybind;
@ -58,6 +54,10 @@ namespace UnityExplorer.Config
Handler.LoadConfig(); Handler.LoadConfig();
InternalHandler.LoadConfig(); InternalHandler.LoadConfig();
#if STANDALONE
Loader.Standalone.ExplorerEditorBehaviour.Instance?.LoadConfigs();
#endif
//InitConsoleCallback(); //InitConsoleCallback();
} }
@ -81,26 +81,18 @@ namespace UnityExplorer.Config
"The key to enable or disable UnityExplorer's menu and features.", "The key to enable or disable UnityExplorer's menu and features.",
KeyCode.F7); KeyCode.F7);
Target_Display = new ConfigElement<int>("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",
"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", Hide_On_Startup = new ConfigElement<bool>("Hide On Startup",
"Should UnityExplorer be hidden on startup?", "Should UnityExplorer be hidden on startup?",
false); false);
World_MouseInspect_Keybind = new("World Mouse-Inspect Keybind", Startup_Delay_Time = new ConfigElement<float>("Startup Delay Time",
"Optional keybind to being a World-mode Mouse Inspect.", "The delay on startup before the UI is created.",
KeyCode.None); 1f);
UI_MouseInspect_Keybind = new("UI Mouse-Inspect Keybind", Target_Display = new ConfigElement<int>("Target Display",
"Optional keybind to begin a UI_mode Mouse Inspect.", "The monitor index for UnityExplorer to use, if you have multiple. 0 is the default display, 1 is secondary, etc. " +
KeyCode.None); "Restart recommended when changing this setting. Make sure your extra monitors are the same resolution as your primary monitor.",
0);
Force_Unlock_Mouse = new ConfigElement<bool>("Force Unlock Mouse", Force_Unlock_Mouse = new ConfigElement<bool>("Force Unlock Mouse",
"Force the Cursor to be unlocked (visible) when the UnityExplorer menu is open.", "Force the Cursor to be unlocked (visible) when the UnityExplorer menu is open.",
@ -116,17 +108,29 @@ namespace UnityExplorer.Config
false); false);
Disable_EventSystem_Override.OnValueChanged += (bool value) => UniverseLib.Config.ConfigManager.Disable_EventSystem_Override = value; 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", Default_Output_Path = new ConfigElement<string>("Default Output Path",
"The default output path when exporting things from UnityExplorer.", "The default output path when exporting things from UnityExplorer.",
Path.Combine(ExplorerCore.ExplorerFolder, "Output")); Path.Combine(ExplorerCore.ExplorerFolder, "Output"));
Startup_Delay_Time = new ConfigElement<float>("Startup Delay Time", DnSpy_Path = new ConfigElement<string>("dnSpy Path",
"The delay on startup before the UI is created.", "The full path to dnSpy.exe (64-bit).",
1f); @"C:/Program Files/dnspy/dnSpy.exe");
Main_Navbar_Anchor = new ConfigElement<UIManager.VerticalAnchor>("Main Navbar Anchor",
"The vertical anchor of the main UnityExplorer Navbar, in case you want to move it.",
UIManager.VerticalAnchor.Top);
Log_Unity_Debug = new ConfigElement<bool>("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.",
KeyCode.None);
Reflection_Signature_Blacklist = new ConfigElement<string>("Member Signature Blacklist", Reflection_Signature_Blacklist = new ConfigElement<string>("Member Signature Blacklist",
"Use this to blacklist certain member signatures if they are known to cause a crash or other issues.\r\n" + "Use this to blacklist certain member signatures if they are known to cause a crash or other issues.\r\n" +

View File

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

View File

@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Reflection;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.UI;
using UniverseLib;
#if CPP #if CPP
using UnhollowerRuntimeLib; using UnhollowerRuntimeLib;
#endif #endif
@ -14,7 +14,7 @@ namespace UnityExplorer
internal static ExplorerBehaviour Instance { get; private set; } internal static ExplorerBehaviour Instance { get; private set; }
#if CPP #if CPP
public ExplorerBehaviour(IntPtr ptr) : base(ptr) { } public ExplorerBehaviour(System.IntPtr ptr) : base(ptr) { }
#endif #endif
internal static void Setup() internal static void Setup()
@ -33,5 +33,39 @@ namespace UnityExplorer
{ {
ExplorerCore.Update(); 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,7 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using UnityEngine; using UnityEngine;
using UnityExplorer.CacheObject;
using UnityExplorer.Config; using UnityExplorer.Config;
using UnityExplorer.ObjectExplorer; using UnityExplorer.ObjectExplorer;
using UnityExplorer.Runtime; using UnityExplorer.Runtime;
@ -15,7 +14,7 @@ namespace UnityExplorer
public static class ExplorerCore public static class ExplorerCore
{ {
public const string NAME = "UnityExplorer"; public const string NAME = "UnityExplorer";
public const string VERSION = "4.7.1"; public const string VERSION = "4.8.0";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer"; public const string GUID = "com.sinai.unityexplorer";
@ -58,8 +57,6 @@ namespace UnityExplorer
// Default delay is 1 second which is usually enough. // Default delay is 1 second which is usually enough.
static void LateInit() static void LateInit()
{ {
Log($"Setting up late core features...");
SceneHandler.Init(); SceneHandler.Init();
Log($"Creating UI..."); Log($"Creating UI...");
@ -67,6 +64,8 @@ namespace UnityExplorer
UIManager.InitUI(); UIManager.InitUI();
Log($"{NAME} {VERSION} ({Universe.Context}) initialized."); Log($"{NAME} {VERSION} ({Universe.Context}) initialized.");
// InspectorManager.Inspect(typeof(Tests.TestClass));
} }
internal static void Update() internal static void Update()
@ -76,60 +75,6 @@ namespace UnityExplorer
UIManager.ShowMenu = !UIManager.ShowMenu; UIManager.ShowMenu = !UIManager.ShowMenu;
} }
// 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 #region LOGGING
@ -175,5 +120,63 @@ namespace UnityExplorer
} }
#endregion #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,7 @@
using System; using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.UI.Widgets.ScrollView;
namespace UnityExplorer.Hooks namespace UnityExplorer.Hooks
@ -23,14 +16,13 @@ namespace UnityExplorer.Hooks
public float DefaultHeight => 30; public float DefaultHeight => 30;
public Text MethodNameLabel; public Text MethodNameLabel;
public Text HookedLabel;
public ButtonRef HookButton; public ButtonRef HookButton;
public int CurrentDisplayedIndex; public int CurrentDisplayedIndex;
private void OnHookClicked() private void OnHookClicked()
{ {
HookManager.Instance.AddHookClicked(CurrentDisplayedIndex); HookCreator.AddHookClicked(CurrentDisplayedIndex);
} }
public void Enable() public void Enable()
@ -51,9 +43,6 @@ namespace UnityExplorer.Hooks
UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600); UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600);
UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize; 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)); HookButton = UIFactory.CreateButton(UIRoot, "HookButton", "Hook", new Color(0.2f, 0.25f, 0.2f));
UIFactory.SetLayoutElement(HookButton.Component.gameObject, minHeight: 25, minWidth: 100); UIFactory.SetLayoutElement(HookButton.Component.gameObject, minHeight: 25, minWidth: 100);
HookButton.OnClick += OnHookClicked; HookButton.OnClick += OnHookClicked;

View File

@ -1,12 +1,8 @@
using System; using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.Panels;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.UI.Widgets.ScrollView;
namespace UnityExplorer.Hooks namespace UnityExplorer.Hooks
@ -29,17 +25,18 @@ namespace UnityExplorer.Hooks
private void OnToggleActiveClicked() private void OnToggleActiveClicked()
{ {
HookManager.Instance.EnableOrDisableHookClicked(CurrentDisplayedIndex); HookList.EnableOrDisableHookClicked(CurrentDisplayedIndex);
} }
private void OnDeleteClicked() private void OnDeleteClicked()
{ {
HookManager.Instance.DeleteHookClicked(CurrentDisplayedIndex); HookList.DeleteHookClicked(CurrentDisplayedIndex);
HookCreator.AddHooksScrollPool.Refresh(true, false);
} }
private void OnEditPatchClicked() private void OnEditPatchClicked()
{ {
HookManager.Instance.EditPatchClicked(CurrentDisplayedIndex); HookList.EditPatchClicked(CurrentDisplayedIndex);
} }
public GameObject CreateContent(GameObject parent) public GameObject CreateContent(GameObject parent)
@ -53,18 +50,18 @@ namespace UnityExplorer.Hooks
MethodNameLabel = UIFactory.CreateLabel(UIRoot, "MethodName", "NOT SET", TextAnchor.MiddleLeft); MethodNameLabel = UIFactory.CreateLabel(UIRoot, "MethodName", "NOT SET", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(MethodNameLabel.gameObject, minHeight: 25, flexibleWidth: 9999); UIFactory.SetLayoutElement(MethodNameLabel.gameObject, minHeight: 25, flexibleWidth: 9999);
ToggleActiveButton = UIFactory.CreateButton(UIRoot, "ToggleActiveBtn", "Enabled", new Color(0.15f, 0.2f, 0.15f)); ToggleActiveButton = UIFactory.CreateButton(UIRoot, "ToggleActiveBtn", "On", new Color(0.15f, 0.2f, 0.15f));
UIFactory.SetLayoutElement(ToggleActiveButton.Component.gameObject, minHeight: 25, minWidth: 100); UIFactory.SetLayoutElement(ToggleActiveButton.Component.gameObject, minHeight: 25, minWidth: 35);
ToggleActiveButton.OnClick += OnToggleActiveClicked; ToggleActiveButton.OnClick += OnToggleActiveClicked;
DeleteButton = UIFactory.CreateButton(UIRoot, "DeleteButton", "Delete", new Color(0.2f, 0.15f, 0.15f)); EditPatchButton = UIFactory.CreateButton(UIRoot, "EditButton", "Edit", new Color(0.15f, 0.15f, 0.15f));
UIFactory.SetLayoutElement(DeleteButton.Component.gameObject, minHeight: 25, minWidth: 100); UIFactory.SetLayoutElement(EditPatchButton.Component.gameObject, minHeight: 25, minWidth: 35);
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.OnClick += OnEditPatchClicked; 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; return UIRoot;
} }

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

@ -0,0 +1,339 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CSConsole;
using UnityExplorer.Runtime;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility;
namespace UnityExplorer.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);
}
}
// 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,11 +1,11 @@
using System; using HarmonyLib;
using System.CodeDom.Compiler; using Mono.CSharp;
using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using HarmonyLib;
using Mono.CSharp;
using UnityExplorer.CSConsole; using UnityExplorer.CSConsole;
using UniverseLib; using UniverseLib;
@ -15,12 +15,13 @@ namespace UnityExplorer.Hooks
{ {
// Static // Static
private static readonly StringBuilder evalOutput = new(); static readonly StringBuilder evaluatorOutput;
private static readonly ScriptEvaluator scriptEvaluator = new(new StringWriter(evalOutput)); static readonly ScriptEvaluator scriptEvaluator = new(new StringWriter(evaluatorOutput = new StringBuilder()));
static HookInstance() static HookInstance()
{ {
scriptEvaluator.Run("using System;"); scriptEvaluator.Run("using System;");
scriptEvaluator.Run("using System.Text;");
scriptEvaluator.Run("using System.Reflection;"); scriptEvaluator.Run("using System.Reflection;");
scriptEvaluator.Run("using System.Collections;"); scriptEvaluator.Run("using System.Collections;");
scriptEvaluator.Run("using System.Collections.Generic;"); scriptEvaluator.Run("using System.Collections.Generic;");
@ -29,21 +30,22 @@ namespace UnityExplorer.Hooks
// Instance // Instance
public bool Enabled; public bool Enabled;
public MethodInfo TargetMethod; public MethodInfo TargetMethod;
public string PatchSourceCode; public string PatchSourceCode;
private readonly string shortSignature; readonly string signature;
private PatchProcessor patchProcessor; PatchProcessor patchProcessor;
private MethodInfo postfix; MethodInfo postfix;
private MethodInfo prefix; MethodInfo prefix;
private MethodInfo finalizer; MethodInfo finalizer;
private MethodInfo transpiler; MethodInfo transpiler;
public HookInstance(MethodInfo targetMethod) public HookInstance(MethodInfo targetMethod)
{ {
this.TargetMethod = targetMethod; this.TargetMethod = targetMethod;
this.shortSignature = $"{targetMethod.DeclaringType.Name}.{targetMethod.Name}"; this.signature = TargetMethod.FullDescription();
GenerateDefaultPatchSourceCode(targetMethod); GenerateDefaultPatchSourceCode(targetMethod);
@ -60,15 +62,15 @@ namespace UnityExplorer.Hooks
{ {
Unpatch(); Unpatch();
StringBuilder codeBuilder = new();
try try
{ {
patchProcessor = ExplorerCore.Harmony.CreateProcessor(TargetMethod); patchProcessor = ExplorerCore.Harmony.CreateProcessor(TargetMethod);
// Dynamically compile the patch method // Dynamically compile the patch method
var codeBuilder = new StringBuilder(); codeBuilder.AppendLine($"static class DynamicPatch_{DateTime.Now.Ticks}");
codeBuilder.AppendLine($"public class DynamicPatch_{DateTime.Now.Ticks}");
codeBuilder.AppendLine("{"); codeBuilder.AppendLine("{");
codeBuilder.AppendLine(patchSource); codeBuilder.AppendLine(patchSource);
codeBuilder.AppendLine("}"); codeBuilder.AppendLine("}");
@ -80,11 +82,11 @@ namespace UnityExplorer.Hooks
// TODO: Publicize MCS to avoid this reflection // TODO: Publicize MCS to avoid this reflection
// Get the most recent Patch type in the source file // 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 .Containers
.Last(it => it.MemberName.Name.StartsWith("DynamicPatch_")); .Last(it => it.MemberName.Name.StartsWith("DynamicPatch_"));
// Get the TypeSpec from the TypeDefinition, then get its "MetaInfo" (System.Type) // 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 // Create the harmony patches as defined
@ -108,85 +110,108 @@ namespace UnityExplorer.Hooks
} }
catch (Exception ex) 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; 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) private string GenerateDefaultPatchSourceCode(MethodInfo targetMethod)
{ {
var codeBuilder = new StringBuilder(); StringBuilder codeBuilder = new();
// Arguments
codeBuilder.Append("public static void Postfix(System.Reflection.MethodBase __originalMethod"); codeBuilder.Append("static void Postfix(");
if (!targetMethod.IsStatic) bool isStatic = targetMethod.IsStatic;
codeBuilder.Append($", {targetMethod.DeclaringType.FullName} __instance");
List<string> arguments = new();
if (!isStatic)
arguments.Add($"{FullDescriptionClean(targetMethod.DeclaringType)} __instance");
if (targetMethod.ReturnType != typeof(void)) 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; 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++; paramIdx++;
} }
codeBuilder.Append(string.Join(", ", arguments.ToArray()));
codeBuilder.Append(")\n"); codeBuilder.Append(")\n");
// Patch body // Patch body
codeBuilder.AppendLine("{"); codeBuilder.AppendLine("{");
codeBuilder.AppendLine(" try {"); codeBuilder.AppendLine(" try {");
codeBuilder.AppendLine(" StringBuilder sb = new StringBuilder();");
// Log message codeBuilder.AppendLine($" sb.AppendLine(\"--------------------\");");
codeBuilder.AppendLine($" sb.AppendLine(\"{signature}\");");
var logMessage = new StringBuilder();
logMessage.Append($"Patch called: {shortSignature}\\n");
if (!targetMethod.IsStatic) if (!targetMethod.IsStatic)
logMessage.Append("__instance: {__instance.ToString()}\\n"); codeBuilder.AppendLine($" sb.Append(\"- __instance: \").AppendLine(__instance.ToString());");
paramIdx = 0; 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; Type pType = param.ParameterType;
if (pType.IsByRef) pType = pType.GetElementType(); if (pType.IsByRef) pType = pType.GetElementType();
if (pType.IsValueType) if (pType.IsValueType)
logMessage.Append($"{{__{paramIdx}.ToString()}}"); codeBuilder.AppendLine($".AppendLine(__{paramIdx}.ToString());");
else else
logMessage.Append($"{{__{paramIdx}?.ToString() ?? \"null\"}}"); codeBuilder.AppendLine($".AppendLine(__{paramIdx}?.ToString() ?? \"null\");");
logMessage.Append("\\n");
paramIdx++; paramIdx++;
} }
if (targetMethod.ReturnType != typeof(void)) if (targetMethod.ReturnType != typeof(void))
{ {
logMessage.Append("Return value: "); codeBuilder.Append(" sb.Append(\"- Return value: \")");
if (targetMethod.ReturnType.IsValueType) if (targetMethod.ReturnType.IsValueType)
logMessage.Append("{__result.ToString()}"); codeBuilder.AppendLine(".AppendLine(__result.ToString());");
else else
logMessage.Append("{__result?.ToString() ?? \"null\"}"); codeBuilder.AppendLine(".AppendLine(__result?.ToString() ?? \"null\");");
logMessage.Append("\\n");
} }
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.Log($\"{logMessage}\");"); codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.Log(sb.ToString());");
codeBuilder.AppendLine(" }"); codeBuilder.AppendLine(" }");
codeBuilder.AppendLine(" catch (System.Exception ex) {"); 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(" }"); codeBuilder.AppendLine(" }");
// End patch body
codeBuilder.AppendLine("}"); codeBuilder.AppendLine("}");
//ExplorerCore.Log(codeBuilder.ToString());
return PatchSourceCode = codeBuilder.ToString(); return PatchSourceCode = codeBuilder.ToString();
} }

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

@ -0,0 +1,97 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.Panels;
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility;
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

@ -2,18 +2,15 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UniverseLib.Input;
using UnityExplorer.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI.Widgets;
using UniverseLib.UI;
using UniverseLib; using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility; using UniverseLib.Utility;
@ -21,15 +18,15 @@ namespace UnityExplorer.Inspectors
{ {
public class GameObjectInspector : InspectorBase public class GameObjectInspector : InspectorBase
{ {
public GameObject GOTarget => Target as GameObject; public new GameObject Target => base.Target as GameObject;
public GameObject Content; public GameObject Content;
public GameObjectControls GOControls; public GameObjectControls Controls;
public TransformTree TransformTree; public TransformTree TransformTree;
private ScrollPool<TransformCell> transformScroll; private ScrollPool<TransformCell> transformScroll;
private readonly List<GameObject> cachedChildren = new List<GameObject>(); private readonly List<GameObject> cachedChildren = new();
public ComponentList ComponentList; public ComponentList ComponentList;
private ScrollPool<ComponentCell> componentScroll; private ScrollPool<ComponentCell> componentScroll;
@ -41,10 +38,10 @@ namespace UnityExplorer.Inspectors
{ {
base.OnBorrowedFromPool(target); base.OnBorrowedFromPool(target);
Target = target as GameObject; base.Target = target as GameObject;
GOControls.UpdateGameObjectInfo(true, true); Controls.UpdateGameObjectInfo(true, true);
GOControls.UpdateTransformControlValues(true); Controls.TransformControl.UpdateTransformControlValues(true);
RuntimeHelper.StartCoroutine(InitCoroutine()); RuntimeHelper.StartCoroutine(InitCoroutine());
} }
@ -77,11 +74,11 @@ namespace UnityExplorer.Inspectors
InspectorManager.ReleaseInspector(this); InspectorManager.ReleaseInspector(this);
} }
public void ChangeTarget(GameObject newTarget) public void OnTransformCellClicked(GameObject newTarget)
{ {
this.Target = newTarget; base.Target = newTarget;
GOControls.UpdateGameObjectInfo(true, true); Controls.UpdateGameObjectInfo(true, true);
GOControls.UpdateTransformControlValues(true); Controls.TransformControl.UpdateTransformControlValues(true);
TransformTree.RefreshData(true, false, true, false); TransformTree.RefreshData(true, false, true, false);
UpdateComponents(); UpdateComponents();
} }
@ -93,21 +90,21 @@ namespace UnityExplorer.Inspectors
if (!this.IsActive) if (!this.IsActive)
return; return;
if (Target.IsNullOrDestroyed(false)) if (base.Target.IsNullOrDestroyed(false))
{ {
InspectorManager.ReleaseInspector(this); InspectorManager.ReleaseInspector(this);
return; return;
} }
GOControls.UpdateVectorSlider(); Controls.UpdateVectorSlider();
GOControls.UpdateTransformControlValues(false); Controls.TransformControl.UpdateTransformControlValues(false);
// Slow update // Slow update
if (timeOfLastUpdate.OccuredEarlierThan(1)) if (timeOfLastUpdate.OccuredEarlierThan(1))
{ {
timeOfLastUpdate = Time.realtimeSinceStartup; timeOfLastUpdate = Time.realtimeSinceStartup;
GOControls.UpdateGameObjectInfo(false, false); Controls.UpdateGameObjectInfo(false, false);
TransformTree.RefreshData(true, false, false, false); TransformTree.RefreshData(true, false, false, false);
UpdateComponents(); UpdateComponents();
@ -118,26 +115,26 @@ namespace UnityExplorer.Inspectors
private IEnumerable<GameObject> GetTransformEntries() private IEnumerable<GameObject> GetTransformEntries()
{ {
if (!GOTarget) if (!Target)
return Enumerable.Empty<GameObject>(); return Enumerable.Empty<GameObject>();
cachedChildren.Clear(); cachedChildren.Clear();
for (int i = 0; i < GOTarget.transform.childCount; i++) for (int i = 0; i < Target.transform.childCount; i++)
cachedChildren.Add(GOTarget.transform.GetChild(i).gameObject); cachedChildren.Add(Target.transform.GetChild(i).gameObject);
return cachedChildren; return cachedChildren;
} }
private readonly List<Component> componentEntries = new List<Component>(); private readonly List<Component> componentEntries = new();
private readonly HashSet<int> compInstanceIDs = new HashSet<int>(); private readonly HashSet<int> compInstanceIDs = new();
private readonly List<Behaviour> behaviourEntries = new List<Behaviour>(); private readonly List<Behaviour> behaviourEntries = new();
private readonly List<bool> behaviourEnabledStates = new List<bool>(); private readonly List<bool> behaviourEnabledStates = new();
// ComponentList.GetRootEntriesMethod // 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() public void UpdateComponents()
{ {
if (!GOTarget) if (!Target)
{ {
componentEntries.Clear(); componentEntries.Clear();
compInstanceIDs.Clear(); compInstanceIDs.Clear();
@ -149,13 +146,13 @@ namespace UnityExplorer.Inspectors
} }
// Check if we actually need to refresh the component cells or not. // Check if we actually need to refresh the component cells or not.
var comps = GOTarget.GetComponents<Component>(); IEnumerable<Component> comps = Target.GetComponents<Component>();
var behaviours = GOTarget.GetComponents<Behaviour>(); IEnumerable<Behaviour> behaviours = Target.GetComponents<Behaviour>();
bool needRefresh = false; bool needRefresh = false;
int count = 0; int count = 0;
foreach (var comp in comps) foreach (Component comp in comps)
{ {
if (!comp) if (!comp)
continue; continue;
@ -173,7 +170,7 @@ namespace UnityExplorer.Inspectors
else else
{ {
count = 0; count = 0;
foreach (var behaviour in behaviours) foreach (Behaviour behaviour in behaviours)
{ {
if (!behaviour) if (!behaviour)
continue; continue;
@ -194,19 +191,35 @@ namespace UnityExplorer.Inspectors
componentEntries.Clear(); componentEntries.Clear();
compInstanceIDs.Clear(); compInstanceIDs.Clear();
foreach (var comp in comps) foreach (Component comp in comps)
{ {
if (!comp) continue; if (!comp)
continue;
componentEntries.Add(comp); componentEntries.Add(comp);
compInstanceIDs.Add(comp.GetInstanceID()); compInstanceIDs.Add(comp.GetInstanceID());
} }
behaviourEntries.Clear(); behaviourEntries.Clear();
behaviourEnabledStates.Clear(); behaviourEnabledStates.Clear();
foreach (var behaviour in behaviours) foreach (Behaviour behaviour in behaviours)
{
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
{ {
if (!behaviour) continue;
behaviourEntries.Add(behaviour); behaviourEntries.Add(behaviour);
}
catch (Exception ex)
{
ExplorerCore.LogWarning(ex);
}
behaviourEnabledStates.Add(behaviour.enabled); behaviourEnabledStates.Add(behaviour.enabled);
} }
@ -217,8 +230,8 @@ namespace UnityExplorer.Inspectors
private void OnAddChildClicked(string input) private void OnAddChildClicked(string input)
{ {
var newObject = new GameObject(input); GameObject newObject = new(input);
newObject.transform.parent = GOTarget.transform; newObject.transform.parent = Target.transform;
TransformTree.RefreshData(true, false, true, false); TransformTree.RefreshData(true, false, true, false);
} }
@ -229,7 +242,7 @@ namespace UnityExplorer.Inspectors
{ {
try try
{ {
RuntimeHelper.AddComponent<Component>(GOTarget, type); RuntimeHelper.AddComponent<Component>(Target, type);
UpdateComponents(); UpdateComponents();
} }
catch (Exception ex) catch (Exception ex)
@ -250,14 +263,14 @@ namespace UnityExplorer.Inspectors
UIRoot = UIFactory.CreateVerticalGroup(parent, "GameObjectInspector", true, false, true, true, 5, UIRoot = UIFactory.CreateVerticalGroup(parent, "GameObjectInspector", true, false, true, true, 5,
new Vector4(4, 4, 4, 4), new Color(0.065f, 0.065f, 0.065f)); new Vector4(4, 4, 4, 4), new Color(0.065f, 0.065f, 0.065f));
var scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out var scrollbar, GameObject scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out AutoSliderScrollbar scrollbar,
new Color(0.065f, 0.065f, 0.065f)); new Color(0.065f, 0.065f, 0.065f));
UIFactory.SetLayoutElement(scrollObj, minHeight: 250, preferredHeight: 300, flexibleHeight: 0, flexibleWidth: 9999); UIFactory.SetLayoutElement(scrollObj, minHeight: 250, preferredHeight: 300, flexibleHeight: 0, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2); UIFactory.SetLayoutGroup<VerticalLayoutGroup>(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2);
// Construct GO Controls // Construct GO Controls
GOControls = new GameObjectControls(this); Controls = new GameObjectControls(this);
ConstructLists(); ConstructLists();
@ -268,27 +281,27 @@ namespace UnityExplorer.Inspectors
private void ConstructLists() 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.SetLayoutGroup<HorizontalLayoutGroup>(listHolder, false, true, true, true, 8, 2, 2, 2, 2);
UIFactory.SetLayoutElement(listHolder, minHeight: 150, flexibleWidth: 9999, flexibleHeight: 9999); UIFactory.SetLayoutElement(listHolder, minHeight: 150, flexibleWidth: 9999, flexibleHeight: 9999);
// Left group (Children) // Left group (Children)
var leftGroup = UIFactory.CreateUIObject("ChildrenGroup", listHolder); GameObject leftGroup = UIFactory.CreateUIObject("ChildrenGroup", listHolder);
UIFactory.SetLayoutElement(leftGroup, flexibleWidth: 9999, flexibleHeight: 9999); UIFactory.SetLayoutElement(leftGroup, flexibleWidth: 9999, flexibleHeight: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(leftGroup, false, false, true, true, 2); 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); UIFactory.SetLayoutElement(childrenLabel.gameObject, flexibleWidth: 9999);
// Add Child // Add Child
var addChildRow = UIFactory.CreateUIObject("AddChildRow", leftGroup); GameObject addChildRow = UIFactory.CreateUIObject("AddChildRow", leftGroup);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(addChildRow, false, false, true, true, 2); UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(addChildRow, false, false, true, true, 2);
addChildInput = UIFactory.CreateInputField(addChildRow, "AddChildInput", "Enter a name..."); addChildInput = UIFactory.CreateInputField(addChildRow, "AddChildInput", "Enter a name...");
UIFactory.SetLayoutElement(addChildInput.Component.gameObject, minHeight: 25, preferredWidth: 9999); 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); UIFactory.SetLayoutElement(addChildButton.Component.gameObject, minHeight: 25, minWidth: 80);
addChildButton.OnClick += () => { OnAddChildClicked(addChildInput.Text); }; addChildButton.OnClick += () => { OnAddChildClicked(addChildInput.Text); };
@ -296,35 +309,31 @@ namespace UnityExplorer.Inspectors
transformScroll = UIFactory.CreateScrollPool<TransformCell>(leftGroup, "TransformTree", out GameObject transformObj, transformScroll = UIFactory.CreateScrollPool<TransformCell>(leftGroup, "TransformTree", out GameObject transformObj,
out GameObject transformContent, new Color(0.11f, 0.11f, 0.11f)); 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 = new TransformTree(transformScroll, GetTransformEntries, OnTransformCellClicked);
TransformTree.Init();
TransformTree.OnClickOverrideHandler = ChangeTarget;
// Right group (Components) // Right group (Components)
var rightGroup = UIFactory.CreateUIObject("ComponentGroup", listHolder); GameObject rightGroup = UIFactory.CreateUIObject("ComponentGroup", listHolder);
UIFactory.SetLayoutElement(rightGroup, flexibleWidth: 9999, flexibleHeight: 9999); UIFactory.SetLayoutElement(rightGroup, flexibleWidth: 9999, flexibleHeight: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(rightGroup, false, false, true, true, 2); 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); UIFactory.SetLayoutElement(compLabel.gameObject, flexibleWidth: 9999);
// Add Comp // Add Comp
var addCompRow = UIFactory.CreateUIObject("AddCompRow", rightGroup); GameObject addCompRow = UIFactory.CreateUIObject("AddCompRow", rightGroup);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(addCompRow, false, false, true, true, 2); UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(addCompRow, false, false, true, true, 2);
addCompInput = UIFactory.CreateInputField(addCompRow, "AddCompInput", "Enter a Component type..."); addCompInput = UIFactory.CreateInputField(addCompRow, "AddCompInput", "Enter a Component type...");
UIFactory.SetLayoutElement(addCompInput.Component.gameObject, minHeight: 25, preferredWidth: 9999); 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); UIFactory.SetLayoutElement(addCompButton.Component.gameObject, minHeight: 25, minWidth: 80);
addCompButton.OnClick += () => { OnAddComponentClicked(addCompInput.Text); }; addCompButton.OnClick += () => { OnAddComponentClicked(addCompInput.Text); };
// comp autocompleter // comp autocompleter
new TypeCompleter(typeof(Component), addCompInput); new TypeCompleter(typeof(Component), addCompInput, false, false, false);
// Component List // Component List
@ -333,8 +342,10 @@ namespace UnityExplorer.Inspectors
UIFactory.SetLayoutElement(compObj, flexibleHeight: 9999); UIFactory.SetLayoutElement(compObj, flexibleHeight: 9999);
UIFactory.SetLayoutElement(compContent, flexibleHeight: 9999); UIFactory.SetLayoutElement(compContent, flexibleHeight: 9999);
ComponentList = new ComponentList(componentScroll, GetComponentEntries); ComponentList = new ComponentList(componentScroll, GetComponentEntries)
ComponentList.Parent = this; {
Parent = this
};
componentScroll.Initialize(ComponentList); 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,8 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UniverseLib.UI; using UniverseLib;
using UniverseLib.UI.ObjectPool; using UniverseLib.UI.ObjectPool;
namespace UnityExplorer.Inspectors namespace UnityExplorer.Inspectors
@ -16,6 +11,7 @@ namespace UnityExplorer.Inspectors
{ {
public bool IsActive { get; internal set; } public bool IsActive { get; internal set; }
public object Target { get; set; } public object Target { get; set; }
public Type TargetType { get; protected set; }
public InspectorTab Tab { get; internal set; } public InspectorTab Tab { get; internal set; }
@ -31,6 +27,8 @@ namespace UnityExplorer.Inspectors
public virtual void OnBorrowedFromPool(object target) public virtual void OnBorrowedFromPool(object target)
{ {
this.Target = target; this.Target = target;
this.TargetType = target is Type type ? type : target.GetActualType();
Tab = Pool<InspectorTab>.Borrow(); Tab = Pool<InspectorTab>.Borrow();
Tab.UIRoot.transform.SetParent(InspectorPanel.Instance.NavbarHolder.transform, false); Tab.UIRoot.transform.SetParent(InspectorPanel.Instance.NavbarHolder.transform, false);

View File

@ -1,16 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.CacheObject; using UnityExplorer.CacheObject;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using UniverseLib.UI.Models; using UnityExplorer.UI;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UniverseLib; using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.ObjectPool; using UniverseLib.UI.ObjectPool;
using UniverseLib.Utility; using UniverseLib.Utility;
@ -27,7 +23,7 @@ namespace UnityExplorer
public static event Action OnInspectedTabsChanged; 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()) if (obj.IsNullOrDestroyed())
return; return;
@ -40,19 +36,34 @@ namespace UnityExplorer
if (obj is GameObject) if (obj is GameObject)
CreateInspector<GameObjectInspector>(obj); CreateInspector<GameObjectInspector>(obj);
else else
CreateInspector<ReflectionInspector>(obj, false, sourceCache); CreateInspector<ReflectionInspector>(obj, false, parent);
} }
public static void Inspect(Type type) public static void Inspect(Type type)
{ {
if (TryFocusActiveInspector(type))
return;
CreateInspector<ReflectionInspector>(type, true); 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); UIManager.SetPanelActive(UIManager.Panels.Inspector, true);
SetInspectorActive(inspector); SetInspectorActive(inspector);
@ -80,7 +91,7 @@ namespace UnityExplorer
} }
} }
internal static void CloseAllTabs() public static void CloseAllTabs()
{ {
if (Inspectors.Any()) if (Inspectors.Any())
{ {
@ -93,18 +104,17 @@ namespace UnityExplorer
UIManager.SetPanelActive(UIManager.Panels.Inspector, false); UIManager.SetPanelActive(UIManager.Panels.Inspector, false);
} }
private static void CreateInspector<T>(object target, bool staticReflection = false, static void CreateInspector<T>(object target, bool staticReflection = false, CacheObjectBase parent = null) where T : InspectorBase
CacheObjectBase parentObject = null) where T : InspectorBase
{ {
var inspector = Pool<T>.Borrow(); T inspector = Pool<T>.Borrow();
Inspectors.Add(inspector); Inspectors.Add(inspector);
inspector.Target = target; 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. // only set parent cache object if we are inspecting a struct, otherwise there is no point.
if (target.GetType().IsValueType && inspector is ReflectionInspector ri) if (target.GetType().IsValueType && inspector is ReflectionInspector ri)
ri.ParentCacheObject = parentObject; ri.ParentCacheObject = parent;
} }
UIManager.SetPanelActive(UIManager.Panels.Inspector, true); UIManager.SetPanelActive(UIManager.Panels.Inspector, true);
@ -119,7 +129,7 @@ namespace UnityExplorer
OnInspectedTabsChanged?.Invoke(); 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) if (lastActiveInspector == inspector)
lastActiveInspector = null; lastActiveInspector = null;
@ -164,7 +174,7 @@ namespace UnityExplorer
{ {
PanelWidth = width; PanelWidth = width;
foreach (var obj in Inspectors) foreach (InspectorBase obj in Inspectors)
{ {
if (obj is ReflectionInspector inspector) if (obj is ReflectionInspector inspector)
{ {

View File

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

View File

@ -1,19 +1,13 @@
using System; using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
using UniverseLib.Input; using UnityExplorer.Config;
using UnityExplorer.Runtime;
using UnityExplorer.Inspectors.MouseInspectors; using UnityExplorer.Inspectors.MouseInspectors;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UniverseLib; using UniverseLib.Input;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Panels;
using UniverseLib.Utility; using UniverseLib.Utility;
using UnityExplorer.Config;
namespace UnityExplorer.Inspectors namespace UnityExplorer.Inspectors
{ {
@ -23,7 +17,7 @@ namespace UnityExplorer.Inspectors
UI UI
} }
public class MouseInspector : UIPanel public class MouseInspector : PanelBase
{ {
public static MouseInspector Instance { get; private set; } public static MouseInspector Instance { get; private set; }
@ -44,22 +38,21 @@ namespace UnityExplorer.Inspectors
// UIPanel // UIPanel
internal static readonly string UIBaseGUID = $"{ExplorerCore.GUID}.MouseInspector"; internal static readonly string UIBaseGUID = $"{ExplorerCore.GUID}.MouseInspector";
private UIBase inspectorUIBase; internal static UIBase inspectorUIBase;
public override string Name => "Inspect Under Mouse"; public override string Name => "Inspect Under Mouse";
public override UIManager.Panels PanelType => UIManager.Panels.MouseInspector;
public override int MinWidth => -1; public override int MinWidth => -1;
public override int MinHeight => -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 CanDragAndResize => false;
public override bool NavButtonWanted => false;
public override bool ShouldSaveActiveState => false;
public override bool ShowByDefault => false;
internal Text objNameLabel; internal Text objNameLabel;
internal Text objPathLabel; internal Text objPathLabel;
internal Text mousePosLabel; internal Text mousePosLabel;
public MouseInspector() public MouseInspector(UIBase owner) : base(owner)
{ {
Instance = this; Instance = this;
worldInspector = new WorldInspector(); worldInspector = new WorldInspector();
@ -84,11 +77,12 @@ namespace UnityExplorer.Inspectors
CurrentInspector.OnBeginMouseInspect(); CurrentInspector.OnBeginMouseInspect();
PanelDragger.ForceEnd(); PanelManager.ForceEndResize();
UIManager.NavBarRect.gameObject.SetActive(false); 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() internal void ClearHitData()
@ -106,9 +100,9 @@ namespace UnityExplorer.Inspectors
Inspecting = false; Inspecting = false;
UIManager.NavBarRect.gameObject.SetActive(true); 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) if (drop.transform.Find("Dropdown List") is Transform list)
drop.DestroyDropdownList(list.gameObject); drop.DestroyDropdownList(list.gameObject);
@ -152,7 +146,7 @@ namespace UnityExplorer.Inspectors
return; return;
} }
var mousePos = InputManager.MousePosition; Vector3 mousePos = InputManager.MousePosition;
if (mousePos != lastMousePos) if (mousePos != lastMousePos)
UpdatePosition(mousePos); UpdatePosition(mousePos);
@ -181,32 +175,34 @@ namespace UnityExplorer.Inspectors
mousePos.y -= 10; mousePos.y -= 10;
// calculate and set our UI position // 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); UIRoot.transform.localPosition = new Vector3(inversePos.x, inversePos.y, 0);
} }
// UI Construction // UI Construction
protected internal override void DoSetDefaultPosAndAnchors() public override void SetDefaultSizeAndPosition()
{ {
base.SetDefaultSizeAndPosition();
Rect.anchorMin = Vector2.zero; Rect.anchorMin = Vector2.zero;
Rect.anchorMax = Vector2.zero; Rect.anchorMax = Vector2.zero;
Rect.pivot = new Vector2(0.5f, 1); Rect.pivot = new Vector2(0.5f, 1);
Rect.sizeDelta = new Vector2(700, 150); Rect.sizeDelta = new Vector2(700, 150);
} }
public override void ConstructPanelContent() protected override void ConstructPanelContent()
{ {
// hide title bar // hide title bar
this.TitleBar.SetActive(false); this.TitleBar.SetActive(false);
this.UIRoot.transform.SetParent(UIManager.UIRoot.transform, 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); UIFactory.SetLayoutElement(inspectContent, flexibleWidth: 9999, flexibleHeight: 9999);
// Title text // Title text
var title = UIFactory.CreateLabel(inspectContent, Text title = UIFactory.CreateLabel(inspectContent,
"InspectLabel", "InspectLabel",
"<b>Mouse Inspector</b> (press <b>ESC</b> to cancel)", "<b>Mouse Inspector</b> (press <b>ESC</b> to cancel)",
TextAnchor.MiddleCenter); TextAnchor.MiddleCenter);
@ -225,11 +221,10 @@ namespace UnityExplorer.Inspectors
UIRoot.SetActive(false); UIRoot.SetActive(false);
// Create a new canvas for this panel to live on. //// 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. //// 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);
UIRoot.transform.SetParent(inspectorUIBase.RootObject.transform);
} }
} }
} }

View File

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

View File

@ -1,29 +1,26 @@
using System; using System.Collections;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UniverseLib; using UniverseLib;
using UniverseLib.Input;
namespace UnityExplorer.Inspectors.MouseInspectors namespace UnityExplorer.Inspectors.MouseInspectors
{ {
public class UiInspector : MouseInspectorBase 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 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<Graphic> wasDisabledGraphics = new();
private static readonly List<CanvasGroup> wasDisabledCanvasGroups = new List<CanvasGroup>(); private static readonly List<CanvasGroup> wasDisabledCanvasGroups = new();
private static readonly List<GameObject> objectsAddedCastersTo = new List<GameObject>(); private static readonly List<GameObject> objectsAddedCastersTo = new();
public override void OnBeginMouseInspect() public override void OnBeginMouseInspect()
{ {
@ -46,7 +43,7 @@ namespace UnityExplorer.Inspectors.MouseInspectors
IEnumerator SetPanelActiveCoro() IEnumerator SetPanelActiveCoro()
{ {
yield return null; yield return null;
var panel = UIManager.GetPanel<MouseInspectorResultsPanel>(UIManager.Panels.UIInspectorResults); MouseInspectorResultsPanel panel = UIManager.GetPanel<MouseInspectorResultsPanel>(UIManager.Panels.UIInspectorResults);
panel.SetActive(true); panel.SetActive(true);
panel.ShowResults(); panel.ShowResults();
} }
@ -55,21 +52,21 @@ namespace UnityExplorer.Inspectors.MouseInspectors
{ {
currentHitObjects.Clear(); currentHitObjects.Clear();
var ped = new PointerEventData(null) PointerEventData ped = new(null)
{ {
position = mousePos position = mousePos
}; };
foreach (var gr in graphicRaycasters) foreach (GraphicRaycaster gr in graphicRaycasters)
{ {
if (!gr || !gr.canvas) if (!gr || !gr.canvas)
continue; continue;
var list = new List<RaycastResult>(); List<RaycastResult> list = new();
RuntimeHelper.GraphicRaycast(gr, ped, list); RuntimeHelper.GraphicRaycast(gr, ped, list);
if (list.Count > 0) if (list.Count > 0)
{ {
foreach (var hit in list) foreach (RaycastResult hit in list)
{ {
if (hit.gameObject) if (hit.gameObject)
currentHitObjects.Add(hit.gameObject); currentHitObjects.Add(hit.gameObject);
@ -85,9 +82,9 @@ namespace UnityExplorer.Inspectors.MouseInspectors
private static void SetupUIRaycast() 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) if (!canvas || !canvas.enabled || !canvas.gameObject.activeInHierarchy)
continue; continue;
if (!canvas.GetComponent<GraphicRaycaster>()) if (!canvas.GetComponent<GraphicRaycaster>())
@ -99,7 +96,7 @@ namespace UnityExplorer.Inspectors.MouseInspectors
} }
// recache Graphic Raycasters each time we start // 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]; graphicRaycasters = new GraphicRaycaster[casters.Length];
for (int i = 0; i < casters.Length; i++) for (int i = 0; i < casters.Length; i++)
{ {
@ -107,9 +104,9 @@ namespace UnityExplorer.Inspectors.MouseInspectors
} }
// enable raycastTarget on Graphics // 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) if (!graphic || !graphic.enabled || graphic.raycastTarget || !graphic.gameObject.activeInHierarchy)
continue; continue;
graphic.raycastTarget = true; graphic.raycastTarget = true;
@ -118,9 +115,9 @@ namespace UnityExplorer.Inspectors.MouseInspectors
} }
// enable blocksRaycasts on CanvasGroups // 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) if (!canvas || !canvas.gameObject.activeInHierarchy || canvas.blocksRaycasts)
continue; continue;
canvas.blocksRaycasts = true; canvas.blocksRaycasts = true;
@ -131,16 +128,16 @@ namespace UnityExplorer.Inspectors.MouseInspectors
public override void OnEndInspect() public override void OnEndInspect()
{ {
foreach (var obj in objectsAddedCastersTo) foreach (GameObject obj in objectsAddedCastersTo)
{ {
if (obj.GetComponent<GraphicRaycaster>() is GraphicRaycaster raycaster) if (obj.GetComponent<GraphicRaycaster>() is GraphicRaycaster raycaster)
GameObject.Destroy(raycaster); GameObject.Destroy(raycaster);
} }
foreach (var graphic in wasDisabledGraphics) foreach (Graphic graphic in wasDisabledGraphics)
graphic.raycastTarget = false; graphic.raycastTarget = false;
foreach (var canvas in wasDisabledCanvasGroups) foreach (CanvasGroup canvas in wasDisabledCanvasGroups)
canvas.blocksRaycasts = false; canvas.blocksRaycasts = false;
objectsAddedCastersTo.Clear(); objectsAddedCastersTo.Clear();

View File

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

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
@ -8,6 +9,8 @@ using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.CacheObject; using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views; using UnityExplorer.CacheObject.Views;
using UnityExplorer.Config;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
using UniverseLib; using UniverseLib;
@ -33,54 +36,53 @@ namespace UnityExplorer.Inspectors
public class ReflectionInspector : InspectorBase, ICellPoolDataSource<CacheMemberCell>, ICacheObjectController public class ReflectionInspector : InspectorBase, ICellPoolDataSource<CacheMemberCell>, ICacheObjectController
{ {
public CacheObjectBase ParentCacheObject { get; set; } public CacheObjectBase ParentCacheObject { get; set; }
public Type TargetType { get; private set; }
public bool StaticOnly { get; internal set; } public bool StaticOnly { get; internal set; }
public bool CanWrite => true; public bool CanWrite => true;
public bool AutoUpdateWanted => autoUpdateToggle.isOn; public bool AutoUpdateWanted => autoUpdateToggle.isOn;
private List<CacheMember> members = new(); List<CacheMember> members = new();
private readonly List<CacheMember> filteredMembers = new(); readonly List<CacheMember> filteredMembers = new();
private BindingFlags scopeFlagsFilter; string nameFilter;
private string nameFilter; BindingFlags scopeFlagsFilter;
MemberFilter memberFilter = MemberFilter.All;
private MemberFilter MemberFilter = MemberFilter.All;
// Updating // Updating
private bool refreshWanted; bool refreshWanted;
private string lastNameFilter; string lastNameFilter;
private BindingFlags lastFlagsFilter; BindingFlags lastFlagsFilter;
private MemberFilter lastMemberFilter = MemberFilter.All; MemberFilter lastMemberFilter = MemberFilter.All;
private float timeOfLastAutoUpdate; float timeOfLastAutoUpdate;
// UI // UI
internal GameObject mainContentHolder; static int LeftGroupWidth { get; set; }
private static int LeftGroupWidth { get; set; } static int RightGroupWidth { get; set; }
private 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 ScrollPool<CacheMemberCell> MemberScrollPool { get; private set; }
public int ItemCount => filteredMembers.Count; 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; ButtonRef dnSpyButton;
public Text NameText;
public Text AssemblyText;
private Toggle autoUpdateToggle;
internal string currentBaseTabText; ButtonRef makeGenericButton;
GenericConstructorWidget genericConstructor;
private readonly Dictionary<BindingFlags, ButtonRef> scopeFilterButtons = new(); InputFieldRef filterInputField;
private readonly List<Toggle> memberTypeToggles = new(); readonly List<Toggle> memberTypeToggles = new();
private InputFieldRef filterInputField; readonly Dictionary<BindingFlags, ButtonRef> scopeFilterButtons = new();
// const
private readonly Color disabledButtonColor = new(0.24f, 0.24f, 0.24f);
private readonly Color enabledButtonColor = new(0.2f, 0.27f, 0.2f);
// Setup // Setup
@ -107,7 +109,7 @@ namespace UnityExplorer.Inspectors
public override void OnReturnToPool() public override void OnReturnToPool()
{ {
foreach (var member in members) foreach (CacheMember member in members)
{ {
member.UnlinkFromView(); member.UnlinkFromView();
member.ReleasePooledObjects(); member.ReleasePooledObjects();
@ -125,6 +127,8 @@ namespace UnityExplorer.Inspectors
this.UnityWidget = null; this.UnityWidget = null;
} }
genericConstructor?.Cancel();
base.OnReturnToPool(); base.OnReturnToPool();
} }
@ -138,6 +142,8 @@ namespace UnityExplorer.Inspectors
Target = null; Target = null;
TargetType = target as Type; TargetType = target as Type;
prefix = "[S]"; prefix = "[S]";
makeGenericButton.GameObject.SetActive(TargetType.IsGenericTypeDefinition);
} }
else else
{ {
@ -146,17 +152,23 @@ namespace UnityExplorer.Inspectors
} }
// Setup main labels and tab text // Setup main labels and tab text
currentBaseTabText = $"{prefix} {SignatureHighlighter.Parse(TargetType, false)}"; TabButtonText = $"{prefix} {SignatureHighlighter.Parse(TargetType, false)}";
Tab.TabText.text = currentBaseTabText; Tab.TabText.text = TabButtonText;
NameText.text = SignatureHighlighter.Parse(TargetType, true); nameText.text = SignatureHighlighter.Parse(TargetType, true);
HiddenNameText.Text = SignatureHighlighter.RemoveHighlighting(NameText.text); hiddenNameText.Text = SignatureHighlighter.RemoveHighlighting(nameText.text);
string asmText; string asmText;
if (TargetType.Assembly is AssemblyBuilder || string.IsNullOrEmpty(TargetType.Assembly.Location)) if (TargetType.Assembly is AssemblyBuilder || string.IsNullOrEmpty(TargetType.Assembly.Location))
{
asmText = $"{TargetType.Assembly.GetName().Name} <color=grey><i>(in memory)</i></color>"; asmText = $"{TargetType.Assembly.GetName().Name} <color=grey><i>(in memory)</i></color>";
dnSpyButton.GameObject.SetActive(false);
}
else else
{
asmText = Path.GetFileName(TargetType.Assembly.Location); 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 // Unity object helper widget
@ -175,7 +187,7 @@ namespace UnityExplorer.Inspectors
scopeFilterButtons[BindingFlags.Default].Component.gameObject.SetActive(!StaticOnly); scopeFilterButtons[BindingFlags.Default].Component.gameObject.SetActive(!StaticOnly);
scopeFilterButtons[BindingFlags.Instance].Component.gameObject.SetActive(!StaticOnly); scopeFilterButtons[BindingFlags.Instance].Component.gameObject.SetActive(!StaticOnly);
foreach (var toggle in memberTypeToggles) foreach (Toggle toggle in memberTypeToggles)
toggle.isOn = true; toggle.isOn = true;
refreshWanted = true; refreshWanted = true;
@ -195,11 +207,11 @@ namespace UnityExplorer.Inspectors
} }
// check filter changes or force-refresh // check filter changes or force-refresh
if (refreshWanted || nameFilter != lastNameFilter || scopeFlagsFilter != lastFlagsFilter || lastMemberFilter != MemberFilter) if (refreshWanted || nameFilter != lastNameFilter || scopeFlagsFilter != lastFlagsFilter || lastMemberFilter != memberFilter)
{ {
lastNameFilter = nameFilter; lastNameFilter = nameFilter;
lastFlagsFilter = scopeFlagsFilter; lastFlagsFilter = scopeFlagsFilter;
lastMemberFilter = MemberFilter; lastMemberFilter = memberFilter;
FilterMembers(); FilterMembers();
MemberScrollPool.Refresh(true, true); MemberScrollPool.Refresh(true, true);
@ -219,24 +231,15 @@ namespace UnityExplorer.Inspectors
} }
} }
public void UpdateClicked()
{
UpdateDisplayedMembers();
}
// Filtering // Filtering
public void SetFilter(string name) => SetFilter(name, scopeFlagsFilter);
public void SetFilter(BindingFlags flags) => SetFilter(nameFilter, flags);
public void SetFilter(string name, BindingFlags flags) public void SetFilter(string name, BindingFlags flags)
{ {
this.nameFilter = name; this.nameFilter = name;
if (flags != scopeFlagsFilter) if (flags != scopeFlagsFilter)
{ {
var btn = scopeFilterButtons[scopeFlagsFilter].Component; Button btn = scopeFilterButtons[scopeFlagsFilter].Component;
RuntimeHelper.SetColorBlock(btn, disabledButtonColor, disabledButtonColor * 1.3f); RuntimeHelper.SetColorBlock(btn, disabledButtonColor, disabledButtonColor * 1.3f);
this.scopeFlagsFilter = flags; this.scopeFlagsFilter = flags;
@ -245,21 +248,13 @@ namespace UnityExplorer.Inspectors
} }
} }
private void OnMemberTypeToggled(MemberFilter flag, bool val) void FilterMembers()
{
if (!val)
MemberFilter &= ~flag;
else
MemberFilter |= flag;
}
private void FilterMembers()
{ {
filteredMembers.Clear(); filteredMembers.Clear();
for (int i = 0; i < members.Count; i++) for (int i = 0; i < members.Count; i++)
{ {
var member = members[i]; CacheMember member = members[i];
if (scopeFlagsFilter != BindingFlags.Default) if (scopeFlagsFilter != BindingFlags.Default)
{ {
@ -268,10 +263,10 @@ namespace UnityExplorer.Inspectors
continue; continue;
} }
if ((member is CacheMethod && !MemberFilter.HasFlag(MemberFilter.Method)) if ((member is CacheMethod && !memberFilter.HasFlag(MemberFilter.Method))
|| (member is CacheField && !MemberFilter.HasFlag(MemberFilter.Field)) || (member is CacheField && !memberFilter.HasFlag(MemberFilter.Field))
|| (member is CacheProperty && !MemberFilter.HasFlag(MemberFilter.Property)) || (member is CacheProperty && !memberFilter.HasFlag(MemberFilter.Property))
|| (member is CacheConstructor && !MemberFilter.HasFlag(MemberFilter.Constructor))) || (member is CacheConstructor && !memberFilter.HasFlag(MemberFilter.Constructor)))
continue; continue;
if (!string.IsNullOrEmpty(nameFilter) && !member.NameForFiltering.ContainsIgnoreCase(nameFilter)) if (!string.IsNullOrEmpty(nameFilter) && !member.NameForFiltering.ContainsIgnoreCase(nameFilter))
@ -281,14 +276,14 @@ namespace UnityExplorer.Inspectors
} }
} }
private void UpdateDisplayedMembers() void UpdateDisplayedMembers()
{ {
bool shouldRefresh = false; bool shouldRefresh = false;
foreach (var cell in MemberScrollPool.CellPool) foreach (CacheMemberCell cell in MemberScrollPool.CellPool)
{ {
if (!cell.Enabled || cell.Occupant == null) if (!cell.Enabled || cell.Occupant == null)
continue; continue;
var member = cell.MemberOccupant; CacheMember member = cell.MemberOccupant;
if (member.ShouldAutoEvaluate) if (member.ShouldAutoEvaluate)
{ {
shouldRefresh = true; shouldRefresh = true;
@ -316,17 +311,17 @@ namespace UnityExplorer.Inspectors
{ {
CalculateLayouts(); CalculateLayouts();
foreach (var cell in MemberScrollPool.CellPool) foreach (CacheMemberCell cell in MemberScrollPool.CellPool)
SetCellLayout(cell); SetCellLayout(cell);
} }
private void CalculateLayouts() void CalculateLayouts()
{ {
LeftGroupWidth = (int)Math.Max(200, (0.4f * InspectorManager.PanelWidth) - 5); LeftGroupWidth = (int)Math.Max(200, (0.4f * InspectorManager.PanelWidth) - 5);
RightGroupWidth = (int)Math.Max(200, InspectorManager.PanelWidth - LeftGroupWidth - 65); RightGroupWidth = (int)Math.Max(200, InspectorManager.PanelWidth - LeftGroupWidth - 65);
} }
private void SetCellLayout(CacheObjectCell cell) void SetCellLayout(CacheObjectCell cell)
{ {
cell.NameLayout.minWidth = LeftGroupWidth; cell.NameLayout.minWidth = LeftGroupWidth;
cell.RightGroupLayout.minWidth = RightGroupWidth; cell.RightGroupLayout.minWidth = RightGroupWidth;
@ -335,11 +330,85 @@ namespace UnityExplorer.Inspectors
cell.Occupant.IValue.SetLayout(); 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); 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 // UI Construction
public override GameObject CreateContent(GameObject parent) public override GameObject CreateContent(GameObject parent)
@ -349,51 +418,68 @@ namespace UnityExplorer.Inspectors
// Class name, assembly // 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); 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); UIFactory.SetLayoutElement(titleHolder, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999);
NameText = UIFactory.CreateLabel(titleHolder, "VisibleTitle", "NotSet", TextAnchor.MiddleLeft); nameText = UIFactory.CreateLabel(titleHolder, "VisibleTitle", "NotSet", TextAnchor.MiddleLeft);
var namerect = NameText.GetComponent<RectTransform>(); RectTransform namerect = nameText.GetComponent<RectTransform>();
namerect.anchorMin = new Vector2(0, 0); namerect.anchorMin = new Vector2(0, 0);
namerect.anchorMax = new Vector2(1, 1); namerect.anchorMax = new Vector2(1, 1);
NameText.fontSize = 17; nameText.fontSize = 17;
UIFactory.SetLayoutElement(NameText.gameObject, minHeight: 35, flexibleHeight: 0, minWidth: 300, flexibleWidth: 9999); UIFactory.SetLayoutElement(nameText.gameObject, minHeight: 35, flexibleHeight: 0, minWidth: 300, flexibleWidth: 9999);
HiddenNameText = UIFactory.CreateInputField(titleHolder, "Title", "not set"); hiddenNameText = UIFactory.CreateInputField(titleHolder, "Title", "not set");
var hiddenrect = HiddenNameText.Component.gameObject.GetComponent<RectTransform>(); RectTransform hiddenrect = hiddenNameText.Component.gameObject.GetComponent<RectTransform>();
hiddenrect.anchorMin = new Vector2(0, 0); hiddenrect.anchorMin = new Vector2(0, 0);
hiddenrect.anchorMax = new Vector2(1, 1); hiddenrect.anchorMax = new Vector2(1, 1);
HiddenNameText.Component.readOnly = true; hiddenNameText.Component.readOnly = true;
HiddenNameText.Component.lineType = InputField.LineType.MultiLineNewline; hiddenNameText.Component.lineType = InputField.LineType.MultiLineNewline;
HiddenNameText.Component.gameObject.GetComponent<Image>().color = Color.clear; hiddenNameText.Component.gameObject.GetComponent<Image>().color = Color.clear;
HiddenNameText.Component.textComponent.horizontalOverflow = HorizontalWrapMode.Wrap; hiddenNameText.Component.textComponent.horizontalOverflow = HorizontalWrapMode.Wrap;
HiddenNameText.Component.textComponent.fontSize = 17; hiddenNameText.Component.textComponent.fontSize = 17;
HiddenNameText.Component.textComponent.color = Color.clear; hiddenNameText.Component.textComponent.color = Color.clear;
UIFactory.SetLayoutElement(HiddenNameText.Component.gameObject, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999); 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; copyButton.ButtonText.color = Color.yellow;
UIFactory.SetLayoutElement(copyButton.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 0); UIFactory.SetLayoutElement(copyButton.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 0);
copyButton.OnClick += OnCopyClicked; copyButton.OnClick += OnCopyClicked;
AssemblyText = UIFactory.CreateLabel(UIRoot, "AssemblyLabel", "not set", TextAnchor.MiddleLeft); // Assembly row
UIFactory.SetLayoutElement(AssemblyText.gameObject, minHeight: 25, flexibleWidth: 9999);
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)); 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 // Member scroll pool
var memberBorder = UIFactory.CreateVerticalGroup(mainContentHolder, "ScrollPoolHolder", false, false, true, true, padding: new Vector4(2, 2, 2, 2), GameObject memberBorder = UIFactory.CreateVerticalGroup(ContentRoot, "ScrollPoolHolder", false, false, true, true,
bgColor: new Color(0.05f, 0.05f, 0.05f)); padding: new Vector4(2, 2, 2, 2), bgColor: new Color(0.05f, 0.05f, 0.05f));
UIFactory.SetLayoutElement(memberBorder, flexibleWidth: 9999, flexibleHeight: 9999); UIFactory.SetLayoutElement(memberBorder, flexibleWidth: 9999, flexibleHeight: 9999);
MemberScrollPool = UIFactory.CreateScrollPool<CacheMemberCell>(memberBorder, "MemberList", out GameObject scrollObj, MemberScrollPool = UIFactory.CreateScrollPool<CacheMemberCell>(memberBorder, "MemberList", out GameObject scrollObj,
@ -411,29 +497,29 @@ namespace UnityExplorer.Inspectors
// First row // 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.SetLayoutGroup<HorizontalLayoutGroup>(rowObj, true, true, true, true, 5, 2, 2, 2, 2);
UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); 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); UIFactory.SetLayoutElement(nameLabel.gameObject, minHeight: 25, minWidth: 90, flexibleWidth: 0);
filterInputField = UIFactory.CreateInputField(rowObj, "NameFilterInput", "..."); filterInputField = UIFactory.CreateInputField(rowObj, "NameFilterInput", "...");
UIFactory.SetLayoutElement(filterInputField.UIRoot, minHeight: 25, flexibleWidth: 300); 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); UIFactory.SetLayoutElement(spacer, minWidth: 25);
// Update button and toggle // 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); 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); UIFactory.SetLayoutElement(toggleObj, minWidth: 125, minHeight: 25);
autoUpdateToggle.isOn = false; autoUpdateToggle.isOn = false;
toggleText.text = "Auto-update"; toggleText.text = "Auto-update";
@ -441,21 +527,21 @@ namespace UnityExplorer.Inspectors
// Second row // 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.SetLayoutGroup<HorizontalLayoutGroup>(rowObj, false, false, true, true, 5, 2, 2, 2, 2);
UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
// Scope buttons // 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); UIFactory.SetLayoutElement(scopeLabel.gameObject, minHeight: 25, minWidth: 60, flexibleWidth: 0);
AddScopeFilterButton(rowObj, BindingFlags.Default, true); AddScopeFilterButton(rowObj, BindingFlags.Default, true);
AddScopeFilterButton(rowObj, BindingFlags.Instance); AddScopeFilterButton(rowObj, BindingFlags.Instance);
AddScopeFilterButton(rowObj, BindingFlags.Static); AddScopeFilterButton(rowObj, BindingFlags.Static);
var spacer = UIFactory.CreateUIObject("Spacer", rowObj); GameObject spacer = UIFactory.CreateUIObject("Spacer", rowObj);
UIFactory.SetLayoutElement(spacer, minWidth: 15); UIFactory.SetLayoutElement(spacer, minWidth: 15);
// Member type toggles // Member type toggles
@ -466,21 +552,21 @@ namespace UnityExplorer.Inspectors
AddMemberTypeToggle(rowObj, MemberTypes.Constructor, 110); 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(); 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); UIFactory.SetLayoutElement(button.Component.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 70, flexibleWidth: 0);
scopeFilterButtons.Add(flags, button); 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); UIFactory.SetLayoutElement(toggleObj, minHeight: 25, minWidth: width);
string color = type switch string color = type switch
{ {

View File

@ -2,8 +2,6 @@
using BepInEx.Configuration; using BepInEx.Configuration;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.Config; using UnityExplorer.Config;
namespace UnityExplorer.Loader.BIE namespace UnityExplorer.Loader.BIE
@ -21,7 +19,7 @@ namespace UnityExplorer.Loader.BIE
public override void RegisterConfigElement<T>(ConfigElement<T> config) 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) => entry.SettingChanged += (object o, EventArgs e) =>
{ {
@ -47,13 +45,13 @@ namespace UnityExplorer.Loader.BIE
public override void LoadConfig() public override void LoadConfig()
{ {
foreach (var entry in ConfigManager.ConfigElements) foreach (KeyValuePair<string, IConfigElement> entry in ConfigManager.ConfigElements)
{ {
var key = entry.Key; string key = entry.Key;
var def = new ConfigDefinition(CTG_NAME, key); ConfigDefinition def = new(CTG_NAME, key);
if (Config.ContainsKey(def) && Config[def] is ConfigEntryBase configEntry) if (Config.ContainsKey(def) && Config[def] is ConfigEntryBase configEntry)
{ {
var config = entry.Value; IConfigElement config = entry.Value;
config.BoxedValue = configEntry.BoxedValue; config.BoxedValue = configEntry.BoxedValue;
} }
} }
@ -61,7 +59,7 @@ namespace UnityExplorer.Loader.BIE
public override void SaveConfig() public override void SaveConfig()
{ {
// not required Config.Save();
} }
} }
} }

View File

@ -3,14 +3,8 @@ using BepInEx;
using BepInEx.Logging; using BepInEx.Logging;
using HarmonyLib; using HarmonyLib;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityExplorer.Config; using UnityExplorer.Config;
using UniverseLib.Input;
using UnityExplorer.Loader.BIE; using UnityExplorer.Loader.BIE;
#if CPP #if CPP
using BepInEx.IL2CPP; using BepInEx.IL2CPP;

View File

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

View File

@ -6,27 +6,53 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.Config;
using UnityExplorer.UI;
using UniverseLib;
namespace UnityExplorer.Loader.Standalone namespace UnityExplorer.Loader.Standalone
{ {
public class ExplorerEditorBehaviour : MonoBehaviour 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() internal void Awake()
{ {
Instance = this;
ExplorerEditorLoader.Initialize(); ExplorerEditorLoader.Initialize();
DontDestroyOnLoad(this); DontDestroyOnLoad(this);
this.gameObject.hideFlags = HideFlags.HideAndDontSave; this.gameObject.hideFlags = HideFlags.HideAndDontSave;
} }
internal void OnDestroy()
{
OnApplicationQuit();
}
internal void OnApplicationQuit() internal void OnApplicationQuit()
{ {
if (UI.UIManager.UIRoot) Destroy(this.gameObject);
Destroy(UI.UIManager.UIRoot.transform.root.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() protected override void CheckExplorerFolder()
{ {
if (explorerFolderDest == null) if (explorerFolderDest == null)
explorerFolderDest = Application.dataPath; explorerFolderDest = Path.GetDirectoryName(Application.dataPath);
} }
} }
} }

View File

@ -1,14 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib; using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets.ButtonList; using UniverseLib.UI.Widgets.ButtonList;
using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility; using UniverseLib.Utility;
@ -35,12 +34,15 @@ namespace UnityExplorer.ObjectExplorer
private ScrollPool<ButtonCell> resultsScrollPool; private ScrollPool<ButtonCell> resultsScrollPool;
private List<object> currentResults = new(); private List<object> currentResults = new();
//public TypeCompleter typeAutocompleter;
public TypeCompleter unityObjectTypeCompleter;
public TypeCompleter allTypesCompleter;
public override GameObject UIRoot => uiRoot; public override GameObject UIRoot => uiRoot;
private GameObject uiRoot; private GameObject uiRoot;
private GameObject sceneFilterRow; private GameObject sceneFilterRow;
private GameObject childFilterRow; private GameObject childFilterRow;
private GameObject classInputRow; private GameObject classInputRow;
public TypeCompleter typeAutocompleter;
private GameObject nameInputRow; private GameObject nameInputRow;
private InputFieldRef nameInputField; private InputFieldRef nameInputField;
private Text resultsLabel; private Text resultsLabel;
@ -73,7 +75,7 @@ namespace UnityExplorer.ObjectExplorer
//var type = ReflectionUtility.GetTypeByName(desiredTypeInput); //var type = ReflectionUtility.GetTypeByName(desiredTypeInput);
if (ReflectionUtility.GetTypeByName(desiredTypeInput) is Type cachedType) if (ReflectionUtility.GetTypeByName(desiredTypeInput) is Type cachedType)
{ {
var type = cachedType; Type type = cachedType;
lastTypeCanHaveGameObject = typeof(Component).IsAssignableFrom(type) || type == typeof(GameObject); lastTypeCanHaveGameObject = typeof(Component).IsAssignableFrom(type) || type == typeof(GameObject);
sceneFilterRow.SetActive(lastTypeCanHaveGameObject); sceneFilterRow.SetActive(lastTypeCanHaveGameObject);
childFilterRow.SetActive(lastTypeCanHaveGameObject); childFilterRow.SetActive(lastTypeCanHaveGameObject);
@ -99,14 +101,18 @@ namespace UnityExplorer.ObjectExplorer
nameInputRow.SetActive(context == SearchContext.UnityObject); nameInputRow.SetActive(context == SearchContext.UnityObject);
if (context == SearchContext.Class) switch (context)
typeAutocompleter.AllTypes = true;
else
{ {
typeAutocompleter.BaseType = context == SearchContext.UnityObject ? typeof(UnityEngine.Object) : typeof(object); case SearchContext.UnityObject:
typeAutocompleter.AllTypes = false; 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; private void OnSceneFilterDropChanged(int value) => sceneFilter = (SceneFilter)value;
@ -135,7 +141,7 @@ namespace UnityExplorer.ObjectExplorer
string text; string text;
if (context == SearchContext.Class) 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>"; text = $"{SignatureHighlighter.Parse(type, true)} <color=grey><i>({type.Assembly.GetName().Name})</i></color>";
} }
else else
@ -164,14 +170,14 @@ namespace UnityExplorer.ObjectExplorer
// Search context row // 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); 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); UIFactory.SetLayoutElement(contextLbl.gameObject, minWidth: 110, flexibleWidth: 0);
var contextDropObj = UIFactory.CreateDropdown(contextGroup, "ContextDropdown", out Dropdown contextDrop, null, 14, OnContextDropdownChanged); GameObject contextDropObj = UIFactory.CreateDropdown(contextGroup, "ContextDropdown", out Dropdown contextDrop, null, 14, OnContextDropdownChanged);
foreach (var name in Enum.GetNames(typeof(SearchContext))) foreach (string name in Enum.GetNames(typeof(SearchContext)))
contextDrop.options.Add(new Dropdown.OptionData(name)); contextDrop.options.Add(new Dropdown.OptionData(name));
UIFactory.SetLayoutElement(contextDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); UIFactory.SetLayoutElement(contextDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
@ -180,13 +186,15 @@ namespace UnityExplorer.ObjectExplorer
classInputRow = UIFactory.CreateHorizontalGroup(uiRoot, "ClassRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2)); classInputRow = UIFactory.CreateHorizontalGroup(uiRoot, "ClassRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(classInputRow, minHeight: 25, flexibleHeight: 0); 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); 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); 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; classInputField.OnValueChanged += OnTypeInputChanged;
//unityObjectClassRow.SetActive(false); //unityObjectClassRow.SetActive(false);
@ -196,11 +204,11 @@ namespace UnityExplorer.ObjectExplorer
childFilterRow = UIFactory.CreateHorizontalGroup(uiRoot, "ChildFilterRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2)); childFilterRow = UIFactory.CreateHorizontalGroup(uiRoot, "ChildFilterRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(childFilterRow, minHeight: 25, flexibleHeight: 0); 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); UIFactory.SetLayoutElement(childLbl.gameObject, minWidth: 110, flexibleWidth: 0);
var childDropObj = UIFactory.CreateDropdown(childFilterRow, "ChildFilterDropdown", out Dropdown childDrop, null, 14, OnChildFilterDropChanged); GameObject childDropObj = UIFactory.CreateDropdown(childFilterRow, "ChildFilterDropdown", out Dropdown childDrop, null, 14, OnChildFilterDropChanged);
foreach (var name in Enum.GetNames(typeof(ChildFilter))) foreach (string name in Enum.GetNames(typeof(ChildFilter)))
childDrop.options.Add(new Dropdown.OptionData(name)); childDrop.options.Add(new Dropdown.OptionData(name));
UIFactory.SetLayoutElement(childDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); UIFactory.SetLayoutElement(childDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
@ -211,11 +219,11 @@ namespace UnityExplorer.ObjectExplorer
sceneFilterRow = UIFactory.CreateHorizontalGroup(uiRoot, "SceneFilterRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2)); sceneFilterRow = UIFactory.CreateHorizontalGroup(uiRoot, "SceneFilterRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(sceneFilterRow, minHeight: 25, flexibleHeight: 0); 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); UIFactory.SetLayoutElement(sceneLbl.gameObject, minWidth: 110, flexibleWidth: 0);
var sceneDropObj = UIFactory.CreateDropdown(sceneFilterRow, "SceneFilterDropdown", out Dropdown sceneDrop, null, 14, OnSceneFilterDropChanged); GameObject sceneDropObj = UIFactory.CreateDropdown(sceneFilterRow, "SceneFilterDropdown", out Dropdown sceneDrop, null, 14, OnSceneFilterDropChanged);
foreach (var name in Enum.GetNames(typeof(SceneFilter))) foreach (string name in Enum.GetNames(typeof(SceneFilter)))
{ {
if (!SceneHandler.DontDestroyExists && name == "DontDestroyOnLoad") if (!SceneHandler.DontDestroyExists && name == "DontDestroyOnLoad")
continue; continue;
@ -230,7 +238,7 @@ namespace UnityExplorer.ObjectExplorer
nameInputRow = UIFactory.CreateHorizontalGroup(uiRoot, "NameRow", true, true, true, true, 2, new Vector4(2, 2, 2, 2)); nameInputRow = UIFactory.CreateHorizontalGroup(uiRoot, "NameRow", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(nameInputRow, minHeight: 25, flexibleHeight: 0); 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); UIFactory.SetLayoutElement(nameLbl.gameObject, minWidth: 110, flexibleWidth: 0);
nameInputField = UIFactory.CreateInputField(nameInputRow, "NameFilterInput", "..."); nameInputField = UIFactory.CreateInputField(nameInputRow, "NameFilterInput", "...");
@ -238,13 +246,13 @@ namespace UnityExplorer.ObjectExplorer
// Search button // 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); UIFactory.SetLayoutElement(searchButton.Component.gameObject, minHeight: 25, flexibleHeight: 0);
searchButton.OnClick += DoSearch; searchButton.OnClick += DoSearch;
// Results count label // 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); UIFactory.SetLayoutElement(resultsCountRow, minHeight: 25, flexibleHeight: 0);
resultsLabel = UIFactory.CreateLabel(resultsCountRow, "ResultsLabel", "0 results", TextAnchor.MiddleCenter); resultsLabel = UIFactory.CreateLabel(resultsCountRow, "ResultsLabel", "0 results", TextAnchor.MiddleCenter);

View File

@ -1,20 +1,19 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI; using UnityExplorer.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
using UniverseLib.UI;
using UniverseLib; using UniverseLib;
using System.Collections; using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.Utility; using UniverseLib.Utility;
using UniverseLib.UI.Widgets;
namespace UnityExplorer.ObjectExplorer namespace UnityExplorer.ObjectExplorer
{ {
@ -76,7 +75,7 @@ namespace UnityExplorer.ObjectExplorer
this.Parent.SetTab(0); this.Parent.SetTab(0);
// select the transform's scene // select the transform's scene
var go = transform.gameObject; GameObject go = transform.gameObject;
if (SceneHandler.SelectedScene != go.scene) if (SceneHandler.SelectedScene != go.scene)
{ {
int idx; int idx;
@ -109,7 +108,7 @@ namespace UnityExplorer.ObjectExplorer
if (sceneToDropdownOption.ContainsKey(scene)) if (sceneToDropdownOption.ContainsKey(scene))
{ {
var opt = sceneToDropdownOption[scene]; Dropdown.OptionData opt = sceneToDropdownOption[scene];
int idx = sceneDropdown.options.IndexOf(opt); int idx = sceneDropdown.options.IndexOf(opt);
if (sceneDropdown.value != idx) if (sceneDropdown.value != idx)
sceneDropdown.value = idx; sceneDropdown.value = idx;
@ -136,7 +135,7 @@ namespace UnityExplorer.ObjectExplorer
sceneToDropdownOption.Clear(); sceneToDropdownOption.Clear();
sceneDropdown.options.Clear(); sceneDropdown.options.Clear();
foreach (var scene in loadedScenes) foreach (Scene scene in loadedScenes)
{ {
if (sceneToDropdownOption.ContainsKey(scene)) if (sceneToDropdownOption.ContainsKey(scene))
continue; continue;
@ -148,7 +147,7 @@ namespace UnityExplorer.ObjectExplorer
else if (string.IsNullOrEmpty(name)) else if (string.IsNullOrEmpty(name))
name = "<untitled>"; name = "<untitled>";
var option = new Dropdown.OptionData(name); Dropdown.OptionData option = new(name);
sceneDropdown.options.Add(option); sceneDropdown.options.Add(option);
sceneToDropdownOption.Add(scene, option); sceneToDropdownOption.Add(scene, option);
} }
@ -158,7 +157,7 @@ namespace UnityExplorer.ObjectExplorer
{ {
if ((!string.IsNullOrEmpty(input) && !Tree.Filtering) || (string.IsNullOrEmpty(input) && Tree.Filtering)) if ((!string.IsNullOrEmpty(input) && !Tree.Filtering) || (string.IsNullOrEmpty(input) && Tree.Filtering))
{ {
Tree.cachedTransforms.Clear(); Tree.Clear();
} }
Tree.CurrentFilter = input; Tree.CurrentFilter = input;
@ -167,7 +166,7 @@ namespace UnityExplorer.ObjectExplorer
private void TryLoadScene(LoadSceneMode mode, Dropdown allSceneDrop) private void TryLoadScene(LoadSceneMode mode, Dropdown allSceneDrop)
{ {
var text = allSceneDrop.captionText.text; string text = allSceneDrop.captionText.text;
if (text == DEFAULT_LOAD_TEXT) if (text == DEFAULT_LOAD_TEXT)
return; return;
@ -191,18 +190,18 @@ namespace UnityExplorer.ObjectExplorer
// Tool bar (top area) // 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)); new Color(0.15f, 0.15f, 0.15f));
// Scene selector dropdown // 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); 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); 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); UIFactory.SetLayoutElement(dropdownObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
SceneHandler.Update(); SceneHandler.Update();
@ -211,11 +210,11 @@ namespace UnityExplorer.ObjectExplorer
// Filter row // 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); UIFactory.SetLayoutElement(filterRow, minHeight: 25, flexibleHeight: 0);
//Filter input field //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); 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), 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)); new Color(0.08f, 0.08f, 0.08f));
@ -228,11 +227,11 @@ namespace UnityExplorer.ObjectExplorer
refreshRow = UIFactory.CreateHorizontalGroup(toolbar, "RefreshGroup", true, true, true, true, 2, new Vector4(2, 2, 2, 2)); refreshRow = UIFactory.CreateHorizontalGroup(toolbar, "RefreshGroup", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(refreshRow, minHeight: 30, flexibleHeight: 0); 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); UIFactory.SetLayoutElement(refreshButton.Component.gameObject, minWidth: 65, flexibleWidth: 0);
refreshButton.OnClick += UpdateTree; 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); UIFactory.SetLayoutElement(refreshToggle, flexibleWidth: 9999);
text.text = "Auto-update (1 second)"; text.text = "Auto-update (1 second)";
text.alignment = TextAnchor.MiddleLeft; text.alignment = TextAnchor.MiddleLeft;
@ -245,24 +244,23 @@ namespace UnityExplorer.ObjectExplorer
// tree labels row // 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); 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); 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); UIFactory.SetLayoutElement(indexLabel.gameObject, minWidth: 100, flexibleWidth: 0, minHeight: 25);
// Transform Tree // 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)); out GameObject scrollContent, new Color(0.11f, 0.11f, 0.11f));
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999); UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
UIFactory.SetLayoutElement(scrollContent, flexibleHeight: 9999); UIFactory.SetLayoutElement(scrollContent, flexibleHeight: 9999);
Tree = new TransformTree(scrollPool, GetRootEntries); Tree = new TransformTree(scrollPool, GetRootEntries, OnCellClicked);
Tree.Init();
Tree.RefreshData(true, true, true, false); Tree.RefreshData(true, true, true, false);
//scrollPool.Viewport.GetComponent<Mask>().enabled = false; //scrollPool.Viewport.GetComponent<Mask>().enabled = false;
//UIRoot.GetComponent<Mask>().enabled = false; //UIRoot.GetComponent<Mask>().enabled = false;
@ -274,6 +272,8 @@ namespace UnityExplorer.ObjectExplorer
RuntimeHelper.StartCoroutine(TempFixCoro()); RuntimeHelper.StartCoroutine(TempFixCoro());
} }
void OnCellClicked(GameObject obj) => InspectorManager.Inspect(obj);
// To "fix" a strange FPS drop issue with MelonLoader. // To "fix" a strange FPS drop issue with MelonLoader.
private IEnumerator TempFixCoro() private IEnumerator TempFixCoro()
{ {
@ -294,7 +294,7 @@ namespace UnityExplorer.ObjectExplorer
allSceneDropdown.options.Clear(); allSceneDropdown.options.Clear();
allSceneDropdown.options.Add(new Dropdown.OptionData(DEFAULT_LOAD_TEXT)); 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)) if (string.IsNullOrEmpty(filter) || scene.ContainsIgnoreCase(filter))
allSceneDropdown.options.Add(new Dropdown.OptionData(Path.GetFileNameWithoutExtension(scene))); allSceneDropdown.options.Add(new Dropdown.OptionData(Path.GetFileNameWithoutExtension(scene)));
@ -308,7 +308,7 @@ namespace UnityExplorer.ObjectExplorer
private void RefreshSceneLoaderButtons() private void RefreshSceneLoaderButtons()
{ {
var text = allSceneDropdown.captionText.text; string text = allSceneDropdown.captionText.text;
if (text == DEFAULT_LOAD_TEXT) if (text == DEFAULT_LOAD_TEXT)
{ {
loadButton.Component.interactable = false; loadButton.Component.interactable = false;
@ -328,30 +328,30 @@ namespace UnityExplorer.ObjectExplorer
{ {
if (SceneHandler.WasAbleToGetScenesInBuild) 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); UIFactory.SetLayoutElement(sceneLoaderObj, minHeight: 25);
// Title // 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); UIFactory.SetLayoutElement(loaderTitle.gameObject, minHeight: 25, flexibleHeight: 0);
// Search filter // 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); UIFactory.SetLayoutElement(searchFilterObj.UIRoot, minHeight: 25, flexibleHeight: 0);
searchFilterObj.OnValueChanged += RefreshSceneLoaderOptions; searchFilterObj.OnValueChanged += RefreshSceneLoaderOptions;
// Dropdown // 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); UIFactory.SetLayoutElement(allSceneDropObj, minHeight: 25, minWidth: 150, flexibleWidth: 0, flexibleHeight: 0);
RefreshSceneLoaderOptions(string.Empty); RefreshSceneLoaderOptions(string.Empty);
// Button row // 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)); loadButton = UIFactory.CreateButton(buttonRow, "LoadSceneButton", "Load (Single)", new Color(0.1f, 0.3f, 0.3f));
UIFactory.SetLayoutElement(loadButton.Component.gameObject, minHeight: 25, minWidth: 150); UIFactory.SetLayoutElement(loadButton.Component.gameObject, minHeight: 25, minWidth: 150);
@ -367,7 +367,7 @@ namespace UnityExplorer.ObjectExplorer
TryLoadScene(LoadSceneMode.Additive, allSceneDropdown); 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(loadButton.Component, disabled: disabledColor);
RuntimeHelper.SetColorBlock(loadAdditiveButton.Component, disabled: disabledColor); RuntimeHelper.SetColorBlock(loadAdditiveButton.Component, disabled: disabledColor);

View File

@ -1,8 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
using UniverseLib; using UniverseLib;
@ -65,11 +63,11 @@ namespace UnityExplorer.ObjectExplorer
if (sceneUtil == null) if (sceneUtil == null)
throw new Exception("This version of Unity does not ship with the 'SceneUtility' class, or it was not unstripped."); 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; int sceneCount = SceneManager.sceneCountInBuildSettings;
for (int i = 0; i < sceneCount; i++) 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); AllSceneNames.Add(scenePath);
} }
@ -121,11 +119,11 @@ namespace UnityExplorer.ObjectExplorer
CurrentRootObjects = RuntimeHelper.GetRootGameObjects((Scene)SelectedScene); CurrentRootObjects = RuntimeHelper.GetRootGameObjects((Scene)SelectedScene);
else else
{ {
var allObjects = RuntimeHelper.FindObjectsOfTypeAll(typeof(GameObject)); UnityEngine.Object[] allObjects = RuntimeHelper.FindObjectsOfTypeAll(typeof(GameObject));
var objects = new List<GameObject>(); List<GameObject> objects = new();
foreach (var obj in allObjects) foreach (UnityEngine.Object obj in allObjects)
{ {
var go = obj.TryCast<GameObject>(); GameObject go = obj.TryCast<GameObject>();
if (go.transform.parent == null && !go.scene.IsValid()) if (go.transform.parent == null && !go.scene.IsValid())
objects.Add(go); objects.Add(go);
} }

View File

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

View File

@ -1,13 +1,7 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Config; using UnityExplorer.Config;
using UniverseLib; using UniverseLib;
@ -50,10 +44,10 @@ namespace UnityExplorer.Runtime
try try
{ {
var sigs = blacklist.Split(';'); string[] sigs = blacklist.Split(';');
foreach (var sig in sigs) foreach (string sig in sigs)
{ {
var s = sig.Trim(); string s = sig.Trim();
if (string.IsNullOrEmpty(s)) if (string.IsNullOrEmpty(s))
continue; continue;
if (!currentBlacklist.Contains(s)) if (!currentBlacklist.Contains(s))
@ -65,7 +59,7 @@ namespace UnityExplorer.Runtime
ExplorerCore.LogWarning($"Exception parsing blacklist string: {ex.ReflectionExToString()}"); ExplorerCore.LogWarning($"Exception parsing blacklist string: {ex.ReflectionExToString()}");
} }
foreach (var sig in Instance.DefaultReflectionBlacklist) foreach (string sig in Instance.DefaultReflectionBlacklist)
{ {
if (!currentBlacklist.Contains(sig)) if (!currentBlacklist.Contains(sig))
currentBlacklist.Add(sig); currentBlacklist.Add(sig);
@ -84,7 +78,7 @@ namespace UnityExplorer.Runtime
if (string.IsNullOrEmpty(member.DeclaringType?.Namespace)) if (string.IsNullOrEmpty(member.DeclaringType?.Namespace))
return false; return false;
var sig = $"{member.DeclaringType.FullName}.{member.Name}"; string sig = $"{member.DeclaringType.FullName}.{member.Name}";
return currentBlacklist.Contains(sig); return currentBlacklist.Contains(sig);
} }

View File

@ -2,15 +2,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.CacheObject;
namespace UnityExplorer.Runtime namespace UnityExplorer.Runtime
{ {
internal static class UnityCrashPrevention 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() internal static void Init()
{ {

View File

@ -1,12 +1,8 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.UI;
using UnityExplorer.CacheObject.IValues;
#if CPP #if CPP
using UnhollowerRuntimeLib; using UnhollowerRuntimeLib;
using UnhollowerBaseLib; using UnhollowerBaseLib;
@ -74,7 +70,7 @@ namespace UnityExplorer.Tests
{ {
get get
{ {
var list = new List<object>(); List<object> list = new();
int count = UnityEngine.Random.Range(0, 100); int count = UnityEngine.Random.Range(0, 100);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
list.Add(GetRandomObject()); list.Add(GetRandomObject());
@ -178,6 +174,7 @@ namespace UnityExplorer.Tests
public static Il2CppSystem.Collections.IDictionary IL2CPP_IDict; public static Il2CppSystem.Collections.IDictionary IL2CPP_IDict;
public static Il2CppSystem.Collections.IList IL2CPP_IList; public static Il2CppSystem.Collections.IList IL2CPP_IList;
public static Dictionary<Il2CppSystem.Object, Il2CppSystem.Object> IL2CPP_BoxedDict; public static Dictionary<Il2CppSystem.Object, Il2CppSystem.Object> IL2CPP_BoxedDict;
public static Il2CppSystem.Array IL2CPP_NonGenericArray;
public static Il2CppSystem.Object IL2CPP_BoxedInt; public static Il2CppSystem.Object IL2CPP_BoxedInt;
public static Il2CppSystem.Int32 IL2CPP_Int; public static Il2CppSystem.Int32 IL2CPP_Int;
@ -191,6 +188,9 @@ namespace UnityExplorer.Tests
private static void Init_IL2CPP() 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>"); ExplorerCore.Log($"IL2CPP 1: Il2Cpp Dictionary<string, string>");
IL2CPP_Dict = new Il2CppSystem.Collections.Generic.Dictionary<string, string>(); IL2CPP_Dict = new Il2CppSystem.Collections.Generic.Dictionary<string, string>();
IL2CPP_Dict.Add("key1", "value1"); IL2CPP_Dict.Add("key1", "value1");
@ -209,12 +209,12 @@ namespace UnityExplorer.Tests
IL2CPP_HashTable.Add("key3", "value3"); IL2CPP_HashTable.Add("key3", "value3");
ExplorerCore.Log($"IL2CPP 3: Il2Cpp IDictionary"); 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"); dict2.Add("key1", "value1");
IL2CPP_IDict = dict2.TryCast<Il2CppSystem.Collections.IDictionary>(); IL2CPP_IDict = dict2.TryCast<Il2CppSystem.Collections.IDictionary>();
ExplorerCore.Log($"IL2CPP 4: Il2Cpp List of Il2Cpp Object"); 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("one");
list.Add("two"); list.Add("two");
IL2CPP_IList = list.TryCast<Il2CppSystem.Collections.IList>(); IL2CPP_IList = list.TryCast<Il2CppSystem.Collections.IList>();
@ -240,14 +240,14 @@ namespace UnityExplorer.Tests
// boxed enum test // boxed enum test
try try
{ {
var cppType = Il2CppType.Of<CameraClearFlags>(); Il2CppSystem.Type cppType = Il2CppType.Of<CameraClearFlags>();
if (cppType != null) if (cppType is not null)
{ {
var boxedEnum = Il2CppSystem.Enum.Parse(cppType, "Color"); Il2CppSystem.Object boxedEnum = Il2CppSystem.Enum.Parse(cppType, "Color");
IL2CPP_listOfBoxedObjects.Add(boxedEnum); IL2CPP_listOfBoxedObjects.Add(boxedEnum);
} }
var structBox = Vector3.one.BoxIl2CppObject(); Il2CppSystem.Object structBox = Vector3.one.BoxIl2CppObject();
IL2CPP_listOfBoxedObjects.Add(structBox); IL2CPP_listOfBoxedObjects.Add(structBox);
} }

View File

@ -1,8 +1,4 @@
using System; using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.Config; using UnityExplorer.Config;
using UniverseLib; using UniverseLib;
@ -72,7 +68,7 @@ namespace UnityExplorer.UI
yield return null; yield return null;
yield return null; yield return null;
foreach (var panel in UIManager.UIPanels.Values) foreach (Panels.UEPanel panel in UIManager.UIPanels.Values)
{ {
panel.EnsureValidSize(); panel.EnsureValidSize();
panel.EnsureValidPosition(); panel.EnsureValidPosition();

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

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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,10 +1,5 @@
using System; using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UniverseLib.Input;
using UniverseLib.UI; using UniverseLib.UI;
namespace UnityExplorer.UI namespace UnityExplorer.UI
@ -44,11 +39,10 @@ namespace UnityExplorer.UI
private static void ConstructUI() private static void ConstructUI()
{ {
popupLabel = UIFactory.CreateLabel(UIManager.UIRoot, "ClipboardNotification", "", TextAnchor.MiddleCenter); popupLabel = UIFactory.CreateLabel(UIManager.UIRoot, "ClipboardNotification", "", TextAnchor.MiddleCenter);
popupLabel.rectTransform.sizeDelta = new(500, 100); popupLabel.rectTransform.sizeDelta = new(500, 100);
popupLabel.gameObject.AddComponent<Outline>(); popupLabel.gameObject.AddComponent<Outline>();
var popupGroup = popupLabel.gameObject.AddComponent<CanvasGroup>(); CanvasGroup popupGroup = popupLabel.gameObject.AddComponent<CanvasGroup>();
popupGroup.blocksRaycasts = false; popupGroup.blocksRaycasts = false;
} }
} }

View File

@ -2,34 +2,36 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
using UniverseLib.Input;
using UnityExplorer.Runtime;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UniverseLib.UI.Widgets; using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib; using UniverseLib;
using UniverseLib.Input;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets.ButtonList; using UniverseLib.UI.Widgets.ButtonList;
using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility; using UniverseLib.Utility;
using UniverseLib.UI.Models;
namespace UnityExplorer.UI.Widgets.AutoComplete namespace UnityExplorer.UI.Panels
{ {
// Shared modal panel for "AutoComplete" suggestions. // Shared modal panel for "AutoComplete" suggestions.
// A data source implements ISuggestionProvider and uses TakeOwnership and ReleaseOwnership // A data source implements ISuggestionProvider and uses TakeOwnership and ReleaseOwnership
// for control, and SetSuggestions to set the actual suggestion data. // 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 static AutoCompleteModal Instance => UIManager.GetPanel<AutoCompleteModal>(UIManager.Panels.AutoCompleter);
public override string Name => "AutoCompleter"; public override string Name => "AutoCompleter";
public override UIManager.Panels PanelType => UIManager.Panels.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 CanDragAndResize => true;
public override bool ShouldSaveActiveState => false; public override bool ShouldSaveActiveState => false;
@ -48,10 +50,10 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
public static bool Suggesting(ISuggestionProvider handler) => CurrentHandler == handler && Instance.UIRoot.activeSelf; public static bool Suggesting(ISuggestionProvider handler) => CurrentHandler == handler && Instance.UIRoot.activeSelf;
public AutoCompleteModal() public AutoCompleteModal(UIBase owner) : base(owner)
{ {
OnPanelsReordered += UIPanel_OnPanelsReordered; UIManager.UiBase.Panels.OnPanelsReordered += UIPanel_OnPanelsReordered;
OnClickedOutsidePanels += AutoCompleter_OnClickedOutsidePanels; UIManager.UiBase.Panels.OnClickedOutsidePanels += AutoCompleter_OnClickedOutsidePanels;
} }
public static void TakeOwnership(ISuggestionProvider provider) public static void TakeOwnership(ISuggestionProvider provider)
@ -67,15 +69,22 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
if (CurrentHandler == provider) if (CurrentHandler == provider)
{ {
Suggestions.Clear();
CurrentHandler = null; CurrentHandler = null;
UIRoot.SetActive(false); UIRoot.SetActive(false);
} }
} }
public void SetSuggestions(IEnumerable<Suggestion> suggestions) public void SetSuggestions(List<Suggestion> suggestions, bool jumpToTop = true)
{
Suggestions = suggestions;
if (jumpToTop)
{ {
Suggestions = suggestions as List<Suggestion> ?? suggestions.ToList();
SelectedIndex = 0; SelectedIndex = 0;
if (scrollPool.DataSource.ItemCount > 0)
scrollPool.JumpToIndex(0, null);
}
if (!Suggestions.Any()) if (!Suggestions.Any())
base.UIRoot.SetActive(false); base.UIRoot.SetActive(false);
@ -84,7 +93,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
base.UIRoot.SetActive(true); base.UIRoot.SetActive(true);
base.UIRoot.transform.SetAsLastSibling(); base.UIRoot.transform.SetAsLastSibling();
buttonListDataHandler.RefreshData(); buttonListDataHandler.RefreshData();
scrollPool.Refresh(true, true); scrollPool.Refresh(true, jumpToTop);
} }
} }
@ -184,7 +193,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
private void OnCellClicked(int dataIndex) private void OnCellClicked(int dataIndex)
{ {
var suggestion = Suggestions[dataIndex]; Suggestion suggestion = Suggestions[dataIndex];
CurrentHandler.OnSuggestionClicked(suggestion); CurrentHandler.OnSuggestionClicked(suggestion);
} }
@ -192,13 +201,19 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
private void SetCell(ButtonCell cell, int index) private void SetCell(ButtonCell cell, int index)
{ {
if (CurrentHandler == null)
{
UIRoot.SetActive(false);
return;
}
if (index < 0 || index >= Suggestions.Count) if (index < 0 || index >= Suggestions.Count)
{ {
cell.Disable(); cell.Disable();
return; return;
} }
var suggestion = Suggestions[index]; Suggestion suggestion = Suggestions[index];
cell.Button.ButtonText.text = suggestion.DisplayText; cell.Button.ButtonText.text = suggestion.DisplayText;
if (CurrentHandler.AllowNavigation && index == SelectedIndex && setFirstCell) if (CurrentHandler.AllowNavigation && index == SelectedIndex && setFirstCell)
@ -223,14 +238,19 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
InputFieldRef input = CurrentHandler.InputField; InputFieldRef input = CurrentHandler.InputField;
if (!input.Component.isFocused || input.Component.caretPosition == lastCaretPosition && input.UIRoot.transform.position == lastInputPosition) //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; return;
lastInputPosition = input.UIRoot.transform.position;
lastCaretPosition = input.Component.caretPosition;
if (CurrentHandler.AnchorToCaretPosition) 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)); int caretIdx = Math.Max(0, Math.Min(textGen.characterCount - 1, input.Component.caretPosition));
// normalize the caret horizontal position // normalize the caret horizontal position
@ -246,6 +266,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
uiRoot.transform.position = input.Transform.position + new Vector3(-(input.Transform.rect.width / 2) + 10, -20, 0); 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(); this.Dragger.OnEndResize();
} }
@ -267,7 +290,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
if (!this.UIRoot || !this.UIRoot.activeInHierarchy) if (!this.UIRoot || !this.UIRoot.activeInHierarchy)
return; 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) if (CurrentHandler != null)
ReleaseOwnership(CurrentHandler); ReleaseOwnership(CurrentHandler);
@ -276,46 +299,36 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
} }
} }
// UI Construction public override void OnFinishResize()
const float MIN_X = 0.42f;
const float MAX_Y = 0.6f;
protected internal override void DoSetDefaultPosAndAnchors()
{ {
Rect.pivot = new Vector2(0f, 1f); float xDiff = Rect.anchorMin.x - MIN_X;
Rect.anchorMin = new Vector2(MIN_X, 0.4f); float yDiff = Rect.anchorMax.y - MAX_Y;
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;
if (xDiff != 0 || yDiff != 0) if (xDiff != 0 || yDiff != 0)
{ {
panel.anchorMin = new(MIN_X, panel.anchorMin.y - yDiff); Rect.anchorMin = new(MIN_X, Rect.anchorMin.y - yDiff);
panel.anchorMax = new(panel.anchorMax.x - xDiff, MAX_Y); 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 // hide the titlebar
this.TitleBar.gameObject.SetActive(false); this.TitleBar.gameObject.SetActive(false);
buttonListDataHandler = new ButtonListHandler<Suggestion, ButtonCell>(scrollPool, GetEntries, SetCell, ShouldDisplay, OnCellClicked); 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); out GameObject scrollContent);
scrollPool.Initialize(buttonListDataHandler); scrollPool.Initialize(buttonListDataHandler);
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999); UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(scrollContent, true, false, true, false); 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.SetLayoutElement(navigationTipRow, minHeight: 20, flexibleWidth: 9999);
UIFactory.CreateLabel(navigationTipRow, "HelpText", "Up/Down to select, Enter to use, Esc to close", UIFactory.CreateLabel(navigationTipRow, "HelpText", "Up/Down to select, Enter to use, Esc to close",
TextAnchor.MiddleLeft, Color.grey, false, 13); TextAnchor.MiddleLeft, Color.grey, false, 13);

View File

@ -1,14 +1,8 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Config;
using UnityExplorer.CSConsole; using UnityExplorer.CSConsole;
using UnityExplorer.UI.Widgets;
using UniverseLib; using UniverseLib;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
@ -16,12 +10,15 @@ using UniverseLib.UI.Widgets;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels
{ {
public class CSConsolePanel : UIPanel public class CSConsolePanel : UEPanel
{ {
public override string Name => "C# Console"; public override string Name => "C# Console";
public override UIManager.Panels PanelType => UIManager.Panels.CSConsole; public override UIManager.Panels PanelType => UIManager.Panels.CSConsole;
public override int MinWidth => 750; public override int MinWidth => 750;
public override int MinHeight => 300; 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 InputFieldScroller InputScroller { get; private set; }
public InputFieldRef Input => InputScroller.InputField; public InputFieldRef Input => InputScroller.InputField;
@ -41,6 +38,10 @@ namespace UnityExplorer.UI.Panels
public Action<bool> OnAutoIndentToggled; public Action<bool> OnAutoIndentToggled;
public Action OnPanelResized; public Action OnPanelResized;
public CSConsolePanel(UIBase owner) : base(owner)
{
}
private void InvokeOnValueChanged(string value) private void InvokeOnValueChanged(string value)
{ {
if (value.Length == UniversalUI.MAX_INPUTFIELD_CHARS) if (value.Length == UniversalUI.MAX_INPUTFIELD_CHARS)
@ -58,49 +59,41 @@ namespace UnityExplorer.UI.Panels
// UI Construction // UI Construction
public override void OnFinishResize(RectTransform panel) public override void OnFinishResize()
{ {
OnPanelResized?.Invoke(); OnPanelResized?.Invoke();
} }
protected internal override void DoSetDefaultPosAndAnchors() protected override void ConstructPanelContent()
{
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()
{ {
// Tools Row // 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); default, TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(toolsRow, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); UIFactory.SetLayoutElement(toolsRow, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
// Buttons // 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); UIFactory.SetLayoutElement(compileButton.Component.gameObject, minHeight: 28, minWidth: 130, flexibleHeight: 0);
compileButton.ButtonText.fontSize = 15; compileButton.ButtonText.fontSize = 15;
compileButton.OnClick += () => { OnCompileClicked?.Invoke(); }; 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); UIFactory.SetLayoutElement(resetButton.Component.gameObject, minHeight: 28, minWidth: 80, flexibleHeight: 0);
resetButton.ButtonText.fontSize = 15; resetButton.ButtonText.fontSize = 15;
resetButton.OnClick += () => { OnResetClicked?.Invoke(); }; resetButton.OnClick += () => { OnResetClicked?.Invoke(); };
// Help dropdown // 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); UIFactory.SetLayoutElement(helpDrop, minHeight: 25, minWidth: 100);
HelpDropdown = dropdown; HelpDropdown = dropdown;
HelpDropdown.onValueChanged.AddListener((int val) => { this.OnHelpDropdownChanged?.Invoke(val); }); HelpDropdown.onValueChanged.AddListener((int val) => { this.OnHelpDropdownChanged?.Invoke(val); });
// Enable Ctrl+R toggle // 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); UIFactory.SetLayoutElement(ctrlRToggleObj, minWidth: 150, flexibleWidth: 0, minHeight: 25);
ctrlRToggleText.alignment = TextAnchor.UpperLeft; ctrlRToggleText.alignment = TextAnchor.UpperLeft;
ctrlRToggleText.text = "Compile on Ctrl+R"; ctrlRToggleText.text = "Compile on Ctrl+R";
@ -108,7 +101,7 @@ namespace UnityExplorer.UI.Panels
// Enable Suggestions toggle // 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); UIFactory.SetLayoutElement(suggestToggleObj, minWidth: 120, flexibleWidth: 0, minHeight: 25);
suggestToggleText.alignment = TextAnchor.UpperLeft; suggestToggleText.alignment = TextAnchor.UpperLeft;
suggestToggleText.text = "Suggestions"; suggestToggleText.text = "Suggestions";
@ -116,7 +109,7 @@ namespace UnityExplorer.UI.Panels
// Enable Auto-indent toggle // 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); UIFactory.SetLayoutElement(autoIndentToggleObj, minWidth: 120, flexibleWidth: 0, minHeight: 25);
autoIndentToggleText.alignment = TextAnchor.UpperLeft; autoIndentToggleText.alignment = TextAnchor.UpperLeft;
autoIndentToggleText.text = "Auto-indent"; autoIndentToggleText.text = "Auto-indent";
@ -124,7 +117,7 @@ namespace UnityExplorer.UI.Panels
// Console Input // Console Input
var inputArea = UIFactory.CreateUIObject("InputGroup", uiContent); GameObject inputArea = UIFactory.CreateUIObject("InputGroup", ContentRoot);
UIFactory.SetLayoutElement(inputArea, flexibleWidth: 9999, flexibleHeight: 9999); UIFactory.SetLayoutElement(inputArea, flexibleWidth: 9999, flexibleHeight: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(inputArea, false, true, true, true); UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(inputArea, false, true, true, true);
inputArea.AddComponent<Image>().color = Color.white; inputArea.AddComponent<Image>().color = Color.white;
@ -132,8 +125,8 @@ namespace UnityExplorer.UI.Panels
// line numbers // line numbers
var linesHolder = UIFactory.CreateUIObject("LinesHolder", inputArea); GameObject linesHolder = UIFactory.CreateUIObject("LinesHolder", inputArea);
var linesRect = linesHolder.GetComponent<RectTransform>(); RectTransform linesRect = linesHolder.GetComponent<RectTransform>();
linesRect.pivot = new Vector2(0, 1); linesRect.pivot = new Vector2(0, 1);
linesRect.anchorMin = new Vector2(0, 0); linesRect.anchorMin = new Vector2(0, 0);
linesRect.anchorMax = new Vector2(0, 1); linesRect.anchorMax = new Vector2(0, 1);
@ -149,10 +142,10 @@ namespace UnityExplorer.UI.Panels
int fontSize = 16; int fontSize = 16;
var inputObj = UIFactory.CreateScrollInputField(inputArea, "ConsoleInput", ConsoleController.STARTUP_TEXT, GameObject inputObj = UIFactory.CreateScrollInputField(inputArea, "ConsoleInput", ConsoleController.STARTUP_TEXT,
out var inputScroller, fontSize); out InputFieldScroller inputScroller, fontSize);
InputScroller = inputScroller; InputScroller = inputScroller;
ConsoleController.defaultInputFieldAlpha = Input.Component.selectionColor.a; ConsoleController.DefaultInputFieldAlpha = Input.Component.selectionColor.a;
Input.OnValueChanged += InvokeOnValueChanged; Input.OnValueChanged += InvokeOnValueChanged;
// move line number text with input field // move line number text with input field
@ -173,8 +166,8 @@ namespace UnityExplorer.UI.Panels
Input.PlaceholderText.fontSize = fontSize; Input.PlaceholderText.fontSize = fontSize;
// Lexer highlight text overlay // Lexer highlight text overlay
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", InputText.gameObject); GameObject highlightTextObj = UIFactory.CreateUIObject("HighlightText", InputText.gameObject);
var highlightTextRect = highlightTextObj.GetComponent<RectTransform>(); RectTransform highlightTextRect = highlightTextObj.GetComponent<RectTransform>();
highlightTextRect.pivot = new Vector2(0, 1); highlightTextRect.pivot = new Vector2(0, 1);
highlightTextRect.anchorMin = Vector2.zero; highlightTextRect.anchorMin = Vector2.zero;
highlightTextRect.anchorMax = Vector2.one; highlightTextRect.anchorMax = Vector2.one;

View File

@ -1,29 +1,24 @@
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Config;
using UniverseLib; using UniverseLib;
using UniverseLib.Input;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Widgets;
using UniverseLib.Utility; using UniverseLib.Utility;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels
{ {
public class ClipboardPanel : UIPanel public class ClipboardPanel : UEPanel
{ {
public static object Current { get; private set; } public static object Current { get; private set; }
public override UIManager.Panels PanelType => UIManager.Panels.Clipboard;
public override string Name => "Clipboard"; public override string Name => "Clipboard";
public override UIManager.Panels PanelType => UIManager.Panels.Clipboard;
public override int MinWidth => 500; public override int MinWidth => 500;
public override int MinHeight => 95; 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 CanDragAndResize => true;
public override bool NavButtonWanted => true; public override bool NavButtonWanted => true;
public override bool ShouldSaveActiveState => true; public override bool ShouldSaveActiveState => true;
@ -31,6 +26,10 @@ namespace UnityExplorer.UI.Panels
private static Text CurrentPasteLabel; private static Text CurrentPasteLabel;
public ClipboardPanel(UIBase owner) : base(owner)
{
}
public static void Copy(object obj) public static void Copy(object obj)
{ {
Current = obj; Current = obj;
@ -41,7 +40,7 @@ namespace UnityExplorer.UI.Panels
public static bool TryPaste(Type targetType, out object paste) public static bool TryPaste(Type targetType, out object paste)
{ {
paste = Current; paste = Current;
var pasteType = Current?.GetActualType(); Type pasteType = Current?.GetActualType();
if (Current != null && !targetType.IsAssignableFrom(pasteType)) if (Current != null && !targetType.IsAssignableFrom(pasteType))
{ {
@ -75,34 +74,34 @@ namespace UnityExplorer.UI.Panels
InspectorManager.Inspect(Current); 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.Horizontal, MinWidth);
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight); 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); this.UIRoot.GetComponent<Image>().color = new(0.1f, 0.1f, 0.1f);
// Actual panel content // 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); UIFactory.SetLayoutElement(firstRow, minHeight: 25, flexibleWidth: 999);
// Title for "Current Paste:" // 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); UIFactory.SetLayoutElement(currentPasteTitle.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
// Clear clipboard button // 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); UIFactory.SetLayoutElement(clearButton.Component.gameObject, minWidth: 120, minHeight: 25, flexibleWidth: 0);
clearButton.OnClick += () => Copy(null); clearButton.OnClick += () => Copy(null);
// Current Paste info row // 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); new(2, 2, 2, 2), childAlignment: TextAnchor.UpperCenter);
// Actual current paste info label // Actual current paste info label
@ -111,7 +110,7 @@ namespace UnityExplorer.UI.Panels
UpdateCurrentPasteInfo(); UpdateCurrentPasteInfo();
// Inspect button // 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); UIFactory.SetLayoutElement(inspectButton.Component.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 80, flexibleWidth: 0);
inspectButton.OnClick += InspectClipboard; inspectButton.OnClick += InspectClipboard;
} }

View File

@ -0,0 +1,397 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UniverseLib;
using UniverseLib.Input;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.Utility;
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()
{
UnhollowerRuntimeLib.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,13 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Config;
using UnityExplorer.Hooks; using UnityExplorer.Hooks;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets; using UniverseLib.UI.Widgets;
@ -15,189 +12,99 @@ using UniverseLib.UI.Widgets.ScrollView;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels
{ {
public class HookManagerPanel : UIPanel public class HookManagerPanel : UEPanel
{ {
public static HookManagerPanel Instance { get; private set; }
public enum Pages public enum Pages
{ {
CurrentHooks,
ClassMethodSelector, 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 UIManager.Panels PanelType => UIManager.Panels.HookManager;
public override string Name => "Hooks"; public override string Name => "Hooks";
public override int MinWidth => 500;
public override int MinHeight => 600;
public override bool ShowByDefault => false; 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 HookManagerPanel(UIBase owner) : base(owner)
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()
{ {
HookManager.Instance.OnClassSelectedForHooks(this.classSelectorInputField.Text);
} }
public void SetAddHooksLabelType(string typeText) => addHooksLabel.text = $"Adding hooks to: {typeText}";
public void SetPage(Pages page) public void SetPage(Pages page)
{ {
switch (page) switch (page)
{ {
case Pages.CurrentHooks:
currentHooksPanel.SetActive(true);
addHooksPanel.SetActive(false);
editorPanel.SetActive(false);
break;
case Pages.ClassMethodSelector: case Pages.ClassMethodSelector:
currentHooksPanel.SetActive(false); HookCreator.AddHooksRoot.SetActive(true);
addHooksPanel.SetActive(true); HookCreator.EditorRoot.SetActive(false);
editorPanel.SetActive(false); genericArgsHandler.UIRoot.SetActive(false);
break; break;
case Pages.HookSourceEditor: case Pages.HookSourceEditor:
currentHooksPanel.SetActive(false); HookCreator.AddHooksRoot.SetActive(false);
addHooksPanel.SetActive(false); HookCreator.EditorRoot.SetActive(true);
editorPanel.SetActive(true); genericArgsHandler.UIRoot.SetActive(false);
break;
case Pages.GenericArgsSelector:
HookCreator.AddHooksRoot.SetActive(false);
HookCreator.EditorRoot.SetActive(false);
genericArgsHandler.UIRoot.SetActive(true);
break; break;
} }
} }
public void ResetMethodFilter() => AddHooksMethodFilterInput.Text = string.Empty; public override void SetDefaultSizeAndPosition()
public override void ConstructPanelContent()
{ {
// ~~~~~~~~~ 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.Horizontal, MinWidth);
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight); 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,22 @@
using System; using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Config;
using UnityExplorer.Inspectors; using UnityExplorer.Inspectors;
using UniverseLib.UI; using UniverseLib.UI;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels
{ {
public class InspectorPanel : UIPanel public class InspectorPanel : UEPanel
{ {
public static InspectorPanel Instance { get; private set; } public static InspectorPanel Instance { get; private set; }
public InspectorPanel() { Instance = this; }
public override string Name => "Inspector"; public override string Name => "Inspector";
public override UIManager.Panels PanelType => UIManager.Panels.Inspector; public override UIManager.Panels PanelType => UIManager.Panels.Inspector;
public override bool ShouldSaveActiveState => false; public override bool ShouldSaveActiveState => false;
public override int MinWidth => 810; public override int MinWidth => 810;
public override int MinHeight => 350; 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 GameObject NavbarHolder;
public Dropdown MouseInspectDropdown; public Dropdown MouseInspectDropdown;
@ -31,34 +26,31 @@ namespace UnityExplorer.UI.Panels
public static float CurrentPanelWidth => Instance.Rect.rect.width; public static float CurrentPanelWidth => Instance.Rect.rect.width;
public static float CurrentPanelHeight => Instance.Rect.rect.height; public static float CurrentPanelHeight => Instance.Rect.rect.height;
public InspectorPanel(UIBase owner) : base(owner)
{
Instance = this;
}
public override void Update() public override void Update()
{ {
InspectorManager.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.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; GameObject closeHolder = this.TitleBar.transform.Find("CloseHolder").gameObject;
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;
// Inspect under mouse dropdown on title bar // 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); MouseInspector.OnDropdownSelect);
UIFactory.SetLayoutElement(mouseDropdown, minHeight: 25, minWidth: 140); UIFactory.SetLayoutElement(mouseDropdown, minHeight: 25, minWidth: 140);
MouseInspectDropdown.options.Add(new Dropdown.OptionData("Mouse Inspect")); MouseInspectDropdown.options.Add(new Dropdown.OptionData("Mouse Inspect"));
@ -68,7 +60,7 @@ namespace UnityExplorer.UI.Panels
// add close all button to titlebar // 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)); new Color(0.3f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(closeAllBtn.Component.gameObject, minHeight: 25, minWidth: 80); UIFactory.SetLayoutElement(closeAllBtn.Component.gameObject, minHeight: 25, minWidth: 80);
closeAllBtn.Component.transform.SetSiblingIndex(closeAllBtn.Component.transform.GetSiblingIndex() - 1); closeAllBtn.Component.transform.SetSiblingIndex(closeAllBtn.Component.transform.GetSiblingIndex() - 1);
@ -76,19 +68,19 @@ namespace UnityExplorer.UI.Panels
// this.UIRoot.GetComponent<Mask>().enabled = false; // 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)); new Color(0.05f, 0.05f, 0.05f));
//UIFactory.SetLayoutElement(NavbarHolder, flexibleWidth: 9999, minHeight: 0, preferredHeight: 0, flexibleHeight: 9999); //UIFactory.SetLayoutElement(NavbarHolder, flexibleWidth: 9999, minHeight: 0, preferredHeight: 0, flexibleHeight: 9999);
NavbarHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize; 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)); new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(ContentHolder, flexibleHeight: 9999); UIFactory.SetLayoutElement(ContentHolder, flexibleHeight: 9999);
ContentRect = ContentHolder.GetComponent<RectTransform>(); ContentRect = ContentHolder.GetComponent<RectTransform>();
UIManager.SetPanelActive(PanelType, false); this.SetActive(false);
} }
} }
} }

View File

@ -3,23 +3,18 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Config; using UnityExplorer.Config;
using UnityExplorer.UI.Widgets;
using UniverseLib; using UniverseLib;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility; using UniverseLib.Utility;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels
{ {
// TODO move the logic out of this class into a LogUtil class (also move ExplorerCore.Log into that) public class LogPanel : UEPanel, ICellPoolDataSource<ConsoleLogCell>
public class LogPanel : UIPanel, ICellPoolDataSource<ConsoleLogCell>
{ {
public struct LogInfo public struct LogInfo
{ {
@ -29,7 +24,7 @@ namespace UnityExplorer.UI.Panels
public LogInfo(string message, LogType type) { this.message = message; this.type = type; } public LogInfo(string message, LogType type) { this.message = message; this.type = type; }
} }
private static readonly List<LogInfo> Logs = new List<LogInfo>(); private static readonly List<LogInfo> Logs = new();
private static string CurrentStreamPath; private static string CurrentStreamPath;
public override string Name => "Log"; public override string Name => "Log";
@ -37,6 +32,9 @@ namespace UnityExplorer.UI.Panels
public override int MinWidth => 350; public override int MinWidth => 350;
public override int MinHeight => 75; public override int MinHeight => 75;
public override Vector2 DefaultAnchorMin => new(0.5f, 0.03f);
public override Vector2 DefaultAnchorMax => new(0.9f, 0.2f);
public override bool ShouldSaveActiveState => true; public override bool ShouldSaveActiveState => true;
public override bool ShowByDefault => true; public override bool ShowByDefault => true;
@ -44,7 +42,7 @@ namespace UnityExplorer.UI.Panels
private static ScrollPool<ConsoleLogCell> logScrollPool; private static ScrollPool<ConsoleLogCell> logScrollPool;
public LogPanel() public LogPanel(UIBase owner) : base(owner)
{ {
SetupIO(); SetupIO();
} }
@ -67,16 +65,16 @@ namespace UnityExplorer.UI.Panels
private void SetupIO() private void SetupIO()
{ {
var fileName = $"UnityExplorer {DateTime.Now:u}.txt"; string fileName = $"UnityExplorer {DateTime.Now:u}.txt";
fileName = IOUtility.EnsureValidFilename(fileName); fileName = IOUtility.EnsureValidFilename(fileName);
var path = Path.Combine(ExplorerCore.ExplorerFolder, "Logs"); string path = Path.Combine(ExplorerCore.ExplorerFolder, "Logs");
CurrentStreamPath = IOUtility.EnsureValidFilePath(Path.Combine(path, fileName)); CurrentStreamPath = IOUtility.EnsureValidFilePath(Path.Combine(path, fileName));
// clean old log(s) // clean old log(s)
var files = Directory.GetFiles(path); string[] files = Directory.GetFiles(path);
if (files.Length >= 10) if (files.Length >= 10)
{ {
var sorted = files.ToList(); List<string> sorted = files.ToList();
// sort by 'datetime.ToString("u")' will put the oldest ones first // sort by 'datetime.ToString("u")' will put the oldest ones first
sorted.Sort(); sorted.Sort();
for (int i = 0; i < files.Length - 9; i++) for (int i = 0; i < files.Length - 9; i++)
@ -113,7 +111,7 @@ namespace UnityExplorer.UI.Panels
// Cell pool // Cell pool
private static readonly Dictionary<LogType, Color> logColors = new Dictionary<LogType, Color> private static readonly Dictionary<LogType, Color> logColors = new()
{ {
{ LogType.Log, Color.white }, { LogType.Log, Color.white },
{ LogType.Warning, Color.yellow }, { LogType.Warning, Color.yellow },
@ -122,8 +120,8 @@ namespace UnityExplorer.UI.Panels
{ LogType.Exception, Color.red }, { LogType.Exception, Color.red },
}; };
private readonly Color logEvenColor = new Color(0.34f, 0.34f, 0.34f); private readonly Color logEvenColor = new(0.34f, 0.34f, 0.34f);
private readonly Color logOddColor = new Color(0.28f, 0.28f, 0.28f); private readonly Color logOddColor = new(0.28f, 0.28f, 0.28f);
public void OnCellBorrowed(ConsoleLogCell cell) { } public void OnCellBorrowed(ConsoleLogCell cell) { }
@ -138,50 +136,42 @@ namespace UnityExplorer.UI.Panels
// Logs are displayed in reverse order (newest at top) // Logs are displayed in reverse order (newest at top)
index = Logs.Count - index - 1; index = Logs.Count - index - 1;
var log = Logs[index]; LogInfo log = Logs[index];
cell.IndexLabel.text = $"{index}:"; cell.IndexLabel.text = $"{index}:";
cell.Input.Text = log.message; cell.Input.Text = log.message;
cell.Input.Component.textComponent.color = logColors[log.type]; cell.Input.Component.textComponent.color = logColors[log.type];
var color = index % 2 == 0 ? logEvenColor : logOddColor; Color color = index % 2 == 0 ? logEvenColor : logOddColor;
RuntimeHelper.SetColorBlock(cell.Input.Component, color); RuntimeHelper.SetColorBlock(cell.Input.Component, color);
} }
protected internal override void DoSetDefaultPosAndAnchors()
{
Rect.localPosition = Vector2.zero;
Rect.pivot = new Vector2(0f, 1f);
Rect.anchorMin = new Vector2(0.5f, 0.03f);
Rect.anchorMax = new Vector2(0.9f, 0.2f);
}
// UI Construction // UI Construction
public override void ConstructPanelContent() protected override void ConstructPanelContent()
{ {
// Log scroll pool // Log scroll pool
logScrollPool = UIFactory.CreateScrollPool<ConsoleLogCell>(this.uiContent, "Logs", out GameObject scrollObj, logScrollPool = UIFactory.CreateScrollPool<ConsoleLogCell>(this.ContentRoot, "Logs", out GameObject scrollObj,
out GameObject scrollContent, new Color(0.03f, 0.03f, 0.03f)); out GameObject scrollContent, new Color(0.03f, 0.03f, 0.03f));
UIFactory.SetLayoutElement(scrollObj, flexibleWidth: 9999, flexibleHeight: 9999); UIFactory.SetLayoutElement(scrollObj, flexibleWidth: 9999, flexibleHeight: 9999);
// Buttons and toggles // Buttons and toggles
var optionsRow = UIFactory.CreateUIObject("OptionsRow", this.uiContent); GameObject optionsRow = UIFactory.CreateUIObject("OptionsRow", this.ContentRoot);
UIFactory.SetLayoutElement(optionsRow, minHeight: 25, flexibleWidth: 9999); UIFactory.SetLayoutElement(optionsRow, minHeight: 25, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(optionsRow, false, false, true, true, 5, 2, 2, 2, 2); UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(optionsRow, false, false, true, true, 5, 2, 2, 2, 2);
var clearButton = UIFactory.CreateButton(optionsRow, "ClearButton", "Clear", new Color(0.2f, 0.2f, 0.2f)); ButtonRef clearButton = UIFactory.CreateButton(optionsRow, "ClearButton", "Clear", new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(clearButton.Component.gameObject, minHeight: 23, flexibleHeight: 0, minWidth: 60); UIFactory.SetLayoutElement(clearButton.Component.gameObject, minHeight: 23, flexibleHeight: 0, minWidth: 60);
clearButton.OnClick += ClearLogs; clearButton.OnClick += ClearLogs;
clearButton.Component.transform.SetSiblingIndex(1); clearButton.Component.transform.SetSiblingIndex(1);
var fileButton = UIFactory.CreateButton(optionsRow, "FileButton", "Open Log File", new Color(0.2f, 0.2f, 0.2f)); ButtonRef fileButton = UIFactory.CreateButton(optionsRow, "FileButton", "Open Log File", new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(fileButton.Component.gameObject, minHeight: 23, flexibleHeight: 0, minWidth: 100); UIFactory.SetLayoutElement(fileButton.Component.gameObject, minHeight: 23, flexibleHeight: 0, minWidth: 100);
fileButton.OnClick += OpenLogFile; fileButton.OnClick += OpenLogFile;
fileButton.Component.transform.SetSiblingIndex(2); fileButton.Component.transform.SetSiblingIndex(2);
var unityToggle = UIFactory.CreateToggle(optionsRow, "UnityLogToggle", out var toggle, out var toggleText); GameObject unityToggle = UIFactory.CreateToggle(optionsRow, "UnityLogToggle", out Toggle toggle, out Text toggleText);
UIFactory.SetLayoutElement(unityToggle, minHeight: 25, minWidth: 150); UIFactory.SetLayoutElement(unityToggle, minHeight: 25, minWidth: 150);
toggleText.text = "Log Unity Debug?"; toggleText.text = "Log Unity Debug?";
toggle.isOn = ConfigManager.Log_Unity_Debug.Value; toggle.isOn = ConfigManager.Log_Unity_Debug.Value;

View File

@ -1,20 +1,14 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.Inspectors.MouseInspectors; using UnityExplorer.Inspectors.MouseInspectors;
using UnityExplorer.UI.Widgets;
using UniverseLib;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ButtonList; using UniverseLib.UI.Widgets.ButtonList;
using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility; using UniverseLib.Utility;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels
{ {
public class MouseInspectorResultsPanel : UIPanel public class MouseInspectorResultsPanel : UEPanel
{ {
public override UIManager.Panels PanelType => UIManager.Panels.UIInspectorResults; public override UIManager.Panels PanelType => UIManager.Panels.UIInspectorResults;
@ -22,6 +16,9 @@ namespace UnityExplorer.UI.Panels
public override int MinWidth => 500; public override int MinWidth => 500;
public override int MinHeight => 500; public override int MinHeight => 500;
public override Vector2 DefaultAnchorMin => new(0.5f, 0.5f);
public override Vector2 DefaultAnchorMax => new(0.5f, 0.5f);
public override bool CanDragAndResize => true; public override bool CanDragAndResize => true;
public override bool NavButtonWanted => false; public override bool NavButtonWanted => false;
public override bool ShouldSaveActiveState => false; public override bool ShouldSaveActiveState => false;
@ -30,6 +27,10 @@ namespace UnityExplorer.UI.Panels
private ButtonListHandler<GameObject, ButtonCell> dataHandler; private ButtonListHandler<GameObject, ButtonCell> dataHandler;
private ScrollPool<ButtonCell> buttonScrollPool; private ScrollPool<ButtonCell> buttonScrollPool;
public MouseInspectorResultsPanel(UIBase owner) : base(owner)
{
}
public void ShowResults() public void ShowResults()
{ {
dataHandler.RefreshData(); dataHandler.RefreshData();
@ -53,27 +54,27 @@ namespace UnityExplorer.UI.Panels
if (index >= UiInspector.LastHitObjects.Count) if (index >= UiInspector.LastHitObjects.Count)
return; return;
var obj = UiInspector.LastHitObjects[index]; GameObject obj = UiInspector.LastHitObjects[index];
cell.Button.ButtonText.text = $"<color=cyan>{obj.name}</color> ({obj.transform.GetTransformPath(true)})"; cell.Button.ButtonText.text = $"<color=cyan>{obj.name}</color> ({obj.transform.GetTransformPath(true)})";
} }
public override void ConstructPanelContent() public override void SetDefaultSizeAndPosition()
{
base.SetDefaultSizeAndPosition();
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 500f);
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 500f);
}
protected override void ConstructPanelContent()
{ {
dataHandler = new ButtonListHandler<GameObject, ButtonCell>(buttonScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked); dataHandler = new ButtonListHandler<GameObject, ButtonCell>(buttonScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked);
buttonScrollPool = UIFactory.CreateScrollPool<ButtonCell>(this.uiContent, "ResultsList", out GameObject scrollObj, buttonScrollPool = UIFactory.CreateScrollPool<ButtonCell>(this.ContentRoot, "ResultsList", out GameObject scrollObj,
out GameObject scrollContent); out GameObject scrollContent);
buttonScrollPool.Initialize(dataHandler); buttonScrollPool.Initialize(dataHandler);
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999); UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
} }
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, 500f);
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 500f);
}
} }
} }

View File

@ -1,28 +1,23 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Config;
using UniverseLib.UI.Models;
using UnityExplorer.ObjectExplorer; using UnityExplorer.ObjectExplorer;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI;
using UniverseLib; using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels
{ {
public class ObjectExplorerPanel : UIPanel public class ObjectExplorerPanel : UEPanel
{ {
public override string Name => "Object Explorer"; public override string Name => "Object Explorer";
public override UIManager.Panels PanelType => UIManager.Panels.ObjectExplorer; public override UIManager.Panels PanelType => UIManager.Panels.ObjectExplorer;
public override int MinWidth => 350; public override int MinWidth => 350;
public override int MinHeight => 200; public override int MinHeight => 200;
public override Vector2 DefaultAnchorMin => new(0.125f, 0.175f);
public override Vector2 DefaultAnchorMax => new(0.325f, 0.925f);
public SceneExplorer SceneExplorer; public SceneExplorer SceneExplorer;
public ObjectSearch ObjectSearch; public ObjectSearch ObjectSearch;
@ -31,18 +26,22 @@ namespace UnityExplorer.UI.Panels
public override bool ShouldSaveActiveState => true; public override bool ShouldSaveActiveState => true;
public int SelectedTab = 0; public int SelectedTab = 0;
private readonly List<UIModel> tabPages = new List<UIModel>(); private readonly List<UIModel> tabPages = new();
private readonly List<ButtonRef> tabButtons = new List<ButtonRef>(); private readonly List<ButtonRef> tabButtons = new();
public ObjectExplorerPanel(UIBase owner) : base(owner)
{
}
public void SetTab(int tabIndex) public void SetTab(int tabIndex)
{ {
if (SelectedTab != -1) if (SelectedTab != -1)
DisableTab(SelectedTab); DisableTab(SelectedTab);
var content = tabPages[tabIndex]; UIModel content = tabPages[tabIndex];
content.SetActive(true); content.SetActive(true);
var button = tabButtons[tabIndex]; ButtonRef button = tabButtons[tabIndex];
RuntimeHelper.SetColorBlock(button.Component, UniversalUI.EnabledButtonColor, UniversalUI.EnabledButtonColor * 1.2f); RuntimeHelper.SetColorBlock(button.Component, UniversalUI.EnabledButtonColor, UniversalUI.EnabledButtonColor * 1.2f);
SelectedTab = tabIndex; SelectedTab = tabIndex;
@ -88,28 +87,20 @@ namespace UnityExplorer.UI.Panels
SetTab(SelectedTab); SetTab(SelectedTab);
} }
protected internal override void DoSetDefaultPosAndAnchors() protected override void ConstructPanelContent()
{
Rect.localPosition = Vector2.zero;
Rect.pivot = new Vector2(0f, 1f);
Rect.anchorMin = new Vector2(0.125f, 0.175f);
Rect.anchorMax = new Vector2(0.325f, 0.925f);
}
public override void ConstructPanelContent()
{ {
// Tab bar // Tab bar
var tabGroup = UIFactory.CreateHorizontalGroup(uiContent, "TabBar", true, true, true, true, 2, new Vector4(2, 2, 2, 2)); GameObject tabGroup = UIFactory.CreateHorizontalGroup(ContentRoot, "TabBar", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(tabGroup, minHeight: 25, flexibleHeight: 0); UIFactory.SetLayoutElement(tabGroup, minHeight: 25, flexibleHeight: 0);
// Scene Explorer // Scene Explorer
SceneExplorer = new SceneExplorer(this); SceneExplorer = new SceneExplorer(this);
SceneExplorer.ConstructUI(uiContent); SceneExplorer.ConstructUI(ContentRoot);
tabPages.Add(SceneExplorer); tabPages.Add(SceneExplorer);
// Object search // Object search
ObjectSearch = new ObjectSearch(this); ObjectSearch = new ObjectSearch(this);
ObjectSearch.ConstructUI(uiContent); ObjectSearch.ConstructUI(ContentRoot);
tabPages.Add(ObjectSearch); tabPages.Add(ObjectSearch);
// set up tabs // set up tabs
@ -117,12 +108,12 @@ namespace UnityExplorer.UI.Panels
AddTabButton(tabGroup, "Object Search"); AddTabButton(tabGroup, "Object Search");
// default active state: Active // default active state: Active
UIManager.SetPanelActive(PanelType, true); this.SetActive(true);
} }
private void AddTabButton(GameObject tabGroup, string label) private void AddTabButton(GameObject tabGroup, string label)
{ {
var button = UIFactory.CreateButton(tabGroup, $"Button_{label}", label); ButtonRef button = UIFactory.CreateButton(tabGroup, $"Button_{label}", label);
int idx = tabButtons.Count; int idx = tabButtons.Count;
//button.onClick.AddListener(() => { SetTab(idx); }); //button.onClick.AddListener(() => { SetTab(idx); });

View File

@ -1,32 +1,29 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Config;
using UnityExplorer.CacheObject; using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views; using UnityExplorer.CacheObject.Views;
using UnityExplorer.UI.Widgets; using UnityExplorer.Config;
using UniverseLib.UI.Widgets;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.UI.Widgets.ScrollView;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels
{ {
public class OptionsPanel : UIPanel, ICacheObjectController, ICellPoolDataSource<ConfigEntryCell> public class OptionsPanel : UEPanel, ICacheObjectController, ICellPoolDataSource<ConfigEntryCell>
{ {
public override string Name => "Options"; public override string Name => "Options";
public override UIManager.Panels PanelType => UIManager.Panels.Options; public override UIManager.Panels PanelType => UIManager.Panels.Options;
public override int MinWidth => 600; public override int MinWidth => 600;
public override int MinHeight => 200; public override int MinHeight => 200;
public override Vector2 DefaultAnchorMin => new(0.5f, 0.1f);
public override Vector2 DefaultAnchorMax => new(0.5f, 0.85f);
public override bool ShouldSaveActiveState => false; public override bool ShouldSaveActiveState => false;
public override bool ShowByDefault => false; public override bool ShowByDefault => false;
// Entry holders // Entry holders
private readonly List<CacheConfigEntry> configEntries = new List<CacheConfigEntry>(); private readonly List<CacheConfigEntry> configEntries = new();
// ICacheObjectController // ICacheObjectController
public CacheObjectBase ParentCacheObject => null; public CacheObjectBase ParentCacheObject => null;
@ -37,14 +34,19 @@ namespace UnityExplorer.UI.Panels
// ICellPoolDataSource // ICellPoolDataSource
public int ItemCount => configEntries.Count; public int ItemCount => configEntries.Count;
public OptionsPanel() public OptionsPanel(UIBase owner) : base(owner)
{ {
foreach (var entry in ConfigManager.ConfigElements) foreach (KeyValuePair<string, IConfigElement> entry in ConfigManager.ConfigElements)
{ {
var cache = new CacheConfigEntry(entry.Value); CacheConfigEntry cache = new(entry.Value)
cache.Owner = this; {
Owner = this
};
configEntries.Add(cache); configEntries.Add(cache);
} }
foreach (CacheConfigEntry config in configEntries)
config.UpdateValueFromSource();
} }
public void OnCellBorrowed(ConfigEntryCell cell) public void OnCellBorrowed(ConfigEntryCell cell)
@ -58,32 +60,30 @@ namespace UnityExplorer.UI.Panels
// UI Construction // UI Construction
protected internal override void DoSetDefaultPosAndAnchors() public override void SetDefaultSizeAndPosition()
{ {
Rect.localPosition = Vector2.zero; base.SetDefaultSizeAndPosition();
Rect.pivot = new Vector2(0f, 1f);
Rect.anchorMin = new Vector2(0.5f, 0.1f);
Rect.anchorMax = new Vector2(0.5f, 0.85f);
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 600f); Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 600f);
} }
public override void ConstructPanelContent() protected override void ConstructPanelContent()
{ {
// Save button // Save button
var saveBtn = UIFactory.CreateButton(this.uiContent, "Save", "Save Options", new Color(0.2f, 0.3f, 0.2f)); UniverseLib.UI.Models.ButtonRef saveBtn = UIFactory.CreateButton(this.ContentRoot, "Save", "Save Options", new Color(0.2f, 0.3f, 0.2f));
UIFactory.SetLayoutElement(saveBtn.Component.gameObject, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 0); UIFactory.SetLayoutElement(saveBtn.Component.gameObject, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 0);
saveBtn.OnClick += ConfigManager.Handler.SaveConfig; saveBtn.OnClick += ConfigManager.Handler.SaveConfig;
// Config entries // Config entries
var scrollPool = UIFactory.CreateScrollPool<ConfigEntryCell>(this.uiContent, "ConfigEntries", out GameObject scrollObj, ScrollPool<ConfigEntryCell> scrollPool = UIFactory.CreateScrollPool<ConfigEntryCell>(
this.ContentRoot,
"ConfigEntries",
out GameObject scrollObj,
out GameObject scrollContent); out GameObject scrollContent);
scrollPool.Initialize(this); scrollPool.Initialize(this);
foreach (var config in configEntries)
config.UpdateValueFromSource();
} }
} }
} }

View File

@ -1,492 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UniverseLib.Input;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib;
using UniverseLib.Utility;
namespace UnityExplorer.UI.Panels
{
public class PanelDragger
{
private enum MouseState
{
Down,
Held,
NotPressed
}
#region Static
public static bool Resizing { get; private set; }
public static bool ResizePrompting => resizeCursorObj && resizeCursorObj.activeSelf;
public static GameObject resizeCursorObj;
internal static bool wasAnyDragging;
internal static List<PanelDragger> Instances = new();
private static bool handledInstanceThisFrame;
static PanelDragger()
{
UIPanel.OnPanelsReordered += OnPanelsReordered;
}
internal static void ForceEnd()
{
resizeCursorObj.SetActive(false);
wasAnyDragging = false;
Resizing = false;
foreach (var instance in Instances)
{
instance.WasDragging = false;
instance.WasResizing = false;
}
}
public static void OnPanelsReordered()
{
Instances.Sort((a, b) => b.Panel.GetSiblingIndex().CompareTo(a.Panel.GetSiblingIndex()));
// move AutoCompleter to bottom
if (AutoCompleteModal.Instance != null)
{
var idx = Instances.IndexOf(AutoCompleteModal.Instance.Dragger);
Instances.RemoveAt(idx);
Instances.Insert(0, AutoCompleteModal.Instance.Dragger);
}
}
public static void UpdateInstances()
{
if (!DisplayManager.MouseInTargetDisplay)
return;
if (!resizeCursorObj)
CreateCursorUI();
MouseState state;
if (InputManager.GetMouseButtonDown(0))
state = MouseState.Down;
else if (InputManager.GetMouseButton(0))
state = MouseState.Held;
else
state = MouseState.NotPressed;
var mousePos = DisplayManager.MousePosition;
handledInstanceThisFrame = false;
foreach (var instance in Instances)
{
if (!instance.Panel.gameObject.activeSelf)
continue;
instance.Update(state, mousePos);
if (handledInstanceThisFrame)
break;
}
if (wasAnyDragging && state == MouseState.NotPressed)
{
foreach (var instance in Instances)
instance.WasDragging = false;
wasAnyDragging = false;
}
}
#endregion
// Instance
public UIPanel UIPanel { get; private set; }
public bool AllowDragAndResize => UIPanel.CanDragAndResize;
public RectTransform Panel { get; set; }
public event Action<RectTransform> OnFinishResize;
public event Action<RectTransform> OnFinishDrag;
// Dragging
public RectTransform DragableArea { get; set; }
public bool WasDragging { get; set; }
private Vector2 lastDragPosition;
// Resizing
private const int RESIZE_THICKNESS = 10;
private bool WasResizing { get; set; }
private ResizeTypes currentResizeType = ResizeTypes.NONE;
private Vector2 lastResizePos;
private bool WasHoveringResize => resizeCursorObj.activeInHierarchy;
private ResizeTypes lastResizeHoverType;
private Rect totalResizeRect;
public PanelDragger(RectTransform dragArea, RectTransform panelToDrag, UIPanel panel)
{
this.UIPanel = panel;
Instances.Add(this);
DragableArea = dragArea;
Panel = panelToDrag;
UpdateResizeCache();
}
public void Destroy()
{
if (resizeCursorObj)
GameObject.Destroy(resizeCursorObj);
if (Instances.Contains(this))
Instances.Remove(this);
}
private void Update(MouseState state, Vector3 rawMousePos)
{
ResizeTypes type;
Vector3 resizePos = Panel.InverseTransformPoint(rawMousePos);
bool inResizePos = !UIManager.NavBarRect.rect.Contains(UIManager.NavBarRect.InverseTransformPoint(rawMousePos))
&& MouseInResizeArea(resizePos);
Vector3 dragPos = DragableArea.InverseTransformPoint(rawMousePos);
bool inDragPos = DragableArea.rect.Contains(dragPos);
if (WasHoveringResize && resizeCursorObj)
UpdateHoverImagePos();
switch (state)
{
case MouseState.Down:
if (inDragPos || inResizePos)
UIManager.SetPanelActive(Panel, true);
if (inDragPos)
{
if (AllowDragAndResize)
OnBeginDrag();
handledInstanceThisFrame = true;
return;
}
else if (inResizePos)
{
type = GetResizeType(resizePos);
if (type != ResizeTypes.NONE)
OnBeginResize(type);
handledInstanceThisFrame = true;
}
break;
case MouseState.Held:
if (WasDragging)
{
OnDrag();
handledInstanceThisFrame = true;
}
else if (WasResizing)
{
OnResize();
handledInstanceThisFrame = true;
}
break;
case MouseState.NotPressed:
if (AllowDragAndResize && inDragPos)
{
if (WasDragging)
OnEndDrag();
if (WasHoveringResize)
OnHoverResizeEnd();
handledInstanceThisFrame = true;
}
else if (inResizePos || WasResizing)
{
if (WasResizing)
OnEndResize();
type = GetResizeType(resizePos);
if (type != ResizeTypes.NONE)
OnHoverResize(type);
else if (WasHoveringResize)
OnHoverResizeEnd();
handledInstanceThisFrame = true;
}
else if (WasHoveringResize)
OnHoverResizeEnd();
break;
}
return;
}
#region DRAGGING
public void OnBeginDrag()
{
wasAnyDragging = true;
WasDragging = true;
lastDragPosition = DisplayManager.MousePosition;
}
public void OnDrag()
{
var mousePos = DisplayManager.MousePosition;
Vector2 diff = (Vector2)mousePos - lastDragPosition;
lastDragPosition = mousePos;
Panel.localPosition = Panel.localPosition + (Vector3)diff;
UIPanel.EnsureValidPosition(Panel);
}
public void OnEndDrag()
{
WasDragging = false;
OnFinishDrag?.Invoke(Panel);
}
#endregion
#region RESIZE
private readonly Dictionary<ResizeTypes, Rect> m_resizeMask = new()
{
{ ResizeTypes.Top, default },
{ ResizeTypes.Left, default },
{ ResizeTypes.Right, default },
{ ResizeTypes.Bottom, default },
};
[Flags]
public enum ResizeTypes : ulong
{
NONE = 0,
Top = 1,
Left = 2,
Right = 4,
Bottom = 8,
TopLeft = Top | Left,
TopRight = Top | Right,
BottomLeft = Bottom | Left,
BottomRight = Bottom | Right,
}
// private const int HALF_THICKESS = RESIZE_THICKNESS / 2;
private const int DBL_THICKESS = RESIZE_THICKNESS * 2;
private void UpdateResizeCache()
{
totalResizeRect = new Rect(Panel.rect.x - RESIZE_THICKNESS + 1,
Panel.rect.y - RESIZE_THICKNESS + 1,
Panel.rect.width + DBL_THICKESS - 2,
Panel.rect.height + DBL_THICKESS - 2);
// calculate the four cross sections to use as flags
if (AllowDragAndResize)
{
m_resizeMask[ResizeTypes.Bottom] = new Rect(
totalResizeRect.x,
totalResizeRect.y,
totalResizeRect.width,
RESIZE_THICKNESS);
m_resizeMask[ResizeTypes.Left] = new Rect(
totalResizeRect.x,
totalResizeRect.y,
RESIZE_THICKNESS,
totalResizeRect.height);
m_resizeMask[ResizeTypes.Top] = new Rect(
totalResizeRect.x,
Panel.rect.y + Panel.rect.height - 2,
totalResizeRect.width,
RESIZE_THICKNESS);
m_resizeMask[ResizeTypes.Right] = new Rect(
totalResizeRect.x + Panel.rect.width + RESIZE_THICKNESS - 2,
totalResizeRect.y,
RESIZE_THICKNESS,
totalResizeRect.height);
}
}
private bool MouseInResizeArea(Vector2 mousePos)
{
return totalResizeRect.Contains(mousePos);
}
private ResizeTypes GetResizeType(Vector2 mousePos)
{
// Calculate which part of the resize area we're in, if any.
// More readable method commented out below.
int mask = 0;
mask |= (int)ResizeTypes.Top * (m_resizeMask[ResizeTypes.Top].Contains(mousePos) ? 1 : 0);
mask |= (int)ResizeTypes.Bottom * (m_resizeMask[ResizeTypes.Bottom].Contains(mousePos) ? 1 : 0);
mask |= (int)ResizeTypes.Left * (m_resizeMask[ResizeTypes.Left].Contains(mousePos) ? 1 : 0);
mask |= (int)ResizeTypes.Right * (m_resizeMask[ResizeTypes.Right].Contains(mousePos) ? 1 : 0);
//if (m_resizeMask[ResizeTypes.Top].Contains(mousePos))
// mask |= ResizeTypes.Top;
//else if (m_resizeMask[ResizeTypes.Bottom].Contains(mousePos))
// mask |= ResizeTypes.Bottom;
//if (m_resizeMask[ResizeTypes.Left].Contains(mousePos))
// mask |= ResizeTypes.Left;
//else if (m_resizeMask[ResizeTypes.Right].Contains(mousePos))
// mask |= ResizeTypes.Right;
return (ResizeTypes)mask;
}
public void OnHoverResize(ResizeTypes resizeType)
{
if (WasHoveringResize && lastResizeHoverType == resizeType)
return;
// we are entering resize, or the resize type has changed.
//WasHoveringResize = true;
lastResizeHoverType = resizeType;
resizeCursorObj.SetActive(true);
resizeCursorObj.transform.SetAsLastSibling();
// set the rotation for the resize icon
float iconRotation = 0f;
switch (resizeType)
{
case ResizeTypes.TopRight:
case ResizeTypes.BottomLeft:
iconRotation = 45f; break;
case ResizeTypes.Top:
case ResizeTypes.Bottom:
iconRotation = 90f; break;
case ResizeTypes.TopLeft:
case ResizeTypes.BottomRight:
iconRotation = 135f; break;
}
Quaternion rot = resizeCursorObj.transform.rotation;
rot.eulerAngles = new Vector3(0, 0, iconRotation);
resizeCursorObj.transform.rotation = rot;
UpdateHoverImagePos();
}
// update the resize icon position to be above the mouse
private void UpdateHoverImagePos()
{
resizeCursorObj.transform.localPosition = UIManager.UIRootRect.InverseTransformPoint(DisplayManager.MousePosition);
}
public void OnHoverResizeEnd()
{
//WasHoveringResize = false;
resizeCursorObj.SetActive(false);
}
public void OnBeginResize(ResizeTypes resizeType)
{
currentResizeType = resizeType;
lastResizePos = DisplayManager.MousePosition;
WasResizing = true;
Resizing = true;
}
public void OnResize()
{
Vector3 mousePos = DisplayManager.MousePosition;
Vector2 diff = lastResizePos - (Vector2)mousePos;
if ((Vector2)mousePos == lastResizePos)
return;
if (mousePos.x < 0 || mousePos.y < 0 || mousePos.x > DisplayManager.Width || mousePos.y > DisplayManager.Height)
return;
lastResizePos = mousePos;
float diffX = (float)((decimal)diff.x / DisplayManager.Width);
float diffY = (float)((decimal)diff.y / DisplayManager.Height);
Vector2 anchorMin = Panel.anchorMin;
Vector2 anchorMax = Panel.anchorMax;
if (currentResizeType.HasFlag(ResizeTypes.Left))
anchorMin.x -= diffX;
else if (currentResizeType.HasFlag(ResizeTypes.Right))
anchorMax.x -= diffX;
if (currentResizeType.HasFlag(ResizeTypes.Top))
anchorMax.y -= diffY;
else if (currentResizeType.HasFlag(ResizeTypes.Bottom))
anchorMin.y -= diffY;
var prevMin = Panel.anchorMin;
var prevMax = Panel.anchorMax;
Panel.anchorMin = new Vector2(anchorMin.x, anchorMin.y);
Panel.anchorMax = new Vector2(anchorMax.x, anchorMax.y);
if (Panel.rect.width < UIPanel.MinWidth)
{
Panel.anchorMin = new Vector2(prevMin.x, Panel.anchorMin.y);
Panel.anchorMax = new Vector2(prevMax.x, Panel.anchorMax.y);
}
if (Panel.rect.height < UIPanel.MinHeight)
{
Panel.anchorMin = new Vector2(Panel.anchorMin.x, prevMin.y);
Panel.anchorMax = new Vector2(Panel.anchorMax.x, prevMax.y);
}
}
public void OnEndResize()
{
WasResizing = false;
Resizing = false;
try { OnHoverResizeEnd(); } catch { }
UpdateResizeCache();
OnFinishResize?.Invoke(Panel);
}
internal static void CreateCursorUI()
{
try
{
var text = UIFactory.CreateLabel(UIManager.UIRoot, "ResizeCursor", "↔", TextAnchor.MiddleCenter, Color.white, true, 35);
resizeCursorObj = text.gameObject;
var outline = text.gameObject.AddComponent<Outline>();
outline.effectColor = Color.black;
outline.effectDistance = new(1, 1);
RectTransform rect = resizeCursorObj.GetComponent<RectTransform>();
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 64);
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 64);
resizeCursorObj.SetActive(false);
}
catch (Exception e)
{
ExplorerCore.LogWarning("Exception creating Resize Cursor UI!\r\n" + e.ToString());
}
}
#endregion
}
}

266
src/UI/Panels/UEPanel.cs Normal file
View File

@ -0,0 +1,266 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Config;
using UniverseLib;
using UniverseLib.Input;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.Panels;
namespace UnityExplorer.UI.Panels
{
public abstract class UEPanel : PanelBase
{
protected UEPanel(UIBase owner) : base(owner) { }
public abstract UIManager.Panels PanelType { get; }
public virtual bool ShowByDefault => false;
public virtual bool ShouldSaveActiveState => true;
public virtual bool NavButtonWanted => true;
public ButtonRef NavButton { get; internal set; }
protected override PanelDragger CreatePanelDragger()
{
return new UEPanelDragger(this);
}
public override void OnFinishDrag()
{
base.OnFinishDrag();
SaveInternalData();
}
public override void OnFinishResize()
{
base.OnFinishResize();
SaveInternalData();
}
public override void SetActive(bool active)
{
if (this.Enabled != active)
{
base.SetActive(active);
if (!ApplyingSaveData)
SaveInternalData();
if (NavButtonWanted && NavButton != null)
{
Color color = active ? UniversalUI.EnabledButtonColor : UniversalUI.DisabledButtonColor;
RuntimeHelper.SetColorBlock(NavButton.Component, color, color * 1.2f);
}
}
if (!active)
{
if (Dragger != null)
this.Dragger.WasDragging = false;
}
else
{
this.UIRoot.transform.SetAsLastSibling();
(this.Owner.Panels as UEPanelManager).DoInvokeOnPanelsReordered();
}
}
// Save Data
public bool ApplyingSaveData { get; set; }
public void SaveInternalData()
{
if (UIManager.Initializing || ApplyingSaveData)
return;
SetSaveDataToConfigValue();
}
private void SetSaveDataToConfigValue()
=> ConfigManager.GetPanelSaveData(this.PanelType).Value = this.ToSaveData();
public virtual string ToSaveData()
{
try
{
return string.Join("|", new string[]
{
$"{ShouldSaveActiveState && Enabled}",
Rect.RectAnchorsToString(),
Rect.RectPositionToString()
});
}
catch (Exception ex)
{
ExplorerCore.LogWarning($"Exception generating Panel save data: {ex}");
return "";
}
}
public virtual void ApplySaveData()
{
string data = ConfigManager.GetPanelSaveData(this.PanelType).Value;
ApplySaveData(data);
}
protected virtual void ApplySaveData(string data)
{
if (string.IsNullOrEmpty(data))
return;
string[] split = data.Split('|');
try
{
Rect.SetAnchorsFromString(split[1]);
Rect.SetPositionFromString(split[2]);
this.EnsureValidSize();
this.EnsureValidPosition();
this.SetActive(bool.Parse(split[0]));
}
catch
{
ExplorerCore.LogWarning("Invalid or corrupt panel save data! Restoring to default.");
SetDefaultSizeAndPosition();
SetSaveDataToConfigValue();
}
}
public override void ConstructUI()
{
base.ConstructUI();
if (NavButtonWanted)
{
// create navbar button
NavButton = UIFactory.CreateButton(UIManager.NavbarTabButtonHolder, $"Button_{PanelType}", Name);
GameObject navBtn = NavButton.Component.gameObject;
navBtn.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navBtn, false, true, true, true, 0, 0, 0, 5, 5, TextAnchor.MiddleCenter);
UIFactory.SetLayoutElement(navBtn, minWidth: 80);
RuntimeHelper.SetColorBlock(NavButton.Component, UniversalUI.DisabledButtonColor, UniversalUI.DisabledButtonColor * 1.2f);
NavButton.OnClick += () => { UIManager.TogglePanel(PanelType); };
GameObject txtObj = navBtn.transform.Find("Text").gameObject;
txtObj.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
}
this.SetActive(true);
this.SetActive(false);
this.SetActive(ShowByDefault);
}
protected override void LateConstructUI()
{
ApplyingSaveData = true;
base.LateConstructUI();
// apply panel save data or revert to default
try
{
ApplySaveData();
}
catch (Exception ex)
{
ExplorerCore.Log($"Exception loading panel save data: {ex}");
SetDefaultSizeAndPosition();
}
// simple listener for saving enabled state
this.OnToggleEnabled += (bool val) =>
{
SaveInternalData();
};
ApplyingSaveData = false;
Dragger.OnEndResize();
}
}
#region WINDOW ANCHORS / POSITION SAVE DATA HELPERS
public static class RectSaveExtensions
{
// Window Anchors helpers
internal static string RectAnchorsToString(this RectTransform rect)
{
if (!rect)
throw new ArgumentNullException("rect");
return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", new object[]
{
rect.anchorMin.x,
rect.anchorMin.y,
rect.anchorMax.x,
rect.anchorMax.y
});
}
internal static void SetAnchorsFromString(this RectTransform panel, string stringAnchors)
{
if (string.IsNullOrEmpty(stringAnchors))
throw new ArgumentNullException("stringAnchors");
if (stringAnchors.Contains(" "))
// outdated save data, not worth recovering just reset it.
throw new Exception("invalid save data, resetting.");
string[] split = stringAnchors.Split(',');
if (split.Length != 4)
throw new Exception($"stringAnchors split is unexpected length: {split.Length}");
Vector4 anchors;
anchors.x = float.Parse(split[0], CultureInfo.InvariantCulture);
anchors.y = float.Parse(split[1], CultureInfo.InvariantCulture);
anchors.z = float.Parse(split[2], CultureInfo.InvariantCulture);
anchors.w = float.Parse(split[3], CultureInfo.InvariantCulture);
panel.anchorMin = new Vector2(anchors.x, anchors.y);
panel.anchorMax = new Vector2(anchors.z, anchors.w);
}
internal static string RectPositionToString(this RectTransform rect)
{
if (!rect)
throw new ArgumentNullException("rect");
return string.Format(CultureInfo.InvariantCulture, "{0},{1}", new object[]
{
rect.anchoredPosition.x, rect.anchoredPosition.y
});
}
internal static void SetPositionFromString(this RectTransform rect, string stringPosition)
{
if (string.IsNullOrEmpty(stringPosition))
throw new ArgumentNullException(stringPosition);
if (stringPosition.Contains(" "))
// outdated save data, not worth recovering just reset it.
throw new Exception("invalid save data, resetting.");
string[] split = stringPosition.Split(',');
if (split.Length != 2)
throw new Exception($"stringPosition split is unexpected length: {split.Length}");
Vector3 vector = rect.anchoredPosition;
vector.x = float.Parse(split[0], CultureInfo.InvariantCulture);
vector.y = float.Parse(split[1], CultureInfo.InvariantCulture);
rect.anchoredPosition = vector;
}
}
#endregion
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.Input;
using UniverseLib.UI;
using UniverseLib.UI.Panels;
using UniverseLib.Utility;
namespace UnityExplorer.UI.Panels
{
public class UEPanelDragger : PanelDragger
{
public UEPanelDragger(PanelBase uiPanel) : base(uiPanel) { }
protected override bool MouseInResizeArea(Vector2 mousePos)
{
return !UIManager.NavBarRect.rect.Contains(UIManager.NavBarRect.InverseTransformPoint(mousePos))
&& base.MouseInResizeArea(mousePos);
}
}
}

View File

@ -1,423 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Config;
using UniverseLib.Input;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI.Models;
using UniverseLib.UI;
using UniverseLib;
using System.Collections;
namespace UnityExplorer.UI.Panels
{
public abstract class UIPanel : UIBehaviourModel
{
#region STATIC
internal static void InvokeOnPanelsReordered() => OnPanelsReordered?.Invoke();
public static event Action OnPanelsReordered;
public static event Action OnClickedOutsidePanels;
internal static readonly List<UIPanel> instances = new();
internal static readonly Dictionary<int, UIPanel> transformToPanelDict = new();
public static void UpdateFocus()
{
if (PanelDragger.ResizePrompting)
return;
// if the user is clicking
if (DisplayManager.MouseInTargetDisplay
&& (InputManager.GetMouseButtonDown(0) || InputManager.GetMouseButtonDown(1)))
{
int count = UIManager.PanelHolder.transform.childCount;
Vector3 mousePos = DisplayManager.MousePosition;
bool clickedInAny = false;
for (int i = count - 1; i >= 0; i--)
{
// make sure this is a real recognized panel
Transform transform = UIManager.PanelHolder.transform.GetChild(i);
if (!transformToPanelDict.TryGetValue(transform.GetInstanceID(), out UIPanel panel))
continue;
// check if our mouse is clicking inside the panel
Vector3 pos = panel.Rect.InverseTransformPoint(mousePos);
if (!panel.Enabled || !panel.Rect.rect.Contains(pos))
continue;
// if this is not the top panel, reorder and invoke the onchanged event
if (transform.GetSiblingIndex() != count - 1)
{
transform.SetAsLastSibling();
OnPanelsReordered?.Invoke();
}
// panel was found, break
clickedInAny = true;
break;
}
if (!clickedInAny)
OnClickedOutsidePanels?.Invoke();
}
}
#endregion
// INSTANCE
public UIPanel()
{
instances.Add(this);
}
public abstract UIManager.Panels PanelType { get; }
public abstract string Name { get; }
public abstract int MinWidth { get; }
public abstract int MinHeight { get; }
public virtual bool ShowByDefault => false;
public virtual bool ShouldSaveActiveState => true;
public virtual bool CanDragAndResize => true;
public virtual bool NavButtonWanted => true;
public ButtonRef NavButton { get; internal set; }
public PanelDragger Dragger { get; internal set; }
public override GameObject UIRoot => uiRoot;
protected GameObject uiRoot;
protected GameObject uiContent;
public RectTransform Rect { get; private set; }
public GameObject TitleBar { get; private set; }
public virtual void OnFinishResize(RectTransform panel)
{
SaveInternalData();
}
public virtual void OnFinishDrag(RectTransform panel)
{
SaveInternalData();
}
public override void SetActive(bool active)
{
if (this.Enabled != active)
{
base.SetActive(active);
if (!ApplyingSaveData)
SaveInternalData();
if (NavButtonWanted)
{
var color = active ? UniversalUI.EnabledButtonColor : UniversalUI.DisabledButtonColor;
RuntimeHelper.SetColorBlock(NavButton.Component, color, color * 1.2f);
}
}
if (!active)
this.Dragger.WasDragging = false;
else
{
this.UIRoot.transform.SetAsLastSibling();
InvokeOnPanelsReordered();
}
}
public override void Destroy()
{
instances.Remove(this);
base.Destroy();
}
protected internal abstract void DoSetDefaultPosAndAnchors();
public void SetTransformDefaults()
{
DoSetDefaultPosAndAnchors();
}
public void EnsureValidSize()
{
if (Rect.rect.width < MinWidth)
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth);
if (Rect.rect.height < MinHeight)
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
}
public void EnsureValidPosition() => EnsureValidPosition(this.Rect);
public static void EnsureValidPosition(RectTransform panel)
{
var pos = panel.localPosition;
// Prevent panel going oustide screen bounds
var halfW = DisplayManager.Width * 0.5f;
var halfH = DisplayManager.Height * 0.5f;
pos.x = Math.Max(-halfW - panel.rect.width + 50, Math.Min(pos.x, halfW - 50));
pos.y = Math.Max(-halfH + 50, Math.Min(pos.y, halfH));
panel.localPosition = pos;
}
// Save Data
public bool ApplyingSaveData { get; set; }
public void SaveInternalData()
{
if (UIManager.Initializing)
return;
SetSaveDataToConfigValue();
}
private void SetSaveDataToConfigValue() => ConfigManager.GetPanelSaveData(this.PanelType).Value = this.ToSaveData();
public virtual string ToSaveData()
{
try
{
return string.Join("|", new string[]
{
$"{ShouldSaveActiveState && Enabled}",
Rect.RectAnchorsToString(),
Rect.RectPositionToString()
});
}
catch (Exception ex)
{
ExplorerCore.LogWarning($"Exception generating Panel save data: {ex}");
return "";
}
}
public virtual void ApplySaveData()
{
string data = ConfigManager.GetPanelSaveData(this.PanelType).Value;
ApplySaveData(data);
}
protected virtual void ApplySaveData(string data)
{
if (string.IsNullOrEmpty(data))
return;
var split = data.Split('|');
try
{
Rect.SetAnchorsFromString(split[1]);
Rect.SetPositionFromString(split[2]);
UIManager.SetPanelActive(this.PanelType, bool.Parse(split[0]));
}
catch
{
ExplorerCore.LogWarning("Invalid or corrupt panel save data! Restoring to default.");
SetTransformDefaults();
SetSaveDataToConfigValue();
}
}
// UI Construction
public abstract void ConstructPanelContent();
public void ConstructUI()
{
//this.Enabled = true;
if (NavButtonWanted)
{
// create navbar button
NavButton = UIFactory.CreateButton(UIManager.NavbarTabButtonHolder, $"Button_{PanelType}", Name);
var navBtn = NavButton.Component.gameObject;
navBtn.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navBtn, false, true, true, true, 0, 0, 0, 5, 5, TextAnchor.MiddleCenter);
UIFactory.SetLayoutElement(navBtn, minWidth: 80);
RuntimeHelper.SetColorBlock(NavButton.Component, UniversalUI.DisabledButtonColor, UniversalUI.DisabledButtonColor * 1.2f);
NavButton.OnClick += () => { UIManager.TogglePanel(PanelType); };
var txtObj = navBtn.transform.Find("Text").gameObject;
txtObj.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
}
// create core canvas
uiRoot = UIFactory.CreatePanel(Name, UIManager.PanelHolder, out uiContent);
Rect = this.uiRoot.GetComponent<RectTransform>();
//UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.uiRoot, false, false, true, true, 0, 2, 2, 2, 2, TextAnchor.UpperLeft);
int id = this.uiRoot.transform.GetInstanceID();
transformToPanelDict.Add(id, this);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.uiContent, false, false, true, true, 2, 2, 2, 2, 2, TextAnchor.UpperLeft);
// Title bar
TitleBar = UIFactory.CreateHorizontalGroup(uiContent, "TitleBar", false, true, true, true, 2,
new Vector4(2, 2, 2, 2), new Color(0.06f, 0.06f, 0.06f));
UIFactory.SetLayoutElement(TitleBar, minHeight: 25, flexibleHeight: 0);
// Title text
var titleTxt = UIFactory.CreateLabel(TitleBar, "TitleBar", Name, TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(titleTxt.gameObject, minWidth: 250, minHeight: 25, flexibleHeight: 0);
// close button
var closeHolder = UIFactory.CreateUIObject("CloseHolder", TitleBar);
UIFactory.SetLayoutElement(closeHolder, minHeight: 25, flexibleHeight: 0, minWidth: 30, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(closeHolder, false, false, true, true, 3, childAlignment: TextAnchor.MiddleRight);
var closeBtn = UIFactory.CreateButton(closeHolder, "CloseButton", "—");
UIFactory.SetLayoutElement(closeBtn.Component.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0);
RuntimeHelper.SetColorBlock(closeBtn.Component, new Color(0.33f, 0.32f, 0.31f));
closeBtn.OnClick += () =>
{
UIManager.SetPanelActive(this.PanelType, false);
SaveInternalData();
};
if (!CanDragAndResize)
TitleBar.SetActive(false);
// Panel dragger
Dragger = new PanelDragger(TitleBar.GetComponent<RectTransform>(), Rect, this);
Dragger.OnFinishResize += OnFinishResize;
Dragger.OnFinishDrag += OnFinishDrag;
// content (abstract)
ConstructPanelContent();
UIManager.SetPanelActive(this.PanelType, true);
UIManager.SetPanelActive(this.PanelType, false);
UIManager.SetPanelActive(this.PanelType, ShowByDefault);
ApplyingSaveData = true;
SetTransformDefaults();
// apply panel save data or revert to default
try
{
ApplySaveData();
}
catch (Exception ex)
{
ExplorerCore.Log($"Exception loading panel save data: {ex}");
SetTransformDefaults();
}
RuntimeHelper.StartCoroutine(LateSetupCoroutine());
// simple listener for saving enabled state
this.OnToggleEnabled += (bool val) =>
{
SaveInternalData();
};
ApplyingSaveData = false;
}
private IEnumerator LateSetupCoroutine()
{
yield return null;
// ensure initialized position is valid
EnsureValidSize();
EnsureValidPosition(this.Rect);
// update dragger and save data
Dragger.OnEndResize();
}
public override void ConstructUI(GameObject parent) => ConstructUI();
}
#region WINDOW ANCHORS / POSITION HELPERS
public static class RectSaveExtensions
{
// Window Anchors helpers
internal static string RectAnchorsToString(this RectTransform rect)
{
if (!rect)
throw new ArgumentNullException("rect");
return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2},{3}", new object[]
{
rect.anchorMin.x,
rect.anchorMin.y,
rect.anchorMax.x,
rect.anchorMax.y
});
}
internal static void SetAnchorsFromString(this RectTransform panel, string stringAnchors)
{
if (string.IsNullOrEmpty(stringAnchors))
throw new ArgumentNullException("stringAnchors");
if (stringAnchors.Contains(" "))
// outdated save data, not worth recovering just reset it.
throw new Exception("invalid save data, resetting.");
var split = stringAnchors.Split(',');
if (split.Length != 4)
throw new Exception($"stringAnchors split is unexpected length: {split.Length}");
Vector4 anchors;
anchors.x = float.Parse(split[0], CultureInfo.InvariantCulture);
anchors.y = float.Parse(split[1], CultureInfo.InvariantCulture);
anchors.z = float.Parse(split[2], CultureInfo.InvariantCulture);
anchors.w = float.Parse(split[3], CultureInfo.InvariantCulture);
panel.anchorMin = new Vector2(anchors.x, anchors.y);
panel.anchorMax = new Vector2(anchors.z, anchors.w);
}
internal static string RectPositionToString(this RectTransform rect)
{
if (!rect)
throw new ArgumentNullException("rect");
return string.Format(CultureInfo.InvariantCulture, "{0},{1}", new object[]
{
rect.anchoredPosition.x, rect.anchoredPosition.y
});
}
internal static void SetPositionFromString(this RectTransform rect, string stringPosition)
{
if (string.IsNullOrEmpty(stringPosition))
throw new ArgumentNullException(stringPosition);
if (stringPosition.Contains(" "))
// outdated save data, not worth recovering just reset it.
throw new Exception("invalid save data, resetting.");
var split = stringPosition.Split(',');
if (split.Length != 2)
throw new Exception($"stringPosition split is unexpected length: {split.Length}");
Vector3 vector = rect.anchoredPosition;
vector.x = float.Parse(split[0], CultureInfo.InvariantCulture);
vector.y = float.Parse(split[1], CultureInfo.InvariantCulture);
rect.anchoredPosition = vector;
}
}
#endregion
}

39
src/UI/UEPanelManager.cs Normal file
View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.UI.Panels;
using UniverseLib.UI;
using UniverseLib.UI.Panels;
namespace UnityExplorer.UI
{
public class UEPanelManager : PanelManager
{
public UEPanelManager(UIBase owner) : base(owner) { }
protected override Vector3 MousePosition => DisplayManager.MousePosition;
protected override Vector2 ScreenDimensions => new(DisplayManager.Width, DisplayManager.Height);
protected override bool MouseInTargetDisplay => DisplayManager.MouseInTargetDisplay;
internal void DoInvokeOnPanelsReordered()
{
InvokeOnPanelsReordered();
}
protected override void SortDraggerHeirarchy()
{
base.SortDraggerHeirarchy();
// move AutoCompleter to first update
if (!UIManager.Initializing && AutoCompleteModal.Instance != null)
{
this.draggerInstances.Remove(AutoCompleteModal.Instance.Dragger);
this.draggerInstances.Insert(0, AutoCompleteModal.Instance.Dragger);
}
}
}
}

View File

@ -10,8 +10,7 @@ using UniverseLib;
using UniverseLib.Input; using UniverseLib.Input;
using UniverseLib.UI; using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib.UI.ObjectPool; using UniverseLib.UI.Panels;
using UniverseLib.UI.Widgets;
using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility; using UniverseLib.Utility;
@ -27,10 +26,10 @@ namespace UnityExplorer.UI
Options, Options,
ConsoleLog, ConsoleLog,
AutoCompleter, AutoCompleter,
MouseInspector,
UIInspectorResults, UIInspectorResults,
HookManager, HookManager,
Clipboard Clipboard,
Freecam
} }
public enum VerticalAnchor public enum VerticalAnchor
@ -48,8 +47,7 @@ namespace UnityExplorer.UI
public static RectTransform UIRootRect { get; private set; } public static RectTransform UIRootRect { get; private set; }
public static Canvas UICanvas { get; private set; } public static Canvas UICanvas { get; private set; }
internal static GameObject PanelHolder { get; private set; } internal static readonly Dictionary<Panels, UEPanel> UIPanels = new();
internal static readonly Dictionary<Panels, UIPanel> UIPanels = new();
public static RectTransform NavBarRect; public static RectTransform NavBarRect;
public static GameObject NavbarTabButtonHolder; public static GameObject NavbarTabButtonHolder;
@ -81,7 +79,7 @@ namespace UnityExplorer.UI
internal static void InitUI() internal static void InitUI()
{ {
UiBase = UniversalUI.RegisterUI(ExplorerCore.GUID, Update); UiBase = UniversalUI.RegisterUI<ExplorerUIBase>(ExplorerCore.GUID, Update);
UIRootRect = UIRoot.GetComponent<RectTransform>(); UIRootRect = UIRoot.GetComponent<RectTransform>();
UICanvas = UIRoot.GetComponent<Canvas>(); UICanvas = UIRoot.GetComponent<Canvas>();
@ -93,39 +91,35 @@ namespace UnityExplorer.UI
lastScreenHeight = display.renderingHeight; lastScreenHeight = display.renderingHeight;
// Create UI. // Create UI.
CreatePanelHolder();
CreateTopNavBar(); CreateTopNavBar();
// This could be automated with Assembly.GetTypes(), // This could be automated with Assembly.GetTypes(),
// but the order is important and I'd have to write something to handle the order. // but the order is important and I'd have to write something to handle the order.
UIPanels.Add(Panels.AutoCompleter, new AutoCompleteModal()); UIPanels.Add(Panels.AutoCompleter, new AutoCompleteModal(UiBase));
UIPanels.Add(Panels.ObjectExplorer, new ObjectExplorerPanel()); UIPanels.Add(Panels.ObjectExplorer, new ObjectExplorerPanel(UiBase));
UIPanels.Add(Panels.Inspector, new InspectorPanel()); UIPanels.Add(Panels.Inspector, new InspectorPanel(UiBase));
UIPanels.Add(Panels.CSConsole, new CSConsolePanel()); UIPanels.Add(Panels.CSConsole, new CSConsolePanel(UiBase));
UIPanels.Add(Panels.HookManager, new HookManagerPanel()); UIPanels.Add(Panels.HookManager, new HookManagerPanel(UiBase));
UIPanels.Add(Panels.Clipboard, new ClipboardPanel()); UIPanels.Add(Panels.Freecam, new FreeCamPanel(UiBase));
UIPanels.Add(Panels.ConsoleLog, new LogPanel()); UIPanels.Add(Panels.Clipboard, new ClipboardPanel(UiBase));
UIPanels.Add(Panels.Options, new OptionsPanel()); UIPanels.Add(Panels.ConsoleLog, new LogPanel(UiBase));
UIPanels.Add(Panels.UIInspectorResults, new MouseInspectorResultsPanel()); UIPanels.Add(Panels.Options, new OptionsPanel(UiBase));
UIPanels.Add(Panels.MouseInspector, new MouseInspector()); UIPanels.Add(Panels.UIInspectorResults, new MouseInspectorResultsPanel(UiBase));
foreach (var panel in UIPanels.Values) MouseInspector.inspectorUIBase = UniversalUI.RegisterUI(MouseInspector.UIBaseGUID, null);
panel.ConstructUI(); new MouseInspector(MouseInspector.inspectorUIBase);
// Call some initialize methods // Call some initialize methods
Notification.Init(); Notification.Init();
ConsoleController.Init(); ConsoleController.Init();
// Add this listener to prevent ScrollPool doing anything while we are resizing panels
ScrollPool<ICell>.writingLockedListeners.Add(() => !PanelDragger.Resizing);
// Set default menu visibility
ShowMenu = !ConfigManager.Hide_On_Startup.Value;
// Failsafe fix, in some games all dropdowns displayed values are blank on startup for some reason. // Failsafe fix, in some games all dropdowns displayed values are blank on startup for some reason.
foreach (var dropdown in UIRoot.GetComponentsInChildren<Dropdown>(true)) foreach (Dropdown dropdown in UIRoot.GetComponentsInChildren<Dropdown>(true))
dropdown.RefreshShownValue(); dropdown.RefreshShownValue();
Initializing = false; Initializing = false;
if (ConfigManager.Hide_On_Startup.Value)
ShowMenu = false;
} }
// Main UI Update loop // Main UI Update loop
@ -146,10 +140,6 @@ namespace UnityExplorer.UI
if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value)) if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value))
UniverseLib.Config.ConfigManager.Force_Unlock_Mouse = !UniverseLib.Config.ConfigManager.Force_Unlock_Mouse; UniverseLib.Config.ConfigManager.Force_Unlock_Mouse = !UniverseLib.Config.ConfigManager.Force_Unlock_Mouse;
// update focused panel
UIPanel.UpdateFocus();
PanelDragger.UpdateInstances();
// update the timescale value // update the timescale value
if (!timeInput.Component.isFocused && lastTimeScale != Time.timeScale) if (!timeInput.Component.isFocused && lastTimeScale != Time.timeScale)
{ {
@ -167,40 +157,33 @@ namespace UnityExplorer.UI
} }
// check screen dimension change // check screen dimension change
var display = DisplayManager.ActiveDisplay; Display display = DisplayManager.ActiveDisplay;
if (display.renderingWidth != lastScreenWidth || display.renderingHeight != lastScreenHeight) if (display.renderingWidth != lastScreenWidth || display.renderingHeight != lastScreenHeight)
OnScreenDimensionsChanged(); OnScreenDimensionsChanged();
} }
// Panels // Panels
public static UIPanel GetPanel(Panels panel) => UIPanels[panel]; public static UEPanel GetPanel(Panels panel) => UIPanels[panel];
public static T GetPanel<T>(Panels panel) where T : UIPanel => (T)UIPanels[panel]; public static T GetPanel<T>(Panels panel) where T : UEPanel => (T)UIPanels[panel];
public static void TogglePanel(Panels panel) public static void TogglePanel(Panels panel)
{ {
var uiPanel = GetPanel(panel); UEPanel uiPanel = GetPanel(panel);
SetPanelActive(panel, !uiPanel.Enabled); SetPanelActive(panel, !uiPanel.Enabled);
} }
public static void SetPanelActive(Panels panelType, bool active) public static void SetPanelActive(Panels panelType, bool active)
{ {
GetPanel(panelType) GetPanel(panelType).SetActive(active);
.SetActive(active);
} }
public static void SetPanelActive(UIPanel panel, bool active) public static void SetPanelActive(UEPanel panel, bool active)
{ {
panel.SetActive(active); panel.SetActive(active);
} }
internal static void SetPanelActive(Transform transform, bool value)
{
if (UIPanel.transformToPanelDict.TryGetValue(transform.GetInstanceID(), out UIPanel panel))
panel.SetActive(value);
}
// navbar // navbar
public static void SetNavBarAnchor() public static void SetNavBarAnchor()
@ -227,14 +210,14 @@ namespace UnityExplorer.UI
private static void OnScreenDimensionsChanged() private static void OnScreenDimensionsChanged()
{ {
var display = DisplayManager.ActiveDisplay; Display display = DisplayManager.ActiveDisplay;
lastScreenWidth = display.renderingWidth; lastScreenWidth = display.renderingWidth;
lastScreenHeight = display.renderingHeight; lastScreenHeight = display.renderingHeight;
foreach (var panel in UIPanels) foreach (KeyValuePair<Panels, UEPanel> panel in UIPanels)
{ {
panel.Value.EnsureValidSize(); panel.Value.EnsureValidSize();
UIPanel.EnsureValidPosition(panel.Value.Rect); panel.Value.EnsureValidPosition();
panel.Value.Dragger.OnEndResize(); panel.Value.Dragger.OnEndResize();
} }
} }
@ -287,23 +270,9 @@ namespace UnityExplorer.UI
// UI Construction // UI Construction
private static void CreatePanelHolder()
{
PanelHolder = new GameObject("PanelHolder");
PanelHolder.transform.SetParent(UIRoot.transform, false);
PanelHolder.layer = 5;
var rect = PanelHolder.AddComponent<RectTransform>();
rect.sizeDelta = Vector2.zero;
rect.anchoredPosition = Vector2.zero;
rect.pivot = new Vector2(0.5f, 0.5f);
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
PanelHolder.transform.SetAsFirstSibling();
}
private static void CreateTopNavBar() private static void CreateTopNavBar()
{ {
var navbarPanel = UIFactory.CreateUIObject("MainNavbar", UIRoot); GameObject navbarPanel = UIFactory.CreateUIObject("MainNavbar", UIRoot);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navbarPanel, false, false, true, true, 5, 4, 4, 4, 4, TextAnchor.MiddleCenter); UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navbarPanel, false, false, true, true, 5, 4, 4, 4, 4, TextAnchor.MiddleCenter);
navbarPanel.AddComponent<Image>().color = new Color(0.1f, 0.1f, 0.1f); navbarPanel.AddComponent<Image>().color = new Color(0.1f, 0.1f, 0.1f);
NavBarRect = navbarPanel.GetComponent<RectTransform>(); NavBarRect = navbarPanel.GetComponent<RectTransform>();
@ -319,9 +288,9 @@ namespace UnityExplorer.UI
// UnityExplorer title // UnityExplorer title
string titleTxt = $"{ExplorerCore.NAME} <i><color=grey>{ExplorerCore.VERSION}</color></i>"; string titleTxt = $"UE <i><color=grey>{ExplorerCore.VERSION}</color></i>";
var title = UIFactory.CreateLabel(navbarPanel, "Title", titleTxt, TextAnchor.MiddleLeft, default, true, 17); Text title = UIFactory.CreateLabel(navbarPanel, "Title", titleTxt, TextAnchor.MiddleCenter, default, true, 14);
UIFactory.SetLayoutElement(title.gameObject, minWidth: 170, flexibleWidth: 0); UIFactory.SetLayoutElement(title.gameObject, minWidth: 75, flexibleWidth: 0);
// panel tabs // panel tabs
@ -331,7 +300,7 @@ namespace UnityExplorer.UI
// Time controls // Time controls
var timeLabel = UIFactory.CreateLabel(navbarPanel, "TimeLabel", "Time:", TextAnchor.MiddleRight, Color.grey); Text timeLabel = UIFactory.CreateLabel(navbarPanel, "TimeLabel", "Time:", TextAnchor.MiddleRight, Color.grey);
UIFactory.SetLayoutElement(timeLabel.gameObject, minHeight: 25, minWidth: 50); UIFactory.SetLayoutElement(timeLabel.gameObject, minHeight: 25, minWidth: 50);
timeInput = UIFactory.CreateInputField(navbarPanel, "TimeInput", "timeScale"); timeInput = UIFactory.CreateInputField(navbarPanel, "TimeInput", "timeScale");

View File

@ -2,8 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using UnityExplorer.CacheObject.IValues; using UnityExplorer.CacheObject.IValues;
using UniverseLib; using UnityExplorer.UI.Panels;
using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib.Utility; using UniverseLib.Utility;
@ -30,8 +29,8 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
public InputFieldRef InputField { get; } public InputFieldRef InputField { get; }
public bool AnchorToCaretPosition => false; public bool AnchorToCaretPosition => false;
private readonly List<Suggestion> suggestions = new List<Suggestion>(); private readonly List<Suggestion> suggestions = new();
private readonly HashSet<string> suggestedValues = new HashSet<string>(); private readonly HashSet<string> suggestedValues = new();
private OrderedDictionary enumValues; private OrderedDictionary enumValues;
@ -139,13 +138,13 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
for (int i = 0; i < this.enumValues.Count; i++) for (int i = 0; i < this.enumValues.Count; i++)
{ {
var enumValue = (CachedEnumValue)enumValues[i]; CachedEnumValue enumValue = (CachedEnumValue)enumValues[i];
if (enumValue.Name.ContainsIgnoreCase(value)) if (enumValue.Name.ContainsIgnoreCase(value))
AddSuggestion(enumValue.Name); AddSuggestion(enumValue.Name);
} }
} }
internal static readonly Dictionary<string, string> sharedValueToLabel = new Dictionary<string, string>(4096); internal static readonly Dictionary<string, string> sharedValueToLabel = new(4096);
void AddSuggestion(string value) void AddSuggestion(string value)
{ {

View File

@ -1,11 +1,4 @@
using System; using UniverseLib.UI.Models;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UniverseLib.UI;
using UniverseLib.UI.Models;
namespace UnityExplorer.UI.Widgets.AutoComplete namespace UnityExplorer.UI.Widgets.AutoComplete
{ {

View File

@ -1,10 +1,4 @@
using System; namespace UnityExplorer.UI.Widgets.AutoComplete
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
namespace UnityExplorer.UI.Widgets.AutoComplete
{ {
public struct Suggestion public struct Suggestion
{ {

View File

@ -1,9 +1,11 @@
using HarmonyLib; using System;
using System; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using UnityEngine;
using UnityExplorer.UI.Panels;
using UniverseLib; using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models; using UniverseLib.UI.Models;
using UniverseLib.Utility; using UniverseLib.Utility;
@ -13,133 +15,217 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
{ {
public bool Enabled public bool Enabled
{ {
get => _enabled; get => enabled;
set set
{ {
_enabled = value; enabled = value;
if (!_enabled) if (!enabled)
{
AutoCompleteModal.Instance.ReleaseOwnership(this); AutoCompleteModal.Instance.ReleaseOwnership(this);
if (getSuggestionsCoroutine != null)
RuntimeHelper.StopCoroutine(getSuggestionsCoroutine);
} }
} }
private bool _enabled = true; }
bool enabled = true;
public event Action<Suggestion> SuggestionClicked; public event Action<Suggestion> SuggestionClicked;
public Type BaseType { get; set; }
public Type[] GenericConstraints { get; set; }
public bool AllTypes { get; set; }
private readonly bool allowAbstract;
private readonly bool allowEnum;
public InputFieldRef InputField { get; } public InputFieldRef InputField { get; }
public bool AnchorToCaretPosition => false; public bool AnchorToCaretPosition => false;
private readonly List<Suggestion> suggestions = new(); readonly bool allowAbstract;
private readonly HashSet<string> suggestedNames = new(); readonly bool allowEnum;
readonly bool allowGeneric;
private HashSet<Type> allowedTypes; public Type BaseType { get; set; }
HashSet<Type> allowedTypes;
string pendingInput;
Coroutine getSuggestionsCoroutine;
readonly Stopwatch cacheTypesStopwatch = new();
private string chosenSuggestion; readonly List<Suggestion> suggestions = new();
readonly HashSet<string> suggestedTypes = new();
string chosenSuggestion;
readonly List<Suggestion> loadingSuggestions = new()
{
new("<color=grey>Loading...</color>", "")
};
bool ISuggestionProvider.AllowNavigation => false; bool ISuggestionProvider.AllowNavigation => false;
public TypeCompleter(Type baseType, InputFieldRef inputField) : this(baseType, inputField, true, true) { } static readonly Dictionary<string, Type> shorthandToType = new()
{
{ "object", typeof(object) },
{ "string", typeof(string) },
{ "bool", typeof(bool) },
{ "byte", typeof(byte) },
{ "sbyte", typeof(sbyte) },
{ "char", typeof(char) },
{ "decimal", typeof(decimal) },
{ "double", typeof(double) },
{ "float", typeof(float) },
{ "int", typeof(int) },
{ "uint", typeof(uint) },
{ "long", typeof(long) },
{ "ulong", typeof(ulong) },
{ "short", typeof(short) },
{ "ushort", typeof(ushort) },
{ "void", typeof(void) },
};
public TypeCompleter(Type baseType, InputFieldRef inputField, bool allowAbstract, bool allowEnum) public TypeCompleter(Type baseType, InputFieldRef inputField) : this(baseType, inputField, true, true, true) { }
public TypeCompleter(Type baseType, InputFieldRef inputField, bool allowAbstract, bool allowEnum, bool allowGeneric)
{ {
BaseType = baseType; BaseType = baseType;
InputField = inputField; InputField = inputField;
this.allowAbstract = allowAbstract; this.allowAbstract = allowAbstract;
this.allowEnum = allowEnum; this.allowEnum = allowEnum;
this.allowGeneric = allowGeneric;
inputField.OnValueChanged += OnInputFieldChanged; inputField.OnValueChanged += OnInputFieldChanged;
if (BaseType != null)
CacheTypes(); CacheTypes();
} }
public void CacheTypes()
{
if (!AllTypes)
allowedTypes = ReflectionUtility.GetImplementationsOf(BaseType, allowAbstract, allowEnum, false);
else
{
allowedTypes = new();
foreach (var entry in ReflectionUtility.AllTypes)
{
// skip <PrivateImplementationDetails> and <AnonymousClass> classes
var type = entry.Value;
if (type.FullName.Contains("PrivateImplementationDetails")
|| type.FullName.Contains("DisplayClass")
|| type.FullName.Contains('<'))
{
continue;
}
allowedTypes.Add(type);
}
}
}
public void OnSuggestionClicked(Suggestion suggestion) public void OnSuggestionClicked(Suggestion suggestion)
{ {
chosenSuggestion = suggestion.UnderlyingValue;
InputField.Text = suggestion.UnderlyingValue; InputField.Text = suggestion.UnderlyingValue;
SuggestionClicked?.Invoke(suggestion); SuggestionClicked?.Invoke(suggestion);
suggestions.Clear(); suggestions.Clear();
AutoCompleteModal.Instance.SetSuggestions(suggestions); //AutoCompleteModal.Instance.SetSuggestions(suggestions, true);
chosenSuggestion = suggestion.UnderlyingValue; AutoCompleteModal.Instance.ReleaseOwnership(this);
} }
private void OnInputFieldChanged(string value) public void CacheTypes()
{
allowedTypes = null;
cacheTypesStopwatch.Reset();
cacheTypesStopwatch.Start();
ReflectionUtility.GetImplementationsOf(BaseType, OnTypesCached, allowAbstract, allowGeneric, allowEnum);
}
void OnTypesCached(HashSet<Type> set)
{
allowedTypes = set;
// ExplorerCore.Log($"Cached {allowedTypes.Count} TypeCompleter types in {cacheTypesStopwatch.ElapsedMilliseconds * 0.001f} seconds.");
if (pendingInput != null)
{
GetSuggestions(pendingInput);
pendingInput = null;
}
}
void OnInputFieldChanged(string input)
{ {
if (!Enabled) if (!Enabled)
return; return;
if (string.IsNullOrEmpty(value) || value == chosenSuggestion) if (input != chosenSuggestion)
{
chosenSuggestion = null; chosenSuggestion = null;
if (string.IsNullOrEmpty(input) || input == chosenSuggestion)
{
if (getSuggestionsCoroutine != null)
RuntimeHelper.StopCoroutine(getSuggestionsCoroutine);
AutoCompleteModal.Instance.ReleaseOwnership(this); AutoCompleteModal.Instance.ReleaseOwnership(this);
} }
else else
{ {
GetSuggestions(value); GetSuggestions(input);
}
}
void GetSuggestions(string input)
{
if (allowedTypes == null)
{
if (pendingInput != null)
{
AutoCompleteModal.TakeOwnership(this); AutoCompleteModal.TakeOwnership(this);
AutoCompleteModal.Instance.SetSuggestions(suggestions); AutoCompleteModal.Instance.SetSuggestions(loadingSuggestions, true);
}
} }
private void GetSuggestions(string value) pendingInput = input;
{
suggestions.Clear();
suggestedNames.Clear();
if (BaseType == null)
{
ExplorerCore.LogWarning("Autocompleter Base type is null!");
return; return;
} }
if (getSuggestionsCoroutine != null)
RuntimeHelper.StopCoroutine(getSuggestionsCoroutine);
getSuggestionsCoroutine = RuntimeHelper.StartCoroutine(GetSuggestionsAsync(input));
}
IEnumerator GetSuggestionsAsync(string input)
{
suggestions.Clear();
suggestedTypes.Clear();
AutoCompleteModal.TakeOwnership(this);
AutoCompleteModal.Instance.SetSuggestions(suggestions, true);
// shorthand types all inherit from System.Object
if (shorthandToType.TryGetValue(input, out Type shorthand) && allowedTypes.Contains(shorthand))
AddSuggestion(shorthand);
foreach (KeyValuePair<string, Type> entry in shorthandToType)
{
if (allowedTypes.Contains(entry.Value) && entry.Key.StartsWith(input, StringComparison.InvariantCultureIgnoreCase))
AddSuggestion(entry.Value);
}
// Check for exact match first // Check for exact match first
if (ReflectionUtility.GetTypeByName(value) is Type t && allowedTypes.Contains(t)) if (ReflectionUtility.GetTypeByName(input) is Type t && allowedTypes.Contains(t))
AddSuggestion(t); AddSuggestion(t);
foreach (var entry in allowedTypes) if (!suggestions.Any())
AutoCompleteModal.Instance.SetSuggestions(loadingSuggestions, false);
else
AutoCompleteModal.Instance.SetSuggestions(suggestions, false);
Stopwatch sw = new();
sw.Start();
// ExplorerCore.Log($"Checking {allowedTypes.Count} types...");
foreach (Type entry in allowedTypes)
{ {
if (entry.FullName.ContainsIgnoreCase(value)) if (AutoCompleteModal.CurrentHandler == null)
yield break;
if (sw.ElapsedMilliseconds > 10)
{
yield return null;
if (suggestions.Any())
AutoCompleteModal.Instance.SetSuggestions(suggestions, false);
sw.Reset();
sw.Start();
}
if (entry.FullName.ContainsIgnoreCase(input))
AddSuggestion(entry); AddSuggestion(entry);
} }
AutoCompleteModal.Instance.SetSuggestions(suggestions, false);
// ExplorerCore.Log($"Fetched {suggestions.Count} TypeCompleter suggestions in {sw.ElapsedMilliseconds * 0.001f} seconds.");
} }
internal static readonly Dictionary<string, string> sharedTypeToLabel = new(); internal static readonly Dictionary<string, string> sharedTypeToLabel = new();
void AddSuggestion(Type type) void AddSuggestion(Type type)
{ {
if (suggestedNames.Contains(type.FullName)) if (suggestedTypes.Contains(type.FullName))
return; return;
suggestedNames.Add(type.FullName); suggestedTypes.Add(type.FullName);
if (!sharedTypeToLabel.ContainsKey(type.FullName)) if (!sharedTypeToLabel.ContainsKey(type.FullName))
sharedTypeToLabel.Add(type.FullName, SignatureHighlighter.Parse(type, true)); sharedTypeToLabel.Add(type.FullName, SignatureHighlighter.Parse(type, true));

View File

@ -1,8 +1,4 @@
using System; using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI; using UniverseLib.UI;
@ -13,8 +9,6 @@ namespace UnityExplorer.UI.Widgets
{ {
public abstract class BaseArgumentHandler : IPooledObject public abstract class BaseArgumentHandler : IPooledObject
{ {
protected EvaluateWidget evaluator;
internal Text argNameLabel; internal Text argNameLabel;
internal InputFieldRef inputField; internal InputFieldRef inputField;
internal TypeCompleter typeCompleter; internal TypeCompleter typeCompleter;
@ -41,8 +35,10 @@ namespace UnityExplorer.UI.Widgets
inputField.Component.lineType = InputField.LineType.MultiLineNewline; inputField.Component.lineType = InputField.LineType.MultiLineNewline;
inputField.UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize; inputField.UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
typeCompleter = new TypeCompleter(typeof(object), this.inputField); typeCompleter = new TypeCompleter(typeof(object), this.inputField)
typeCompleter.Enabled = false; {
Enabled = false
};
CreateSpecialContent(); CreateSpecialContent();

View File

@ -1,16 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib;
using UnityExplorer.CacheObject; using UnityExplorer.CacheObject;
using UniverseLib.UI;
using UniverseLib.UI.Models;
using UniverseLib.UI.ObjectPool; using UniverseLib.UI.ObjectPool;
using UniverseLib.Utility; using UniverseLib.Utility;
@ -48,14 +43,14 @@ namespace UnityExplorer.UI.Widgets
public void OnReturnToPool() public void OnReturnToPool()
{ {
foreach (var widget in paramHandlers) foreach (ParameterHandler widget in paramHandlers)
{ {
widget.OnReturned(); widget.OnReturned();
Pool<ParameterHandler>.Return(widget); Pool<ParameterHandler>.Return(widget);
} }
paramHandlers = null; paramHandlers = null;
foreach (var widget in genericHandlers) foreach (GenericArgumentHandler widget in genericHandlers)
{ {
widget.OnReturned(); widget.OnReturned();
Pool<GenericArgumentHandler>.Return(widget); Pool<GenericArgumentHandler>.Return(widget);
@ -111,11 +106,11 @@ namespace UnityExplorer.UI.Widgets
{ {
for (int i = 0; i < genericArguments.Length; i++) for (int i = 0; i < genericArguments.Length; i++)
{ {
var type = genericArguments[i]; Type type = genericArguments[i];
var holder = genericHandlers[i] = Pool<GenericArgumentHandler>.Borrow(); GenericArgumentHandler holder = genericHandlers[i] = Pool<GenericArgumentHandler>.Borrow();
holder.UIRoot.transform.SetParent(this.genericArgumentsHolder.transform, false); holder.UIRoot.transform.SetParent(this.genericArgumentsHolder.transform, false);
holder.OnBorrowed(this, type); holder.OnBorrowed(type);
} }
} }
@ -123,11 +118,11 @@ namespace UnityExplorer.UI.Widgets
{ {
for (int i = 0; i < parameters.Length; i++) for (int i = 0; i < parameters.Length; i++)
{ {
var param = parameters[i]; ParameterInfo param = parameters[i];
var holder = paramHandlers[i] = Pool<ParameterHandler>.Borrow(); ParameterHandler holder = paramHandlers[i] = Pool<ParameterHandler>.Borrow();
holder.UIRoot.transform.SetParent(this.parametersHolder.transform, false); holder.UIRoot.transform.SetParent(this.parametersHolder.transform, false);
holder.OnBorrowed(this, param); holder.OnBorrowed(param);
} }
} }
@ -142,7 +137,7 @@ namespace UnityExplorer.UI.Widgets
// generic args // generic args
this.genericArgumentsHolder = UIFactory.CreateUIObject("GenericHolder", UIRoot); this.genericArgumentsHolder = UIFactory.CreateUIObject("GenericHolder", UIRoot);
UIFactory.SetLayoutElement(genericArgumentsHolder, flexibleWidth: 1000); UIFactory.SetLayoutElement(genericArgumentsHolder, flexibleWidth: 1000);
var genericsTitle = UIFactory.CreateLabel(genericArgumentsHolder, "GenericsTitle", "Generic Arguments", TextAnchor.MiddleLeft); Text genericsTitle = UIFactory.CreateLabel(genericArgumentsHolder, "GenericsTitle", "Generic Arguments", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(genericsTitle.gameObject, minHeight: 25, flexibleWidth: 1000); UIFactory.SetLayoutElement(genericsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(genericArgumentsHolder, false, false, true, true, 3); UIFactory.SetLayoutGroup<VerticalLayoutGroup>(genericArgumentsHolder, false, false, true, true, 3);
UIFactory.SetLayoutElement(genericArgumentsHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999); UIFactory.SetLayoutElement(genericArgumentsHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
@ -151,14 +146,14 @@ namespace UnityExplorer.UI.Widgets
// args // args
this.parametersHolder = UIFactory.CreateUIObject("ArgHolder", UIRoot); this.parametersHolder = UIFactory.CreateUIObject("ArgHolder", UIRoot);
UIFactory.SetLayoutElement(parametersHolder, flexibleWidth: 1000); UIFactory.SetLayoutElement(parametersHolder, flexibleWidth: 1000);
var argsTitle = UIFactory.CreateLabel(parametersHolder, "ArgsTitle", "Arguments", TextAnchor.MiddleLeft); Text argsTitle = UIFactory.CreateLabel(parametersHolder, "ArgsTitle", "Arguments", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(argsTitle.gameObject, minHeight: 25, flexibleWidth: 1000); UIFactory.SetLayoutElement(argsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(parametersHolder, false, false, true, true, 3); UIFactory.SetLayoutGroup<VerticalLayoutGroup>(parametersHolder, false, false, true, true, 3);
UIFactory.SetLayoutElement(parametersHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999); UIFactory.SetLayoutElement(parametersHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
//argHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize; //argHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// evaluate button // evaluate button
var evalButton = UIFactory.CreateButton(UIRoot, "EvaluateButton", "Evaluate", new Color(0.2f, 0.2f, 0.2f)); ButtonRef evalButton = UIFactory.CreateButton(UIRoot, "EvaluateButton", "Evaluate", new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(evalButton.Component.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0); UIFactory.SetLayoutElement(evalButton.Component.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0);
evalButton.OnClick += () => evalButton.OnClick += () =>
{ {

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