mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-03 03:52:28 +08:00
Compare commits
25 Commits
Author | SHA1 | Date | |
---|---|---|---|
d1fbbfa62d | |||
56a3cef245 | |||
61e7915a55 | |||
88e63c8d6a | |||
048e5980a0 | |||
3b851b6e08 | |||
4c029dad90 | |||
3d61011e59 | |||
5285239bc5 | |||
57d3a3f52e | |||
c88182c831 | |||
02e0102041 | |||
6adecef785 | |||
ff6c03e1f3 | |||
1aedc505b2 | |||
dbe993a7c7 | |||
5a1676fb84 | |||
a7a663aefa | |||
76c77fb082 | |||
a25017df69 | |||
a1fab0c4a7 | |||
4599747bfe | |||
3856e84c08 | |||
104288a912 | |||
41e8a5ae33 |
25
README.md
25
README.md
@ -38,10 +38,10 @@ Nightly builds can be found [here](https://github.com/sinai-dev/UnityExplorer/ac
|
|||||||
|
|
||||||
## 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
|
||||||
2. Copy the DLL inside the `Mods` folder into your MelonLoader `Mods` folder
|
2. Copy the DLL inside the `Mods` folder into your MelonLoader `Mods` folder
|
||||||
@ -90,6 +90,20 @@ If these fixes do not work, please create an issue in this repo and I'll do my b
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
### Inspector API
|
||||||
|
|
||||||
|
If you want to inspect an object or Type from outside the C# console, use the `InspectorManager` class:
|
||||||
|
|
||||||
|
**To inspect an object:**
|
||||||
|
```csharp
|
||||||
|
UnityExplorer.InspectorManager.Inspect(theObject);
|
||||||
|
```
|
||||||
|
|
||||||
|
**To inspect a Type:**
|
||||||
|
```cs
|
||||||
|
UnityExplorer.InspectorManager.Inspect(typeof(SomeClass));
|
||||||
|
```
|
||||||
|
|
||||||
### Object Explorer
|
### Object Explorer
|
||||||
|
|
||||||
* Use the <b>Scene Explorer</b> tab to traverse the active scenes, as well as the DontDestroyOnLoad and HideAndDontSave objects.
|
* Use the <b>Scene Explorer</b> tab to traverse the active scenes, as well as the DontDestroyOnLoad and HideAndDontSave objects.
|
||||||
@ -110,7 +124,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
|
||||||
|
|
||||||
|
Binary file not shown.
Binary file not shown.
161
build.ps1
161
build.ps1
@ -1,125 +1,134 @@
|
|||||||
# ----------- 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
|
||||||
$Path = "Release\UnityExplorer.MelonLoader.IL2CPP.net6preview"
|
$Path = "Release\UnityExplorer.MelonLoader.IL2CPP.net6preview"
|
||||||
# ILRepack
|
# 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
|
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)
|
# (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/mcs.dll
|
||||||
Remove-Item $Path\Iced.dll
|
Remove-Item $Path/Iced.dll
|
||||||
Remove-Item $Path\UnhollowerBaseLib.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\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
|
Remove-Item $Path/../UnityExplorer.MelonLoader.IL2CPP.net6preview.zip -ErrorAction SilentlyContinue
|
||||||
|
7z a $Path/../UnityExplorer.MelonLoader.IL2CPP.net6preview.zip .\$Path\*
|
||||||
|
|
||||||
# ----------- 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
|
||||||
$Path = "Release\UnityExplorer.MelonLoader.IL2CPP"
|
$Path = "Release/UnityExplorer.MelonLoader.IL2CPP"
|
||||||
# ILRepack
|
# 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
|
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)
|
# (cleanup and move files)
|
||||||
Remove-Item $Path\Tomlet.dll
|
Remove-Item $Path/Tomlet.dll
|
||||||
Remove-Item $Path\mcs.dll
|
Remove-Item $Path/mcs.dll
|
||||||
Remove-Item $Path\Iced.dll
|
Remove-Item $Path/Iced.dll
|
||||||
Remove-Item $Path\UnhollowerBaseLib.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\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
|
Remove-Item $Path/../UnityExplorer.MelonLoader.IL2CPP.zip -ErrorAction SilentlyContinue
|
||||||
|
7z a $Path/../UnityExplorer.MelonLoader.IL2CPP.zip .\$Path\*
|
||||||
|
|
||||||
# ----------- MelonLoader Mono -----------
|
# ----------- MelonLoader Mono -----------
|
||||||
dotnet build src\UnityExplorer.sln -c Release_ML_Mono
|
dotnet build src/UnityExplorer.sln -c Release_ML_Mono
|
||||||
$Path = "Release\UnityExplorer.MelonLoader.Mono"
|
$Path = "Release/UnityExplorer.MelonLoader.Mono"
|
||||||
# ILRepack
|
# 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
|
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)
|
# (cleanup and move files)
|
||||||
Remove-Item $Path\Tomlet.dll
|
Remove-Item $Path/Tomlet.dll
|
||||||
Remove-Item $Path\mcs.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\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
|
Remove-Item $Path/../UnityExplorer.MelonLoader.Mono.zip -ErrorAction SilentlyContinue
|
||||||
|
7z a $Path/../UnityExplorer.MelonLoader.Mono.zip .\$Path\*
|
||||||
|
|
||||||
# ----------- BepInEx IL2CPP -----------
|
# ----------- BepInEx IL2CPP -----------
|
||||||
dotnet build src\UnityExplorer.sln -c Release_BIE_Cpp
|
dotnet build src/UnityExplorer.sln -c Release_BIE_Cpp
|
||||||
$Path = "Release\UnityExplorer.BepInEx.IL2CPP"
|
$Path = "Release/UnityExplorer.BepInEx.IL2CPP"
|
||||||
# ILRepack
|
# 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
|
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)
|
# (cleanup and move files)
|
||||||
Remove-Item $Path\Tomlet.dll
|
Remove-Item $Path/Tomlet.dll
|
||||||
Remove-Item $Path\mcs.dll
|
Remove-Item $Path/mcs.dll
|
||||||
Remove-Item $Path\Iced.dll
|
Remove-Item $Path/Iced.dll
|
||||||
Remove-Item $Path\UnhollowerBaseLib.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\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
|
Remove-Item $Path/../UnityExplorer.BepInEx.IL2CPP.zip -ErrorAction SilentlyContinue
|
||||||
|
7z a $Path/../UnityExplorer.BepInEx.IL2CPP.zip .\$Path\*
|
||||||
|
|
||||||
# ----------- BepInEx 5 Mono -----------
|
# ----------- BepInEx 5 Mono -----------
|
||||||
dotnet build src\UnityExplorer.sln -c Release_BIE5_Mono
|
dotnet build src/UnityExplorer.sln -c Release_BIE5_Mono
|
||||||
$Path = "Release\UnityExplorer.BepInEx5.Mono"
|
$Path = "Release/UnityExplorer.BepInEx5.Mono"
|
||||||
# ILRepack
|
# 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
|
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)
|
# (cleanup and move files)
|
||||||
Remove-Item $Path\Tomlet.dll
|
Remove-Item $Path/Tomlet.dll
|
||||||
Remove-Item $Path\mcs.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\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
|
Remove-Item $Path/../UnityExplorer.BepInEx5.Mono.zip -ErrorAction SilentlyContinue
|
||||||
|
7z a $Path/../UnityExplorer.BepInEx5.Mono.zip .\$Path\*
|
||||||
|
|
||||||
# ----------- BepInEx 6 Mono -----------
|
# ----------- BepInEx 6 Mono -----------
|
||||||
dotnet build src\UnityExplorer.sln -c Release_BIE6_Mono
|
dotnet build src/UnityExplorer.sln -c Release_BIE6_Mono
|
||||||
$Path = "Release\UnityExplorer.BepInEx6.Mono"
|
$Path = "Release/UnityExplorer.BepInEx6.Mono"
|
||||||
# ILRepack
|
# 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
|
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)
|
# (cleanup and move files)
|
||||||
Remove-Item $Path\Tomlet.dll
|
Remove-Item $Path/Tomlet.dll
|
||||||
Remove-Item $Path\mcs.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\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
|
Remove-Item $Path/../UnityExplorer.BepInEx6.Mono.zip -ErrorAction SilentlyContinue
|
||||||
|
7z a $Path/../UnityExplorer.BepInEx6.Mono.zip .\$Path\*
|
||||||
|
|
||||||
# ----------- 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
|
# 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
|
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)
|
# (cleanup and move files)
|
||||||
Remove-Item $Path\Tomlet.dll
|
Remove-Item $Path/Tomlet.dll
|
||||||
Remove-Item $Path\mcs.dll
|
Remove-Item $Path/mcs.dll
|
||||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.Standalone.Mono.zip -Force
|
Remove-Item $Path/../UnityExplorer.Standalone.Mono.zip -ErrorAction SilentlyContinue
|
||||||
|
7z a $Path/../UnityExplorer.Standalone.Mono.zip .\$Path\*
|
||||||
|
|
||||||
# ----------- 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
|
# 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
|
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)
|
# (cleanup and move files)
|
||||||
Remove-Item $Path\Tomlet.dll
|
Remove-Item $Path/Tomlet.dll
|
||||||
Remove-Item $Path\mcs.dll
|
Remove-Item $Path/mcs.dll
|
||||||
Remove-Item $Path\Iced.dll
|
Remove-Item $Path/Iced.dll
|
||||||
Remove-Item $Path\UnhollowerBaseLib.dll
|
Remove-Item $Path/UnhollowerBaseLib.dll
|
||||||
Compress-Archive -Path $Path\* -CompressionLevel Fastest -DestinationPath $Path\..\UnityExplorer.Standalone.IL2CPP.zip -Force
|
Remove-Item $Path/../UnityExplorer.Standalone.IL2CPP.zip -ErrorAction SilentlyContinue
|
||||||
|
7z a $Path/../UnityExplorer.Standalone.IL2CPP.zip .\$Path\*
|
||||||
|
|
||||||
# ----------- 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\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
|
Remove-Item Release/UnityExplorer.Editor.zip -ErrorAction SilentlyContinue
|
||||||
|
7z a Release/UnityExplorer.Editor.zip .\UnityEditorPackage\*
|
@ -56,6 +56,7 @@ namespace UnityExplorer.CSConsole
|
|||||||
"System.Text",
|
"System.Text",
|
||||||
"System.Collections",
|
"System.Collections",
|
||||||
"System.Collections.Generic",
|
"System.Collections.Generic",
|
||||||
|
"System.Reflection",
|
||||||
"UnityEngine",
|
"UnityEngine",
|
||||||
"UniverseLib",
|
"UniverseLib",
|
||||||
#if CPP
|
#if CPP
|
||||||
|
@ -3,6 +3,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using UnityExplorer.Config;
|
||||||
|
|
||||||
// Thanks to ManlyMarco for this
|
// Thanks to ManlyMarco for this
|
||||||
|
|
||||||
@ -10,6 +11,9 @@ namespace UnityExplorer.CSConsole
|
|||||||
{
|
{
|
||||||
public class ScriptEvaluator : Evaluator, IDisposable
|
public class ScriptEvaluator : Evaluator, IDisposable
|
||||||
{
|
{
|
||||||
|
internal TextWriter _textWriter;
|
||||||
|
internal static StreamReportPrinter _reportPrinter;
|
||||||
|
|
||||||
private static readonly HashSet<string> StdLib = new(StringComparer.InvariantCultureIgnoreCase)
|
private static readonly HashSet<string> StdLib = new(StringComparer.InvariantCultureIgnoreCase)
|
||||||
{
|
{
|
||||||
"mscorlib",
|
"mscorlib",
|
||||||
@ -18,9 +22,6 @@ namespace UnityExplorer.CSConsole
|
|||||||
"System.Xml"
|
"System.Xml"
|
||||||
};
|
};
|
||||||
|
|
||||||
internal TextWriter _textWriter;
|
|
||||||
internal static StreamReportPrinter _reportPrinter;
|
|
||||||
|
|
||||||
public ScriptEvaluator(TextWriter tw) : base(BuildContext(tw))
|
public ScriptEvaluator(TextWriter tw) : base(BuildContext(tw))
|
||||||
{
|
{
|
||||||
_textWriter = tw;
|
_textWriter = tw;
|
||||||
@ -48,8 +49,19 @@ namespace UnityExplorer.CSConsole
|
|||||||
private void Reference(Assembly asm)
|
private void Reference(Assembly asm)
|
||||||
{
|
{
|
||||||
string name = asm.GetName().Name;
|
string name = asm.GetName().Name;
|
||||||
if (name == "completions")
|
|
||||||
|
if (name == "completions") // ignore assemblies generated by mcs' autocomplete.
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
foreach (string blacklisted in ConfigManager.CSConsole_Assembly_Blacklist.Value.Split(';'))
|
||||||
|
{
|
||||||
|
string bl = blacklisted;
|
||||||
|
if (bl.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
||||||
|
bl = blacklisted.Substring(0, bl.Length - 4);
|
||||||
|
if (string.Equals(bl, name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ReferenceAssembly(asm);
|
ReferenceAssembly(asm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,19 +16,20 @@ 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<string> Reflection_Signature_Blacklist;
|
public static ConfigElement<bool> Disable_EventSystem_Override;
|
||||||
|
public static ConfigElement<int> Target_Display;
|
||||||
|
public static ConfigElement<bool> Force_Unlock_Mouse;
|
||||||
|
public static ConfigElement<KeyCode> Force_Unlock_Toggle;
|
||||||
|
public static ConfigElement<string> Default_Output_Path;
|
||||||
|
public static ConfigElement<string> DnSpy_Path;
|
||||||
|
public static ConfigElement<bool> Log_Unity_Debug;
|
||||||
|
public static ConfigElement<UIManager.VerticalAnchor> Main_Navbar_Anchor;
|
||||||
public static ConfigElement<KeyCode> World_MouseInspect_Keybind;
|
public static ConfigElement<KeyCode> World_MouseInspect_Keybind;
|
||||||
public static ConfigElement<KeyCode> UI_MouseInspect_Keybind;
|
public static ConfigElement<KeyCode> UI_MouseInspect_Keybind;
|
||||||
|
public static ConfigElement<string> CSConsole_Assembly_Blacklist;
|
||||||
|
public static ConfigElement<string> Reflection_Signature_Blacklist;
|
||||||
|
|
||||||
// internal configs
|
// internal configs
|
||||||
internal static InternalConfigHandler InternalHandler { get; private set; }
|
internal static InternalConfigHandler InternalHandler { get; private set; }
|
||||||
@ -57,8 +58,6 @@ namespace UnityExplorer.Config
|
|||||||
#if STANDALONE
|
#if STANDALONE
|
||||||
Loader.Standalone.ExplorerEditorBehaviour.Instance?.LoadConfigs();
|
Loader.Standalone.ExplorerEditorBehaviour.Instance?.LoadConfigs();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//InitConsoleCallback();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void RegisterConfigElement<T>(ConfigElement<T> configElement)
|
internal static void RegisterConfigElement<T>(ConfigElement<T> configElement)
|
||||||
@ -77,23 +76,53 @@ namespace UnityExplorer.Config
|
|||||||
|
|
||||||
private static void CreateConfigElements()
|
private static void CreateConfigElements()
|
||||||
{
|
{
|
||||||
Master_Toggle = new ConfigElement<KeyCode>("UnityExplorer Toggle",
|
Master_Toggle = new("UnityExplorer Toggle",
|
||||||
"The key to enable or disable UnityExplorer's menu and features.",
|
"The key to enable or disable UnityExplorer's menu and features.",
|
||||||
KeyCode.F7);
|
KeyCode.F7);
|
||||||
|
|
||||||
Hide_On_Startup = new ConfigElement<bool>("Hide On Startup",
|
Hide_On_Startup = new("Hide On Startup",
|
||||||
"Should UnityExplorer be hidden on startup?",
|
"Should UnityExplorer be hidden on startup?",
|
||||||
false);
|
false);
|
||||||
|
|
||||||
Target_Display = new ConfigElement<int>("Target Display",
|
Startup_Delay_Time = new("Startup Delay Time",
|
||||||
|
"The delay on startup before the UI is created.",
|
||||||
|
1f);
|
||||||
|
|
||||||
|
Target_Display = new("Target Display",
|
||||||
"The monitor index for UnityExplorer to use, if you have multiple. 0 is the default display, 1 is secondary, etc. " +
|
"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.",
|
"Restart recommended when changing this setting. Make sure your extra monitors are the same resolution as your primary monitor.",
|
||||||
0);
|
0);
|
||||||
|
|
||||||
Main_Navbar_Anchor = new ConfigElement<UIManager.VerticalAnchor>("Main Navbar Anchor",
|
Force_Unlock_Mouse = new("Force Unlock Mouse",
|
||||||
|
"Force the Cursor to be unlocked (visible) when the UnityExplorer menu is open.",
|
||||||
|
true);
|
||||||
|
Force_Unlock_Mouse.OnValueChanged += (bool value) => UniverseLib.Config.ConfigManager.Force_Unlock_Mouse = value;
|
||||||
|
|
||||||
|
Force_Unlock_Toggle = new("Force Unlock Toggle Key",
|
||||||
|
"The keybind to toggle the 'Force Unlock Mouse' setting. Only usable when UnityExplorer is open.",
|
||||||
|
KeyCode.None);
|
||||||
|
|
||||||
|
Disable_EventSystem_Override = new("Disable EventSystem override",
|
||||||
|
"If enabled, UnityExplorer will not override the EventSystem from the game.\n<b>May require restart to take effect.</b>",
|
||||||
|
false);
|
||||||
|
Disable_EventSystem_Override.OnValueChanged += (bool value) => UniverseLib.Config.ConfigManager.Disable_EventSystem_Override = value;
|
||||||
|
|
||||||
|
Default_Output_Path = new("Default Output Path",
|
||||||
|
"The default output path when exporting things from UnityExplorer.",
|
||||||
|
Path.Combine(ExplorerCore.ExplorerFolder, "Output"));
|
||||||
|
|
||||||
|
DnSpy_Path = new("dnSpy Path",
|
||||||
|
"The full path to dnSpy.exe (64-bit).",
|
||||||
|
@"C:/Program Files/dnspy/dnSpy.exe");
|
||||||
|
|
||||||
|
Main_Navbar_Anchor = new("Main Navbar Anchor",
|
||||||
"The vertical anchor of the main UnityExplorer Navbar, in case you want to move it.",
|
"The vertical anchor of the main UnityExplorer Navbar, in case you want to move it.",
|
||||||
UIManager.VerticalAnchor.Top);
|
UIManager.VerticalAnchor.Top);
|
||||||
|
|
||||||
|
Log_Unity_Debug = new("Log Unity Debug",
|
||||||
|
"Should UnityEngine.Debug.Log messages be printed to UnityExplorer's log?",
|
||||||
|
false);
|
||||||
|
|
||||||
World_MouseInspect_Keybind = new("World Mouse-Inspect Keybind",
|
World_MouseInspect_Keybind = new("World Mouse-Inspect Keybind",
|
||||||
"Optional keybind to being a World-mode Mouse Inspect.",
|
"Optional keybind to being a World-mode Mouse Inspect.",
|
||||||
KeyCode.None);
|
KeyCode.None);
|
||||||
@ -102,33 +131,13 @@ namespace UnityExplorer.Config
|
|||||||
"Optional keybind to begin a UI-mode Mouse Inspect.",
|
"Optional keybind to begin a UI-mode Mouse Inspect.",
|
||||||
KeyCode.None);
|
KeyCode.None);
|
||||||
|
|
||||||
Force_Unlock_Mouse = new ConfigElement<bool>("Force Unlock Mouse",
|
CSConsole_Assembly_Blacklist = new("CSharp Console Assembly Blacklist",
|
||||||
"Force the Cursor to be unlocked (visible) when the UnityExplorer menu is open.",
|
"Use this to blacklist Assembly names from being referenced by the C# Console. Requires a Reset of the C# Console.\n" +
|
||||||
true);
|
"Separate each Assembly with a semicolon ';'." +
|
||||||
Force_Unlock_Mouse.OnValueChanged += (bool value) => UniverseLib.Config.ConfigManager.Force_Unlock_Mouse = value;
|
"For example, to blacklist Assembly-CSharp, you would add 'Assembly-CSharp;'",
|
||||||
|
"");
|
||||||
|
|
||||||
Force_Unlock_Toggle = new ConfigElement<KeyCode>("Force Unlock Toggle Key",
|
Reflection_Signature_Blacklist = new("Member Signature Blacklist",
|
||||||
"The keybind to toggle the 'Force Unlock Mouse' setting. Only usable when UnityExplorer is open.",
|
|
||||||
KeyCode.None);
|
|
||||||
|
|
||||||
Disable_EventSystem_Override = new ConfigElement<bool>("Disable EventSystem override",
|
|
||||||
"If enabled, UnityExplorer will not override the EventSystem from the game.\n<b>May require restart to take effect.</b>",
|
|
||||||
false);
|
|
||||||
Disable_EventSystem_Override.OnValueChanged += (bool value) => UniverseLib.Config.ConfigManager.Disable_EventSystem_Override = value;
|
|
||||||
|
|
||||||
Log_Unity_Debug = new ConfigElement<bool>("Log Unity Debug",
|
|
||||||
"Should UnityEngine.Debug.Log messages be printed to UnityExplorer's log?",
|
|
||||||
false);
|
|
||||||
|
|
||||||
Default_Output_Path = new ConfigElement<string>("Default Output Path",
|
|
||||||
"The default output path when exporting things from UnityExplorer.",
|
|
||||||
Path.Combine(ExplorerCore.ExplorerFolder, "Output"));
|
|
||||||
|
|
||||||
Startup_Delay_Time = new ConfigElement<float>("Startup Delay Time",
|
|
||||||
"The delay on startup before the UI is created.",
|
|
||||||
1f);
|
|
||||||
|
|
||||||
Reflection_Signature_Blacklist = new ConfigElement<string>("Member Signature Blacklist",
|
|
||||||
"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" +
|
||||||
"Seperate signatures with a semicolon ';'.\r\n" +
|
"Seperate signatures with a semicolon ';'.\r\n" +
|
||||||
"For example, to blacklist Camera.main, you would add 'UnityEngine.Camera.main;'",
|
"For example, to blacklist Camera.main, you would add 'UnityEngine.Camera.main;'",
|
||||||
|
@ -14,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.12";
|
public const string VERSION = "4.8.1";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
public const string GUID = "com.sinai.unityexplorer";
|
public const string GUID = "com.sinai.unityexplorer";
|
||||||
|
|
||||||
|
@ -158,11 +158,8 @@ namespace UnityExplorer.Hooks
|
|||||||
}
|
}
|
||||||
|
|
||||||
HookInstance hook = new(method);
|
HookInstance hook = new(method);
|
||||||
if (hook.Enabled)
|
HookList.hookedSignatures.Add(sig);
|
||||||
{
|
HookList.currentHooks.Add(sig, hook);
|
||||||
HookList.hookedSignatures.Add(sig);
|
|
||||||
HookList.currentHooks.Add(sig, hook);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddHooksScrollPool.Refresh(true, false);
|
AddHooksScrollPool.Refresh(true, false);
|
||||||
HookList.HooksScrollPool.Refresh(true, false);
|
HookList.HooksScrollPool.Refresh(true, false);
|
||||||
@ -239,6 +236,8 @@ namespace UnityExplorer.Hooks
|
|||||||
CurrentEditedHook = null;
|
CurrentEditedHook = null;
|
||||||
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
HookManagerPanel.Instance.SetPage(HookManagerPanel.Pages.ClassMethodSelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HookList.HooksScrollPool.Refresh(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI Construction
|
// UI Construction
|
||||||
|
@ -15,7 +15,6 @@ namespace UnityExplorer.Hooks
|
|||||||
{
|
{
|
||||||
// Static
|
// Static
|
||||||
|
|
||||||
//static readonly StringBuilder evalOutput = new();
|
|
||||||
static readonly StringBuilder evaluatorOutput;
|
static readonly StringBuilder evaluatorOutput;
|
||||||
static readonly ScriptEvaluator scriptEvaluator = new(new StringWriter(evaluatorOutput = new StringBuilder()));
|
static readonly ScriptEvaluator scriptEvaluator = new(new StringWriter(evaluatorOutput = new StringBuilder()));
|
||||||
|
|
||||||
@ -31,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.FullDescription();
|
this.signature = TargetMethod.FullDescription();
|
||||||
|
|
||||||
GenerateDefaultPatchSourceCode(targetMethod);
|
GenerateDefaultPatchSourceCode(targetMethod);
|
||||||
|
|
||||||
@ -144,28 +144,29 @@ namespace UnityExplorer.Hooks
|
|||||||
{
|
{
|
||||||
StringBuilder codeBuilder = new();
|
StringBuilder codeBuilder = new();
|
||||||
|
|
||||||
codeBuilder.Append("static void Postfix("); // System.Reflection.MethodBase __originalMethod
|
codeBuilder.Append("static void Postfix(");
|
||||||
|
|
||||||
bool isStatic = targetMethod.IsStatic;
|
bool isStatic = targetMethod.IsStatic;
|
||||||
|
|
||||||
|
List<string> arguments = new();
|
||||||
|
|
||||||
if (!isStatic)
|
if (!isStatic)
|
||||||
codeBuilder.Append($"{FullDescriptionClean(targetMethod.DeclaringType)} __instance");
|
arguments.Add($"{FullDescriptionClean(targetMethod.DeclaringType)} __instance");
|
||||||
|
|
||||||
if (targetMethod.ReturnType != typeof(void))
|
if (targetMethod.ReturnType != typeof(void))
|
||||||
{
|
arguments.Add($"{FullDescriptionClean(targetMethod.ReturnType)} __result");
|
||||||
if (!isStatic)
|
|
||||||
codeBuilder.Append(", ");
|
|
||||||
codeBuilder.Append($"{FullDescriptionClean(targetMethod.ReturnType)} __result");
|
|
||||||
}
|
|
||||||
|
|
||||||
ParameterInfo[] parameters = targetMethod.GetParameters();
|
ParameterInfo[] parameters = targetMethod.GetParameters();
|
||||||
|
|
||||||
int paramIdx = 0;
|
int paramIdx = 0;
|
||||||
foreach (ParameterInfo param in parameters)
|
foreach (ParameterInfo param in parameters)
|
||||||
{
|
{
|
||||||
codeBuilder.Append($", {FullDescriptionClean(param.ParameterType)} __{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
|
||||||
@ -173,8 +174,8 @@ namespace UnityExplorer.Hooks
|
|||||||
codeBuilder.AppendLine("{");
|
codeBuilder.AppendLine("{");
|
||||||
codeBuilder.AppendLine(" try {");
|
codeBuilder.AppendLine(" try {");
|
||||||
codeBuilder.AppendLine(" StringBuilder sb = new StringBuilder();");
|
codeBuilder.AppendLine(" StringBuilder sb = new StringBuilder();");
|
||||||
codeBuilder.AppendLine($" sb.AppendLine(\"---- Patched called ----\");");
|
codeBuilder.AppendLine($" sb.AppendLine(\"--------------------\");");
|
||||||
codeBuilder.AppendLine($" sb.AppendLine(\"{shortSignature}\");");
|
codeBuilder.AppendLine($" sb.AppendLine(\"{signature}\");");
|
||||||
|
|
||||||
if (!targetMethod.IsStatic)
|
if (!targetMethod.IsStatic)
|
||||||
codeBuilder.AppendLine($" sb.Append(\"- __instance: \").AppendLine(__instance.ToString());");
|
codeBuilder.AppendLine($" sb.Append(\"- __instance: \").AppendLine(__instance.ToString());");
|
||||||
@ -206,15 +207,11 @@ namespace UnityExplorer.Hooks
|
|||||||
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.Log(sb.ToString());");
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,17 +113,11 @@ namespace UnityExplorer.Inspectors
|
|||||||
|
|
||||||
public bool TryUpdate()
|
public bool TryUpdate()
|
||||||
{
|
{
|
||||||
if (ConfigManager.World_MouseInspect_Keybind.Value != KeyCode.None)
|
if (InputManager.GetKeyDown(ConfigManager.World_MouseInspect_Keybind.Value))
|
||||||
{
|
Instance.StartInspect(MouseInspectMode.World);
|
||||||
if (InputManager.GetKeyDown(ConfigManager.World_MouseInspect_Keybind.Value))
|
|
||||||
Instance.StartInspect(MouseInspectMode.World);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ConfigManager.World_MouseInspect_Keybind.Value != KeyCode.None)
|
if (InputManager.GetKeyDown(ConfigManager.UI_MouseInspect_Keybind.Value))
|
||||||
{
|
Instance.StartInspect(MouseInspectMode.UI);
|
||||||
if (InputManager.GetKeyDown(ConfigManager.World_MouseInspect_Keybind.Value))
|
|
||||||
Instance.StartInspect(MouseInspectMode.World);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Inspecting)
|
if (Inspecting)
|
||||||
UpdateInspect();
|
UpdateInspect();
|
||||||
|
@ -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,7 +36,6 @@ 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;
|
||||||
|
|
||||||
@ -73,6 +75,8 @@ namespace UnityExplorer.Inspectors
|
|||||||
Text assemblyText;
|
Text assemblyText;
|
||||||
Toggle autoUpdateToggle;
|
Toggle autoUpdateToggle;
|
||||||
|
|
||||||
|
ButtonRef dnSpyButton;
|
||||||
|
|
||||||
ButtonRef makeGenericButton;
|
ButtonRef makeGenericButton;
|
||||||
GenericConstructorWidget genericConstructor;
|
GenericConstructorWidget genericConstructor;
|
||||||
|
|
||||||
@ -155,9 +159,15 @@ namespace UnityExplorer.Inspectors
|
|||||||
|
|
||||||
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);
|
||||||
|
dnSpyButton.GameObject.SetActive(true);
|
||||||
|
}
|
||||||
assemblyText.text = $"<color=grey>Assembly:</color> {asmText}";
|
assemblyText.text = $"<color=grey>Assembly:</color> {asmText}";
|
||||||
|
|
||||||
// Unity object helper widget
|
// Unity object helper widget
|
||||||
@ -350,6 +360,25 @@ namespace UnityExplorer.Inspectors
|
|||||||
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()
|
void OnMakeGenericClicked()
|
||||||
{
|
{
|
||||||
ContentRoot.SetActive(false);
|
ContentRoot.SetActive(false);
|
||||||
@ -425,10 +454,21 @@ namespace UnityExplorer.Inspectors
|
|||||||
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
|
||||||
|
|
||||||
|
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);
|
UIFactory.SetLayoutElement(assemblyText.gameObject, minHeight: 25, flexibleWidth: 9999);
|
||||||
|
|
||||||
ContentRoot = UIFactory.CreateVerticalGroup(UIRoot, "MemberHolder", false, false, true, true, 5, new Vector4(2, 2, 2, 2),
|
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(ContentRoot, flexibleWidth: 9999, flexibleHeight: 9999);
|
UIFactory.SetLayoutElement(ContentRoot, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||||
|
|
||||||
|
@ -39,7 +39,6 @@ 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>();
|
||||||
|
@ -171,6 +171,9 @@ namespace UnityExplorer.UI.Panels
|
|||||||
if (!ourCamera)
|
if (!ourCamera)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (positionInput.Component.isFocused)
|
||||||
|
return;
|
||||||
|
|
||||||
lastSetCameraPosition = ourCamera.transform.position;
|
lastSetCameraPosition = ourCamera.transform.position;
|
||||||
positionInput.Text = ParseUtility.ToStringForInput<Vector3>(lastSetCameraPosition);
|
positionInput.Text = ParseUtility.ToStringForInput<Vector3>(lastSetCameraPosition);
|
||||||
}
|
}
|
||||||
|
@ -71,6 +71,17 @@ namespace UnityExplorer.UI.Panels
|
|||||||
|
|
||||||
// Save Data
|
// Save Data
|
||||||
|
|
||||||
|
bool setDefault = false;
|
||||||
|
|
||||||
|
public override void SetDefaultSizeAndPosition()
|
||||||
|
{
|
||||||
|
if (setDefault)
|
||||||
|
return;
|
||||||
|
setDefault = true;
|
||||||
|
|
||||||
|
base.SetDefaultSizeAndPosition();
|
||||||
|
}
|
||||||
|
|
||||||
public bool ApplyingSaveData { get; set; }
|
public bool ApplyingSaveData { get; set; }
|
||||||
|
|
||||||
public void SaveInternalData()
|
public void SaveInternalData()
|
||||||
|
@ -5,6 +5,7 @@ using UnityExplorer.Config;
|
|||||||
using UnityExplorer.CSConsole;
|
using UnityExplorer.CSConsole;
|
||||||
using UnityExplorer.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
using UnityExplorer.UI.Panels;
|
using UnityExplorer.UI.Panels;
|
||||||
|
using UnityExplorer.UI.Widgets;
|
||||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||||
using UniverseLib;
|
using UniverseLib;
|
||||||
using UniverseLib.Input;
|
using UniverseLib.Input;
|
||||||
@ -54,10 +55,7 @@ namespace UnityExplorer.UI
|
|||||||
private static readonly Vector2 NAVBAR_DIMENSIONS = new(1020f, 35f);
|
private static readonly Vector2 NAVBAR_DIMENSIONS = new(1020f, 35f);
|
||||||
|
|
||||||
private static ButtonRef closeBtn;
|
private static ButtonRef closeBtn;
|
||||||
private static ButtonRef pauseBtn;
|
private static TimeScaleWidget timeScaleWidget;
|
||||||
private static InputFieldRef timeInput;
|
|
||||||
private static bool pauseButtonPausing;
|
|
||||||
private static float lastTimeScale;
|
|
||||||
|
|
||||||
private static int lastScreenWidth;
|
private static int lastScreenWidth;
|
||||||
private static int lastScreenHeight;
|
private static int lastScreenHeight;
|
||||||
@ -141,20 +139,7 @@ namespace UnityExplorer.UI
|
|||||||
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 the timescale value
|
// update the timescale value
|
||||||
if (!timeInput.Component.isFocused && lastTimeScale != Time.timeScale)
|
timeScaleWidget.Update();
|
||||||
{
|
|
||||||
if (pauseButtonPausing && Time.timeScale != 0.0f)
|
|
||||||
{
|
|
||||||
pauseButtonPausing = false;
|
|
||||||
OnPauseButtonToggled();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pauseButtonPausing)
|
|
||||||
{
|
|
||||||
timeInput.Text = Time.timeScale.ToString("F2");
|
|
||||||
lastTimeScale = Time.timeScale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check screen dimension change
|
// check screen dimension change
|
||||||
Display display = DisplayManager.ActiveDisplay;
|
Display display = DisplayManager.ActiveDisplay;
|
||||||
@ -232,41 +217,7 @@ namespace UnityExplorer.UI
|
|||||||
closeBtn.ButtonText.text = val.ToString();
|
closeBtn.ButtonText.text = val.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time controls
|
|
||||||
|
|
||||||
private static void OnTimeInputEndEdit(string val)
|
|
||||||
{
|
|
||||||
if (pauseButtonPausing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (float.TryParse(val, out float f))
|
|
||||||
{
|
|
||||||
Time.timeScale = f;
|
|
||||||
lastTimeScale = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
timeInput.Text = Time.timeScale.ToString("F2");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnPauseButtonClicked()
|
|
||||||
{
|
|
||||||
pauseButtonPausing = !pauseButtonPausing;
|
|
||||||
|
|
||||||
Time.timeScale = pauseButtonPausing ? 0f : lastTimeScale;
|
|
||||||
|
|
||||||
OnPauseButtonToggled();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnPauseButtonToggled()
|
|
||||||
{
|
|
||||||
timeInput.Component.text = Time.timeScale.ToString("F2");
|
|
||||||
timeInput.Component.readOnly = pauseButtonPausing;
|
|
||||||
timeInput.Component.textComponent.color = pauseButtonPausing ? Color.grey : Color.white;
|
|
||||||
|
|
||||||
Color color = pauseButtonPausing ? new Color(0.3f, 0.3f, 0.2f) : new Color(0.2f, 0.2f, 0.2f);
|
|
||||||
RuntimeHelper.SetColorBlock(pauseBtn.Component, color, color * 1.2f, color * 0.7f);
|
|
||||||
pauseBtn.ButtonText.text = pauseButtonPausing ? "►" : "||";
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI Construction
|
// UI Construction
|
||||||
|
|
||||||
@ -298,26 +249,17 @@ namespace UnityExplorer.UI
|
|||||||
UIFactory.SetLayoutElement(NavbarTabButtonHolder, minHeight: 25, flexibleHeight: 999, flexibleWidth: 999);
|
UIFactory.SetLayoutElement(NavbarTabButtonHolder, minHeight: 25, flexibleHeight: 999, flexibleWidth: 999);
|
||||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(NavbarTabButtonHolder, false, true, true, true, 4, 2, 2, 2, 2);
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(NavbarTabButtonHolder, false, true, true, true, 4, 2, 2, 2, 2);
|
||||||
|
|
||||||
// Time controls
|
// Time scale widget
|
||||||
|
timeScaleWidget = new(navbarPanel);
|
||||||
|
|
||||||
Text timeLabel = UIFactory.CreateLabel(navbarPanel, "TimeLabel", "Time:", TextAnchor.MiddleRight, Color.grey);
|
//spacer
|
||||||
UIFactory.SetLayoutElement(timeLabel.gameObject, minHeight: 25, minWidth: 50);
|
GameObject spacer = UIFactory.CreateUIObject("Spacer", navbarPanel);
|
||||||
|
UIFactory.SetLayoutElement(spacer, minWidth: 15);
|
||||||
timeInput = UIFactory.CreateInputField(navbarPanel, "TimeInput", "timeScale");
|
|
||||||
UIFactory.SetLayoutElement(timeInput.Component.gameObject, minHeight: 25, minWidth: 40);
|
|
||||||
timeInput.Component.GetOnEndEdit().AddListener(OnTimeInputEndEdit);
|
|
||||||
|
|
||||||
timeInput.Text = string.Empty;
|
|
||||||
timeInput.Text = Time.timeScale.ToString();
|
|
||||||
|
|
||||||
pauseBtn = UIFactory.CreateButton(navbarPanel, "PauseButton", "||", new Color(0.2f, 0.2f, 0.2f));
|
|
||||||
UIFactory.SetLayoutElement(pauseBtn.Component.gameObject, minHeight: 25, minWidth: 25);
|
|
||||||
pauseBtn.OnClick += OnPauseButtonClicked;
|
|
||||||
|
|
||||||
// Hide menu button
|
// Hide menu button
|
||||||
|
|
||||||
closeBtn = UIFactory.CreateButton(navbarPanel, "CloseButton", ConfigManager.Master_Toggle.Value.ToString());
|
closeBtn = UIFactory.CreateButton(navbarPanel, "CloseButton", ConfigManager.Master_Toggle.Value.ToString());
|
||||||
UIFactory.SetLayoutElement(closeBtn.Component.gameObject, minHeight: 25, minWidth: 80, flexibleWidth: 0);
|
UIFactory.SetLayoutElement(closeBtn.Component.gameObject, minHeight: 25, minWidth: 60, flexibleWidth: 0);
|
||||||
RuntimeHelper.SetColorBlock(closeBtn.Component, new Color(0.63f, 0.32f, 0.31f),
|
RuntimeHelper.SetColorBlock(closeBtn.Component, new Color(0.63f, 0.32f, 0.31f),
|
||||||
new Color(0.81f, 0.25f, 0.2f), new Color(0.6f, 0.18f, 0.16f));
|
new Color(0.81f, 0.25f, 0.2f), new Color(0.6f, 0.18f, 0.16f));
|
||||||
|
|
||||||
|
@ -33,7 +33,8 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
Text ActiveSelfText;
|
Text ActiveSelfText;
|
||||||
Toggle IsStaticToggle;
|
Toggle IsStaticToggle;
|
||||||
|
|
||||||
InputFieldRef SceneInput;
|
ButtonRef SceneButton;
|
||||||
|
|
||||||
InputFieldRef InstanceIDInput;
|
InputFieldRef InstanceIDInput;
|
||||||
InputFieldRef TagInput;
|
InputFieldRef TagInput;
|
||||||
|
|
||||||
@ -100,7 +101,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
if (force || Target.scene.handle != lastSceneHandle)
|
if (force || Target.scene.handle != lastSceneHandle)
|
||||||
{
|
{
|
||||||
lastSceneHandle = Target.scene.handle;
|
lastSceneHandle = Target.scene.handle;
|
||||||
SceneInput.Text = Target.scene.IsValid() ? Target.scene.name : "None (Asset/Resource)";
|
SceneButton.ButtonText.text = Target.scene.IsValid() ? Target.scene.name : "None (Asset/Resource)";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (force || (!TagInput.Component.isFocused && Target.tag != lastTag))
|
if (force || (!TagInput.Component.isFocused && Target.tag != lastTag))
|
||||||
@ -228,6 +229,11 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
ExplorerCore.LogWarning($"Exception setting tag! {ex.ReflectionExToString()}");
|
ExplorerCore.LogWarning($"Exception setting tag! {ex.ReflectionExToString()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnSceneButtonClicked()
|
||||||
|
{
|
||||||
|
InspectorManager.Inspect(Target.scene);
|
||||||
|
}
|
||||||
|
|
||||||
void OnExploreButtonClicked()
|
void OnExploreButtonClicked()
|
||||||
{
|
{
|
||||||
@ -383,10 +389,9 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
Text sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey);
|
Text sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey);
|
||||||
UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50);
|
UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||||
|
|
||||||
SceneInput = UIFactory.CreateInputField(thirdrow, "SceneInput", "untitled");
|
SceneButton = UIFactory.CreateButton(thirdrow, "SceneButton", "untitled");
|
||||||
UIFactory.SetLayoutElement(SceneInput.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 999);
|
UIFactory.SetLayoutElement(SceneButton.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 999);
|
||||||
SceneInput.Component.readOnly = true;
|
SceneButton.OnClick += OnSceneButtonClicked;
|
||||||
SceneInput.Component.textComponent.color = new Color(0.7f, 0.7f, 0.7f);
|
|
||||||
|
|
||||||
// Layer
|
// Layer
|
||||||
Text layerLabel = UIFactory.CreateLabel(thirdrow, "LayerLabel", "Layer:", TextAnchor.MiddleLeft, Color.grey);
|
Text layerLabel = UIFactory.CreateLabel(thirdrow, "LayerLabel", "Layer:", TextAnchor.MiddleLeft, Color.grey);
|
||||||
|
116
src/UI/Widgets/TimeScaleWidget.cs
Normal file
116
src/UI/Widgets/TimeScaleWidget.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using UniverseLib;
|
||||||
|
using UniverseLib.UI;
|
||||||
|
using UniverseLib.UI.Models;
|
||||||
|
using UniverseLib.Utility;
|
||||||
|
|
||||||
|
namespace UnityExplorer.UI.Widgets
|
||||||
|
{
|
||||||
|
internal class TimeScaleWidget
|
||||||
|
{
|
||||||
|
public TimeScaleWidget(GameObject parent)
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
|
||||||
|
ConstructUI(parent);
|
||||||
|
|
||||||
|
InitPatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
static TimeScaleWidget Instance;
|
||||||
|
|
||||||
|
ButtonRef lockBtn;
|
||||||
|
bool locked;
|
||||||
|
InputFieldRef timeInput;
|
||||||
|
float desiredTime;
|
||||||
|
bool settingTimeScale;
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
// Fallback in case Time.timeScale patch failed for whatever reason
|
||||||
|
if (locked)
|
||||||
|
SetTimeScale(desiredTime);
|
||||||
|
|
||||||
|
if (!timeInput.Component.isFocused)
|
||||||
|
timeInput.Text = Time.timeScale.ToString("F2");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTimeScale(float time)
|
||||||
|
{
|
||||||
|
settingTimeScale = true;
|
||||||
|
Time.timeScale = time;
|
||||||
|
settingTimeScale = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI event listeners
|
||||||
|
|
||||||
|
void OnTimeInputEndEdit(string val)
|
||||||
|
{
|
||||||
|
if (float.TryParse(val, out float f))
|
||||||
|
{
|
||||||
|
SetTimeScale(f);
|
||||||
|
desiredTime = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnPauseButtonClicked()
|
||||||
|
{
|
||||||
|
OnTimeInputEndEdit(timeInput.Text);
|
||||||
|
|
||||||
|
locked = !locked;
|
||||||
|
|
||||||
|
Color color = locked ? new Color(0.3f, 0.3f, 0.2f) : new Color(0.2f, 0.2f, 0.2f);
|
||||||
|
RuntimeHelper.SetColorBlock(lockBtn.Component, color, color * 1.2f, color * 0.7f);
|
||||||
|
lockBtn.ButtonText.text = locked ? "Unlock" : "Lock";
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI Construction
|
||||||
|
|
||||||
|
void ConstructUI(GameObject parent)
|
||||||
|
{
|
||||||
|
Text timeLabel = UIFactory.CreateLabel(parent, "TimeLabel", "Time:", TextAnchor.MiddleRight, Color.grey);
|
||||||
|
UIFactory.SetLayoutElement(timeLabel.gameObject, minHeight: 25, minWidth: 35);
|
||||||
|
|
||||||
|
timeInput = UIFactory.CreateInputField(parent, "TimeInput", "timeScale");
|
||||||
|
UIFactory.SetLayoutElement(timeInput.Component.gameObject, minHeight: 25, minWidth: 40);
|
||||||
|
timeInput.Component.GetOnEndEdit().AddListener(OnTimeInputEndEdit);
|
||||||
|
|
||||||
|
timeInput.Text = string.Empty;
|
||||||
|
timeInput.Text = Time.timeScale.ToString();
|
||||||
|
|
||||||
|
lockBtn = UIFactory.CreateButton(parent, "PauseButton", "Lock", new Color(0.2f, 0.2f, 0.2f));
|
||||||
|
UIFactory.SetLayoutElement(lockBtn.Component.gameObject, minHeight: 25, minWidth: 50);
|
||||||
|
lockBtn.OnClick += OnPauseButtonClicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only allow Time.timeScale to be set if the user hasn't "locked" it or if we are setting the value internally.
|
||||||
|
|
||||||
|
static void InitPatch()
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MethodInfo target = AccessTools.Method(typeof(Time), nameof(Time.timeScale));
|
||||||
|
#if CPP
|
||||||
|
if (UnhollowerBaseLib.UnhollowerUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(target) == null)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
ExplorerCore.Harmony.Patch(target,
|
||||||
|
prefix: new(AccessTools.Method(typeof(TimeScaleWidget), nameof(Prefix_Time_set_timeScale))));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Prefix_Time_set_timeScale()
|
||||||
|
{
|
||||||
|
return !Instance.locked || Instance.settingTimeScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,18 +22,18 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
static Coroutine CurrentlyPlayingCoroutine;
|
static Coroutine CurrentlyPlayingCoroutine;
|
||||||
static readonly string zeroLengthString = GetLengthString(0f);
|
static readonly string zeroLengthString = GetLengthString(0f);
|
||||||
|
|
||||||
public AudioClip RefAudioClip;
|
public AudioClip audioClip;
|
||||||
private string fullLengthText;
|
string fullLengthText;
|
||||||
|
|
||||||
private ButtonRef toggleButton;
|
ButtonRef toggleButton;
|
||||||
private bool audioPlayerWanted;
|
bool audioPlayerWanted;
|
||||||
|
|
||||||
private GameObject audioPlayerRoot;
|
GameObject audioPlayerRoot;
|
||||||
private ButtonRef playStopButton;
|
ButtonRef playStopButton;
|
||||||
private Text progressLabel;
|
Text progressLabel;
|
||||||
private GameObject saveObjectRow;
|
GameObject saveObjectRow;
|
||||||
private InputFieldRef savePathInput;
|
InputFieldRef savePathInput;
|
||||||
private GameObject cantSaveRow;
|
GameObject cantSaveRow;
|
||||||
|
|
||||||
public override void OnBorrowed(object target, Type targetType, ReflectionInspector inspector)
|
public override void OnBorrowed(object target, Type targetType, ReflectionInspector inspector)
|
||||||
{
|
{
|
||||||
@ -42,10 +42,10 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
this.audioPlayerRoot.transform.SetParent(inspector.UIRoot.transform);
|
this.audioPlayerRoot.transform.SetParent(inspector.UIRoot.transform);
|
||||||
this.audioPlayerRoot.transform.SetSiblingIndex(inspector.UIRoot.transform.childCount - 2);
|
this.audioPlayerRoot.transform.SetSiblingIndex(inspector.UIRoot.transform.childCount - 2);
|
||||||
|
|
||||||
RefAudioClip = target.TryCast<AudioClip>();
|
audioClip = target.TryCast<AudioClip>();
|
||||||
this.fullLengthText = GetLengthString(RefAudioClip.length);
|
this.fullLengthText = GetLengthString(audioClip.length);
|
||||||
|
|
||||||
if (RefAudioClip.loadType == AudioClipLoadType.DecompressOnLoad)
|
if (audioClip.loadType == AudioClipLoadType.DecompressOnLoad)
|
||||||
{
|
{
|
||||||
cantSaveRow.SetActive(false);
|
cantSaveRow.SetActive(false);
|
||||||
saveObjectRow.SetActive(true);
|
saveObjectRow.SetActive(true);
|
||||||
@ -62,7 +62,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
|
|
||||||
public override void OnReturnToPool()
|
public override void OnReturnToPool()
|
||||||
{
|
{
|
||||||
RefAudioClip = null;
|
audioClip = null;
|
||||||
|
|
||||||
if (audioPlayerWanted)
|
if (audioPlayerWanted)
|
||||||
ToggleAudioWidget();
|
ToggleAudioWidget();
|
||||||
@ -95,7 +95,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
|
|
||||||
void SetDefaultSavePath()
|
void SetDefaultSavePath()
|
||||||
{
|
{
|
||||||
string name = RefAudioClip.name;
|
string name = audioClip.name;
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
name = "untitled";
|
name = "untitled";
|
||||||
savePathInput.Text = Path.Combine(ConfigManager.Default_Output_Path.Value, $"{name}.wav");
|
savePathInput.Text = Path.Combine(ConfigManager.Default_Output_Path.Value, $"{name}.wav");
|
||||||
@ -163,7 +163,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
{
|
{
|
||||||
playStopButton.ButtonText.text = "Stop Clip";
|
playStopButton.ButtonText.text = "Stop Clip";
|
||||||
CurrentlyPlaying = this;
|
CurrentlyPlaying = this;
|
||||||
Source.clip = this.RefAudioClip;
|
Source.clip = this.audioClip;
|
||||||
Source.Play();
|
Source.Play();
|
||||||
|
|
||||||
while (Source.isPlaying)
|
while (Source.isPlaying)
|
||||||
@ -191,7 +191,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
|
|
||||||
public void OnSaveClipClicked()
|
public void OnSaveClipClicked()
|
||||||
{
|
{
|
||||||
if (!RefAudioClip)
|
if (!audioClip)
|
||||||
{
|
{
|
||||||
ExplorerCore.LogWarning("AudioClip is null, maybe it was destroyed?");
|
ExplorerCore.LogWarning("AudioClip is null, maybe it was destroyed?");
|
||||||
return;
|
return;
|
||||||
@ -212,7 +212,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
|
|
||||||
SavWav.Save(RefAudioClip, path);
|
SavWav.Save(audioClip, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override GameObject CreateContent(GameObject uiRoot)
|
public override GameObject CreateContent(GameObject uiRoot)
|
||||||
|
344
src/UI/Widgets/UnityObjects/MaterialWidget.cs
Normal file
344
src/UI/Widgets/UnityObjects/MaterialWidget.cs
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using UnityExplorer.Config;
|
||||||
|
using UnityExplorer.Inspectors;
|
||||||
|
using UnityExplorer.UI.Panels;
|
||||||
|
using UniverseLib;
|
||||||
|
using UniverseLib.Runtime;
|
||||||
|
using UniverseLib.UI;
|
||||||
|
using UniverseLib.UI.Models;
|
||||||
|
using UniverseLib.UI.ObjectPool;
|
||||||
|
using UniverseLib.Utility;
|
||||||
|
|
||||||
|
namespace UnityExplorer.UI.Widgets
|
||||||
|
{
|
||||||
|
public class MaterialWidget : UnityObjectWidget
|
||||||
|
{
|
||||||
|
static MaterialWidget()
|
||||||
|
{
|
||||||
|
mi_GetTexturePropertyNames = typeof(Material).GetMethod("GetTexturePropertyNames", ArgumentUtility.EmptyTypes);
|
||||||
|
MaterialWidgetSupported = mi_GetTexturePropertyNames != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool MaterialWidgetSupported { get; }
|
||||||
|
static readonly MethodInfo mi_GetTexturePropertyNames;
|
||||||
|
|
||||||
|
Material material;
|
||||||
|
Texture2D activeTexture;
|
||||||
|
readonly Dictionary<string, Texture> textures = new();
|
||||||
|
readonly HashSet<Texture2D> texturesToDestroy = new();
|
||||||
|
|
||||||
|
bool textureViewerWanted;
|
||||||
|
ButtonRef toggleButton;
|
||||||
|
|
||||||
|
GameObject textureViewerRoot;
|
||||||
|
Dropdown textureDropdown;
|
||||||
|
InputFieldRef savePathInput;
|
||||||
|
Image image;
|
||||||
|
LayoutElement imageLayout;
|
||||||
|
|
||||||
|
public override void OnBorrowed(object target, Type targetType, ReflectionInspector inspector)
|
||||||
|
{
|
||||||
|
base.OnBorrowed(target, targetType, inspector);
|
||||||
|
|
||||||
|
material = target.TryCast<Material>();
|
||||||
|
|
||||||
|
if (material.mainTexture)
|
||||||
|
SetActiveTexture(material.mainTexture);
|
||||||
|
|
||||||
|
if (mi_GetTexturePropertyNames.Invoke(material, ArgumentUtility.EmptyArgs) is IEnumerable<string> propNames)
|
||||||
|
{
|
||||||
|
foreach (string property in propNames)
|
||||||
|
{
|
||||||
|
if (material.GetTexture(property) is Texture texture)
|
||||||
|
{
|
||||||
|
if (texture.TryCast<Texture2D>() is null && texture.TryCast<Cubemap>() is null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
textures.Add(property, texture);
|
||||||
|
|
||||||
|
if (!activeTexture)
|
||||||
|
SetActiveTexture(texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textureViewerRoot)
|
||||||
|
{
|
||||||
|
textureViewerRoot.transform.SetParent(inspector.UIRoot.transform);
|
||||||
|
RefreshTextureDropdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
InspectorPanel.Instance.Dragger.OnFinishResize += OnInspectorFinishResize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetActiveTexture(Texture texture)
|
||||||
|
{
|
||||||
|
if (texture.TryCast<Texture2D>() is Texture2D tex2D)
|
||||||
|
activeTexture = tex2D;
|
||||||
|
else if (texture.TryCast<Cubemap>() is Cubemap cubemap)
|
||||||
|
{
|
||||||
|
activeTexture = TextureHelper.UnwrapCubemap(cubemap);
|
||||||
|
texturesToDestroy.Add(activeTexture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnReturnToPool()
|
||||||
|
{
|
||||||
|
InspectorPanel.Instance.Dragger.OnFinishResize -= OnInspectorFinishResize;
|
||||||
|
|
||||||
|
if (texturesToDestroy.Any())
|
||||||
|
{
|
||||||
|
foreach (Texture2D tex in texturesToDestroy)
|
||||||
|
UnityEngine.Object.Destroy(tex);
|
||||||
|
texturesToDestroy.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
material = null;
|
||||||
|
activeTexture = null;
|
||||||
|
textures.Clear();
|
||||||
|
|
||||||
|
if (image.sprite)
|
||||||
|
UnityEngine.Object.Destroy(image.sprite);
|
||||||
|
|
||||||
|
if (textureViewerWanted)
|
||||||
|
ToggleTextureViewer();
|
||||||
|
|
||||||
|
if (textureViewerRoot)
|
||||||
|
textureViewerRoot.transform.SetParent(Pool<Texture2DWidget>.Instance.InactiveHolder.transform);
|
||||||
|
|
||||||
|
base.OnReturnToPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleTextureViewer()
|
||||||
|
{
|
||||||
|
if (textureViewerWanted)
|
||||||
|
{
|
||||||
|
// disable
|
||||||
|
|
||||||
|
textureViewerWanted = false;
|
||||||
|
textureViewerRoot.SetActive(false);
|
||||||
|
toggleButton.ButtonText.text = "View Material";
|
||||||
|
|
||||||
|
owner.ContentRoot.SetActive(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// enable
|
||||||
|
|
||||||
|
if (!image.sprite)
|
||||||
|
{
|
||||||
|
RefreshTextureViewer();
|
||||||
|
RefreshTextureDropdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
SetImageSize();
|
||||||
|
|
||||||
|
textureViewerWanted = true;
|
||||||
|
textureViewerRoot.SetActive(true);
|
||||||
|
toggleButton.ButtonText.text = "Hide Material";
|
||||||
|
|
||||||
|
owner.ContentRoot.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefreshTextureViewer()
|
||||||
|
{
|
||||||
|
if (!this.activeTexture)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Material has no active textures!");
|
||||||
|
savePathInput.Text = string.Empty;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.sprite)
|
||||||
|
UnityEngine.Object.Destroy(image.sprite);
|
||||||
|
|
||||||
|
string name = activeTexture.name;
|
||||||
|
if (string.IsNullOrEmpty(name))
|
||||||
|
name = "untitled";
|
||||||
|
savePathInput.Text = Path.Combine(ConfigManager.Default_Output_Path.Value, $"{name}.png");
|
||||||
|
|
||||||
|
Sprite sprite = TextureHelper.CreateSprite(activeTexture);
|
||||||
|
image.sprite = sprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RefreshTextureDropdown()
|
||||||
|
{
|
||||||
|
if (!textureDropdown)
|
||||||
|
return;
|
||||||
|
|
||||||
|
textureDropdown.options.Clear();
|
||||||
|
|
||||||
|
foreach (string key in textures.Keys)
|
||||||
|
textureDropdown.options.Add(new(key));
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (Texture value in textures.Values)
|
||||||
|
{
|
||||||
|
if (activeTexture.ReferenceEqual(value))
|
||||||
|
{
|
||||||
|
textureDropdown.value = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
textureDropdown.RefreshShownValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnTextureDropdownChanged(int value)
|
||||||
|
{
|
||||||
|
Texture tex = textures.ElementAt(value).Value;
|
||||||
|
if (activeTexture.ReferenceEqual(tex))
|
||||||
|
return;
|
||||||
|
SetActiveTexture(tex);
|
||||||
|
RefreshTextureViewer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnInspectorFinishResize()
|
||||||
|
{
|
||||||
|
SetImageSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetImageSize()
|
||||||
|
{
|
||||||
|
if (!imageLayout)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RuntimeHelper.StartCoroutine(SetImageSizeCoro());
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator SetImageSizeCoro()
|
||||||
|
{
|
||||||
|
if (!activeTexture)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
// let unity rebuild layout etc
|
||||||
|
yield return null;
|
||||||
|
|
||||||
|
RectTransform imageRect = InspectorPanel.Instance.Rect;
|
||||||
|
|
||||||
|
float rectWidth = imageRect.rect.width - 25;
|
||||||
|
float rectHeight = imageRect.rect.height - 196;
|
||||||
|
|
||||||
|
// If our image is smaller than the viewport, just use 100% scaling
|
||||||
|
if (activeTexture.width < rectWidth && activeTexture.height < rectHeight)
|
||||||
|
{
|
||||||
|
imageLayout.minWidth = activeTexture.width;
|
||||||
|
imageLayout.minHeight = activeTexture.height;
|
||||||
|
}
|
||||||
|
else // we will need to scale down the image to fit
|
||||||
|
{
|
||||||
|
// get the ratio of our viewport dimensions to width and height
|
||||||
|
float viewWidthRatio = (float)((decimal)rectWidth / (decimal)activeTexture.width);
|
||||||
|
float viewHeightRatio = (float)((decimal)rectHeight / (decimal)activeTexture.height);
|
||||||
|
|
||||||
|
// if width needs to be scaled more than height
|
||||||
|
if (viewWidthRatio < viewHeightRatio)
|
||||||
|
{
|
||||||
|
imageLayout.minWidth = activeTexture.width * viewWidthRatio;
|
||||||
|
imageLayout.minHeight = activeTexture.height * viewWidthRatio;
|
||||||
|
}
|
||||||
|
else // if height needs to be scaled more than width
|
||||||
|
{
|
||||||
|
imageLayout.minWidth = activeTexture.width * viewHeightRatio;
|
||||||
|
imageLayout.minHeight = activeTexture.height * viewHeightRatio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnSaveTextureClicked()
|
||||||
|
{
|
||||||
|
if (!activeTexture)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning("Texture is null, maybe it was destroyed?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(savePathInput.Text))
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning("Save path cannot be empty!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string path = savePathInput.Text;
|
||||||
|
if (!path.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
path += ".png";
|
||||||
|
|
||||||
|
path = IOUtility.EnsureValidFilePath(path);
|
||||||
|
|
||||||
|
if (File.Exists(path))
|
||||||
|
File.Delete(path);
|
||||||
|
|
||||||
|
TextureHelper.SaveTextureAsPNG(activeTexture, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override GameObject CreateContent(GameObject uiRoot)
|
||||||
|
{
|
||||||
|
GameObject ret = base.CreateContent(uiRoot);
|
||||||
|
|
||||||
|
// Button
|
||||||
|
|
||||||
|
toggleButton = UIFactory.CreateButton(UIRoot, "MaterialButton", "View Material", new Color(0.2f, 0.3f, 0.2f));
|
||||||
|
toggleButton.Transform.SetSiblingIndex(0);
|
||||||
|
UIFactory.SetLayoutElement(toggleButton.Component.gameObject, minHeight: 25, minWidth: 150);
|
||||||
|
toggleButton.OnClick += ToggleTextureViewer;
|
||||||
|
|
||||||
|
// Texture viewer
|
||||||
|
|
||||||
|
textureViewerRoot = UIFactory.CreateVerticalGroup(uiRoot, "MaterialViewer", false, false, true, true, 2, new Vector4(5, 5, 5, 5),
|
||||||
|
new Color(0.1f, 0.1f, 0.1f), childAlignment: TextAnchor.UpperLeft);
|
||||||
|
UIFactory.SetLayoutElement(textureViewerRoot, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||||
|
|
||||||
|
// Buttons holder
|
||||||
|
|
||||||
|
GameObject dropdownRow = UIFactory.CreateHorizontalGroup(textureViewerRoot, "DropdownRow", false, true, true, true, 5, new(3, 3, 3, 3));
|
||||||
|
UIFactory.SetLayoutElement(dropdownRow, minHeight: 30, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
Text dropdownLabel = UIFactory.CreateLabel(dropdownRow, "DropdownLabel", "Texture:");
|
||||||
|
UIFactory.SetLayoutElement(dropdownLabel.gameObject, minWidth: 75, minHeight: 25);
|
||||||
|
|
||||||
|
GameObject dropdownObj = UIFactory.CreateDropdown(dropdownRow, "TextureDropdown", out textureDropdown, "NOT SET", 13, OnTextureDropdownChanged);
|
||||||
|
UIFactory.SetLayoutElement(dropdownObj, minWidth: 350, minHeight: 25);
|
||||||
|
|
||||||
|
// Save helper
|
||||||
|
|
||||||
|
GameObject saveRowObj = UIFactory.CreateHorizontalGroup(textureViewerRoot, "SaveRow", false, false, true, true, 2, new Vector4(2, 2, 2, 2),
|
||||||
|
new Color(0.1f, 0.1f, 0.1f));
|
||||||
|
|
||||||
|
ButtonRef saveBtn = UIFactory.CreateButton(saveRowObj, "SaveButton", "Save .PNG", new Color(0.2f, 0.25f, 0.2f));
|
||||||
|
UIFactory.SetLayoutElement(saveBtn.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 0);
|
||||||
|
saveBtn.OnClick += OnSaveTextureClicked;
|
||||||
|
|
||||||
|
savePathInput = UIFactory.CreateInputField(saveRowObj, "SaveInput", "...");
|
||||||
|
UIFactory.SetLayoutElement(savePathInput.UIRoot, minHeight: 25, minWidth: 100, flexibleWidth: 9999);
|
||||||
|
|
||||||
|
// Actual texture viewer
|
||||||
|
|
||||||
|
GameObject imageViewport = UIFactory.CreateVerticalGroup(textureViewerRoot, "ImageViewport", false, false, true, true,
|
||||||
|
bgColor: new(1, 1, 1, 0), childAlignment: TextAnchor.MiddleCenter);
|
||||||
|
UIFactory.SetLayoutElement(imageViewport, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||||
|
|
||||||
|
GameObject imageHolder = UIFactory.CreateUIObject("ImageHolder", imageViewport);
|
||||||
|
imageLayout = UIFactory.SetLayoutElement(imageHolder, 1, 1, 0, 0);
|
||||||
|
|
||||||
|
GameObject actualImageObj = UIFactory.CreateUIObject("ActualImage", imageHolder);
|
||||||
|
RectTransform actualRect = actualImageObj.GetComponent<RectTransform>();
|
||||||
|
actualRect.anchorMin = new(0, 0);
|
||||||
|
actualRect.anchorMax = new(1, 1);
|
||||||
|
image = actualImageObj.AddComponent<Image>();
|
||||||
|
|
||||||
|
textureViewerRoot.SetActive(false);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,29 +17,51 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
{
|
{
|
||||||
public class Texture2DWidget : UnityObjectWidget
|
public class Texture2DWidget : UnityObjectWidget
|
||||||
{
|
{
|
||||||
private Texture2D TextureRef;
|
Texture2D texture;
|
||||||
private float realWidth;
|
bool shouldDestroyTexture;
|
||||||
private float realHeight;
|
|
||||||
|
|
||||||
private bool textureViewerWanted;
|
bool textureViewerWanted;
|
||||||
private ButtonRef toggleButton;
|
ButtonRef toggleButton;
|
||||||
|
|
||||||
private GameObject textureViewerRoot;
|
GameObject textureViewerRoot;
|
||||||
private InputFieldRef savePathInput;
|
InputFieldRef savePathInput;
|
||||||
private Image image;
|
Image image;
|
||||||
private LayoutElement imageLayout;
|
LayoutElement imageLayout;
|
||||||
|
|
||||||
public override void OnBorrowed(object target, Type targetType, ReflectionInspector inspector)
|
public override void OnBorrowed(object target, Type targetType, ReflectionInspector inspector)
|
||||||
{
|
{
|
||||||
base.OnBorrowed(target, targetType, inspector);
|
base.OnBorrowed(target, targetType, inspector);
|
||||||
|
|
||||||
TextureRef = target.TryCast<Texture2D>();
|
if (target.TryCast<Cubemap>() is Cubemap cubemap)
|
||||||
|
{
|
||||||
|
texture = TextureHelper.UnwrapCubemap(cubemap);
|
||||||
|
shouldDestroyTexture = true;
|
||||||
|
}
|
||||||
|
else if (target.TryCast<Sprite>() is Sprite sprite)
|
||||||
|
{
|
||||||
|
if (sprite.packingMode == SpritePackingMode.Tight)
|
||||||
|
texture = sprite.texture;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texture = TextureHelper.CopyTexture(sprite.texture, sprite.textureRect);
|
||||||
|
shouldDestroyTexture = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (target.TryCast<Image>() is Image image)
|
||||||
|
{
|
||||||
|
if (image.sprite.packingMode == SpritePackingMode.Tight)
|
||||||
|
texture = image.sprite.texture;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texture = TextureHelper.CopyTexture(image.sprite.texture, image.sprite.textureRect);
|
||||||
|
shouldDestroyTexture = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
texture = target.TryCast<Texture2D>();
|
||||||
|
|
||||||
realWidth = TextureRef.width;
|
if (textureViewerRoot)
|
||||||
realHeight = TextureRef.height;
|
textureViewerRoot.transform.SetParent(inspector.UIRoot.transform);
|
||||||
|
|
||||||
if (this.textureViewerRoot)
|
|
||||||
this.textureViewerRoot.transform.SetParent(inspector.UIRoot.transform);
|
|
||||||
|
|
||||||
InspectorPanel.Instance.Dragger.OnFinishResize += OnInspectorFinishResize;
|
InspectorPanel.Instance.Dragger.OnFinishResize += OnInspectorFinishResize;
|
||||||
}
|
}
|
||||||
@ -48,21 +70,25 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
{
|
{
|
||||||
InspectorPanel.Instance.Dragger.OnFinishResize -= OnInspectorFinishResize;
|
InspectorPanel.Instance.Dragger.OnFinishResize -= OnInspectorFinishResize;
|
||||||
|
|
||||||
TextureRef = null;
|
if (shouldDestroyTexture)
|
||||||
|
UnityEngine.Object.Destroy(texture);
|
||||||
|
|
||||||
|
texture = null;
|
||||||
|
shouldDestroyTexture = false;
|
||||||
|
|
||||||
if (image.sprite)
|
if (image.sprite)
|
||||||
GameObject.Destroy(image.sprite);
|
UnityEngine.Object.Destroy(image.sprite);
|
||||||
|
|
||||||
if (textureViewerWanted)
|
if (textureViewerWanted)
|
||||||
ToggleTextureViewer();
|
ToggleTextureViewer();
|
||||||
|
|
||||||
if (this.textureViewerRoot)
|
if (textureViewerRoot)
|
||||||
this.textureViewerRoot.transform.SetParent(Pool<Texture2DWidget>.Instance.InactiveHolder.transform);
|
textureViewerRoot.transform.SetParent(Pool<Texture2DWidget>.Instance.InactiveHolder.transform);
|
||||||
|
|
||||||
base.OnReturnToPool();
|
base.OnReturnToPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleTextureViewer()
|
void ToggleTextureViewer()
|
||||||
{
|
{
|
||||||
if (textureViewerWanted)
|
if (textureViewerWanted)
|
||||||
{
|
{
|
||||||
@ -71,7 +97,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
textureViewerRoot.SetActive(false);
|
textureViewerRoot.SetActive(false);
|
||||||
toggleButton.ButtonText.text = "View Texture";
|
toggleButton.ButtonText.text = "View Texture";
|
||||||
|
|
||||||
ParentInspector.ContentRoot.SetActive(true);
|
owner.ContentRoot.SetActive(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -85,30 +111,30 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
textureViewerRoot.SetActive(true);
|
textureViewerRoot.SetActive(true);
|
||||||
toggleButton.ButtonText.text = "Hide Texture";
|
toggleButton.ButtonText.text = "Hide Texture";
|
||||||
|
|
||||||
ParentInspector.ContentRoot.gameObject.SetActive(false);
|
owner.ContentRoot.gameObject.SetActive(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupTextureViewer()
|
void SetupTextureViewer()
|
||||||
{
|
{
|
||||||
if (!this.TextureRef)
|
if (!this.texture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string name = TextureRef.name;
|
string name = texture.name;
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
name = "untitled";
|
name = "untitled";
|
||||||
savePathInput.Text = Path.Combine(ConfigManager.Default_Output_Path.Value, $"{name}.png");
|
savePathInput.Text = Path.Combine(ConfigManager.Default_Output_Path.Value, $"{name}.png");
|
||||||
|
|
||||||
Sprite sprite = TextureHelper.CreateSprite(TextureRef);
|
Sprite sprite = TextureHelper.CreateSprite(texture);
|
||||||
image.sprite = sprite;
|
image.sprite = sprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInspectorFinishResize()
|
void OnInspectorFinishResize()
|
||||||
{
|
{
|
||||||
SetImageSize();
|
SetImageSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetImageSize()
|
void SetImageSize()
|
||||||
{
|
{
|
||||||
if (!imageLayout)
|
if (!imageLayout)
|
||||||
return;
|
return;
|
||||||
@ -127,34 +153,34 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
float rectHeight = imageRect.rect.height - 196;
|
float rectHeight = imageRect.rect.height - 196;
|
||||||
|
|
||||||
// If our image is smaller than the viewport, just use 100% scaling
|
// If our image is smaller than the viewport, just use 100% scaling
|
||||||
if (realWidth < rectWidth && realHeight < rectHeight)
|
if (texture.width < rectWidth && texture.height < rectHeight)
|
||||||
{
|
{
|
||||||
imageLayout.minWidth = realWidth;
|
imageLayout.minWidth = texture.width;
|
||||||
imageLayout.minHeight = realHeight;
|
imageLayout.minHeight = texture.height;
|
||||||
}
|
}
|
||||||
else // we will need to scale down the image to fit
|
else // we will need to scale down the image to fit
|
||||||
{
|
{
|
||||||
// get the ratio of our viewport dimensions to width and height
|
// get the ratio of our viewport dimensions to width and height
|
||||||
float viewWidthRatio = (float)((decimal)rectWidth / (decimal)realWidth);
|
float viewWidthRatio = (float)((decimal)rectWidth / (decimal)texture.width);
|
||||||
float viewHeightRatio = (float)((decimal)rectHeight / (decimal)realHeight);
|
float viewHeightRatio = (float)((decimal)rectHeight / (decimal)texture.height);
|
||||||
|
|
||||||
// if width needs to be scaled more than height
|
// if width needs to be scaled more than height
|
||||||
if (viewWidthRatio < viewHeightRatio)
|
if (viewWidthRatio < viewHeightRatio)
|
||||||
{
|
{
|
||||||
imageLayout.minWidth = realWidth * viewWidthRatio;
|
imageLayout.minWidth = texture.width * viewWidthRatio;
|
||||||
imageLayout.minHeight = realHeight * viewWidthRatio;
|
imageLayout.minHeight = texture.height * viewWidthRatio;
|
||||||
}
|
}
|
||||||
else // if height needs to be scaled more than width
|
else // if height needs to be scaled more than width
|
||||||
{
|
{
|
||||||
imageLayout.minWidth = realWidth * viewHeightRatio;
|
imageLayout.minWidth = texture.width * viewHeightRatio;
|
||||||
imageLayout.minHeight = realHeight * viewHeightRatio;
|
imageLayout.minHeight = texture.height * viewHeightRatio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSaveTextureClicked()
|
void OnSaveTextureClicked()
|
||||||
{
|
{
|
||||||
if (!TextureRef)
|
if (!texture)
|
||||||
{
|
{
|
||||||
ExplorerCore.LogWarning("Texture is null, maybe it was destroyed?");
|
ExplorerCore.LogWarning("Texture is null, maybe it was destroyed?");
|
||||||
return;
|
return;
|
||||||
@ -175,18 +201,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
if (File.Exists(path))
|
if (File.Exists(path))
|
||||||
File.Delete(path);
|
File.Delete(path);
|
||||||
|
|
||||||
Texture2D tex = TextureRef;
|
TextureHelper.SaveTextureAsPNG(texture, path);
|
||||||
if (!TextureHelper.IsReadable(tex))
|
|
||||||
tex = TextureHelper.ForceReadTexture(tex);
|
|
||||||
|
|
||||||
byte[] data = TextureHelper.EncodeToPNG(tex);
|
|
||||||
File.WriteAllBytes(path, data);
|
|
||||||
|
|
||||||
if (tex != TextureRef)
|
|
||||||
{
|
|
||||||
// cleanup temp texture if we had to force-read it.
|
|
||||||
GameObject.Destroy(tex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override GameObject CreateContent(GameObject uiRoot)
|
public override GameObject CreateContent(GameObject uiRoot)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityExplorer.Inspectors;
|
using UnityExplorer.Inspectors;
|
||||||
@ -11,9 +12,9 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
{
|
{
|
||||||
public class UnityObjectWidget : IPooledObject
|
public class UnityObjectWidget : IPooledObject
|
||||||
{
|
{
|
||||||
public UnityEngine.Object UnityObjectRef;
|
public UnityEngine.Object unityObject;
|
||||||
public Component ComponentRef;
|
public Component component;
|
||||||
public ReflectionInspector ParentInspector;
|
public ReflectionInspector owner;
|
||||||
|
|
||||||
protected ButtonRef gameObjectButton;
|
protected ButtonRef gameObjectButton;
|
||||||
protected InputFieldRef nameInput;
|
protected InputFieldRef nameInput;
|
||||||
@ -30,8 +31,14 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
|
|
||||||
UnityObjectWidget widget = target switch
|
UnityObjectWidget widget = target switch
|
||||||
{
|
{
|
||||||
Texture2D => Pool<Texture2DWidget>.Borrow(),
|
Texture2D or Cubemap => Pool<Texture2DWidget>.Borrow(),
|
||||||
|
Sprite s when s.texture => Pool<Texture2DWidget>.Borrow(),
|
||||||
|
Image i when i.sprite?.texture => Pool<Texture2DWidget>.Borrow(),
|
||||||
|
|
||||||
|
Material when MaterialWidget.MaterialWidgetSupported => Pool<MaterialWidget>.Borrow(),
|
||||||
|
|
||||||
AudioClip => Pool<AudioClipWidget>.Borrow(),
|
AudioClip => Pool<AudioClipWidget>.Borrow(),
|
||||||
|
|
||||||
_ => Pool<UnityObjectWidget>.Borrow()
|
_ => Pool<UnityObjectWidget>.Borrow()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,7 +49,7 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
|
|
||||||
public virtual void OnBorrowed(object target, Type targetType, ReflectionInspector inspector)
|
public virtual void OnBorrowed(object target, Type targetType, ReflectionInspector inspector)
|
||||||
{
|
{
|
||||||
this.ParentInspector = inspector ?? throw new ArgumentNullException(nameof(inspector));
|
this.owner = inspector;
|
||||||
|
|
||||||
if (!this.UIRoot)
|
if (!this.UIRoot)
|
||||||
CreateContent(inspector.UIRoot);
|
CreateContent(inspector.UIRoot);
|
||||||
@ -51,15 +58,15 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
|
|
||||||
this.UIRoot.transform.SetSiblingIndex(inspector.UIRoot.transform.childCount - 2);
|
this.UIRoot.transform.SetSiblingIndex(inspector.UIRoot.transform.childCount - 2);
|
||||||
|
|
||||||
UnityObjectRef = target.TryCast<UnityEngine.Object>();
|
unityObject = target.TryCast<UnityEngine.Object>();
|
||||||
UIRoot.SetActive(true);
|
UIRoot.SetActive(true);
|
||||||
|
|
||||||
nameInput.Text = UnityObjectRef.name;
|
nameInput.Text = unityObject.name;
|
||||||
instanceIdInput.Text = UnityObjectRef.GetInstanceID().ToString();
|
instanceIdInput.Text = unityObject.GetInstanceID().ToString();
|
||||||
|
|
||||||
if (typeof(Component).IsAssignableFrom(targetType))
|
if (typeof(Component).IsAssignableFrom(targetType))
|
||||||
{
|
{
|
||||||
ComponentRef = (Component)target.TryCast(typeof(Component));
|
component = (Component)target.TryCast(typeof(Component));
|
||||||
gameObjectButton.Component.gameObject.SetActive(true);
|
gameObjectButton.Component.gameObject.SetActive(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -68,19 +75,20 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
|
|
||||||
public virtual void OnReturnToPool()
|
public virtual void OnReturnToPool()
|
||||||
{
|
{
|
||||||
UnityObjectRef = null;
|
unityObject = null;
|
||||||
ComponentRef = null;
|
component = null;
|
||||||
ParentInspector = null;
|
owner = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
|
|
||||||
public virtual void Update()
|
public virtual void Update()
|
||||||
{
|
{
|
||||||
if (this.UnityObjectRef)
|
if (this.unityObject)
|
||||||
{
|
{
|
||||||
nameInput.Text = UnityObjectRef.name;
|
nameInput.Text = unityObject.name;
|
||||||
ParentInspector.Tab.TabText.text = $"{ParentInspector.TabButtonText} \"{UnityObjectRef.name}\"";
|
|
||||||
|
owner.Tab.TabText.text = $"{owner.TabButtonText} \"{unityObject.name}\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,13 +96,13 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
|
|
||||||
private void OnGameObjectButtonClicked()
|
private void OnGameObjectButtonClicked()
|
||||||
{
|
{
|
||||||
if (!ComponentRef)
|
if (!component)
|
||||||
{
|
{
|
||||||
ExplorerCore.LogWarning("Component reference is null or destroyed!");
|
ExplorerCore.LogWarning("Component reference is null or destroyed!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InspectorManager.Inspect(ComponentRef.gameObject);
|
InspectorManager.Inspect(component.gameObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI construction
|
// UI construction
|
||||||
|
@ -79,11 +79,11 @@
|
|||||||
<!-- il2cpp nuget -->
|
<!-- il2cpp nuget -->
|
||||||
<ItemGroup Condition="'$(Configuration)'=='ML_Cpp_net6' or '$(Configuration)'=='ML_Cpp_net472' or '$(Configuration)'=='STANDALONE_Cpp' or '$(Configuration)'=='BIE_Cpp'">
|
<ItemGroup Condition="'$(Configuration)'=='ML_Cpp_net6' or '$(Configuration)'=='ML_Cpp_net472' or '$(Configuration)'=='STANDALONE_Cpp' or '$(Configuration)'=='BIE_Cpp'">
|
||||||
<PackageReference Include="Il2CppAssemblyUnhollower.BaseLib" Version="0.4.22" />
|
<PackageReference Include="Il2CppAssemblyUnhollower.BaseLib" Version="0.4.22" />
|
||||||
<PackageReference Include="UniverseLib.IL2CPP" Version="1.3.14" />
|
<PackageReference Include="UniverseLib.IL2CPP" Version="1.4.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- mono nuget -->
|
<!-- mono nuget -->
|
||||||
<ItemGroup Condition="'$(Configuration)'=='BIE6_Mono' or '$(Configuration)'=='BIE5_Mono' or '$(Configuration)'=='ML_Mono' or '$(Configuration)'=='STANDALONE_Mono'">
|
<ItemGroup Condition="'$(Configuration)'=='BIE6_Mono' or '$(Configuration)'=='BIE5_Mono' or '$(Configuration)'=='ML_Mono' or '$(Configuration)'=='STANDALONE_Mono'">
|
||||||
<PackageReference Include="UniverseLib.Mono" Version="1.3.14" />
|
<PackageReference Include="UniverseLib.Mono" Version="1.4.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- ~~~~~ ASSEMBLY REFERENCES ~~~~~ -->
|
<!-- ~~~~~ ASSEMBLY REFERENCES ~~~~~ -->
|
||||||
|
Reference in New Issue
Block a user