mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-19 01:27:55 +08:00
Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
a5f56cf5a3 | |||
8c822b2ee9 | |||
4681b7e192 | |||
97093733d8 | |||
615f77979f | |||
ba3cf970d9 | |||
b2fb571b18 | |||
67ce6f946a | |||
1b82ccb49f | |||
480eb5afd5 | |||
88ea2a09c9 | |||
a678aa4d78 | |||
eaf478e314 | |||
d391968b32 | |||
70349ad7c7 | |||
78f2d1070f | |||
51307563ab | |||
185d1aaa0f | |||
3d6e8fcbf8 | |||
1daf4fade4 | |||
d92fb3f83f | |||
fe24b68fe2 | |||
6bf92b9a96 | |||
9f1cab019d | |||
a131404ac7 | |||
773900d749 | |||
342fc6bdb8 | |||
e85ea6ac3a | |||
af889e64cb | |||
0274022ce4 | |||
211576e0f8 | |||
3e42d7479f | |||
df4dea20c1 | |||
ece0c43067 | |||
6311c8d09a | |||
04739d0be8 |
113
.github/workflows/dotnet.yml
vendored
Normal file
113
.github/workflows/dotnet.yml
vendored
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
name: Build UnityExplorer
|
||||||
|
|
||||||
|
# Controls when the action will run.
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: windows-latest
|
||||||
|
if: "!contains(github.event.head_commit.message, '-noci')"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Checkout latest with submodules
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
# Setup tools
|
||||||
|
- name: Setup msbuild
|
||||||
|
uses: microsoft/setup-msbuild@v1
|
||||||
|
|
||||||
|
- name: Setup nuget
|
||||||
|
uses: nuget/setup-nuget@v1
|
||||||
|
with:
|
||||||
|
nuget-api-key: ${{ secrets.NuGetAPIKey }}
|
||||||
|
nuget-version: '5.x'
|
||||||
|
|
||||||
|
# Build Il2CppAssemblyUnhollower
|
||||||
|
- run: msbuild lib\Il2CppAssemblyUnhollower\UnhollowerBaseLib\UnhollowerBaseLib.csproj -t:Restore -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release
|
||||||
|
|
||||||
|
# Build mcs
|
||||||
|
- run: nuget restore lib\mcs-unity\mcs.sln
|
||||||
|
- run: msbuild lib\mcs-unity\mcs\mcs.csproj -t:Restore -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release
|
||||||
|
|
||||||
|
# Build UnityExplorer releases, and upload artifacts
|
||||||
|
|
||||||
|
- run: nuget restore src\UnityExplorer.sln
|
||||||
|
|
||||||
|
# BepInEx Il2Cpp
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_BIE_Cpp
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.BepInEx.Il2Cpp
|
||||||
|
path: ./Release/UnityExplorer.BepInEx.Il2Cpp/*
|
||||||
|
|
||||||
|
# BepInEx 5 Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_BIE5_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.BepInEx5.Mono
|
||||||
|
path: ./Release/UnityExplorer.BepInEx5.Mono/*
|
||||||
|
|
||||||
|
# BepInEx 6 Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_BIE6_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.BepInEx6.Mono
|
||||||
|
path: ./Release/UnityExplorer.BepInEx6.Mono/*
|
||||||
|
|
||||||
|
# MelonLoader Il2Cpp
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_ML_Cpp
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.MelonLoader.Il2Cpp
|
||||||
|
path: ./Release/UnityExplorer.MelonLoader.Il2Cpp/*
|
||||||
|
|
||||||
|
# MelonLoader Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_ML_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.MelonLoader.Mono
|
||||||
|
path: ./Release/UnityExplorer.MelonLoader.Mono/*
|
||||||
|
|
||||||
|
# MelonLoader 0.3.0 Il2Cpp
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_MLLegacy_Cpp
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.MelonLoader_Legacy.Il2Cpp
|
||||||
|
path: ./Release/UnityExplorer.MelonLoader_Legacy.Il2Cpp/*
|
||||||
|
|
||||||
|
# MelonLoader 0.3.0 Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_MLLegacy_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.MelonLoader_Legacy.Mono
|
||||||
|
path: ./Release/UnityExplorer.MelonLoader_Legacy.Mono/*
|
||||||
|
|
||||||
|
# Standalone Il2Cpp
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_STANDALONE_Cpp
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.Standalone.Il2Cpp
|
||||||
|
path: ./Release/UnityExplorer.Standalone.Il2Cpp/*
|
||||||
|
|
||||||
|
# Standalone Mono
|
||||||
|
- run: msbuild src\UnityExplorer.csproj -t:Rebuild -p:Platform="AnyCPU" -p:Configuration=Release_STANDALONE_Mono
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: UnityExplorer.Standalone.Mono
|
||||||
|
path: ./Release/UnityExplorer.Standalone.Mono/*
|
||||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,9 +1,6 @@
|
|||||||
[submodule "lib/Il2CppAssemblyUnhollower"]
|
[submodule "lib/Il2CppAssemblyUnhollower"]
|
||||||
path = lib/Il2CppAssemblyUnhollower
|
path = lib/Il2CppAssemblyUnhollower
|
||||||
url = https://github.com/knah/Il2CppAssemblyUnhollower
|
url = https://github.com/knah/Il2CppAssemblyUnhollower
|
||||||
[submodule "lib/HarmonyX"]
|
|
||||||
path = lib/HarmonyX
|
|
||||||
url = https://github.com/BepInEx/HarmonyX
|
|
||||||
[submodule "lib/mcs-unity"]
|
[submodule "lib/mcs-unity"]
|
||||||
path = lib/mcs-unity
|
path = lib/mcs-unity
|
||||||
url = https://github.com/sinai-dev/mcs-unity
|
url = https://github.com/sinai-dev/mcs-unity
|
||||||
|
25
README.md
25
README.md
@ -10,8 +10,9 @@
|
|||||||
Supports most Unity games from versions 5.2 to 2020+.
|
Supports most Unity games from versions 5.2 to 2020+.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Releases [](../../releases/latest) [](../../releases) [](../../releases/latest)
|
## Releases [](../../releases)
|
||||||
|
|
||||||
|
[](../../releases/latest) [](../../releases/latest)
|
||||||
| Mod Loader | IL2CPP | Mono |
|
| Mod Loader | IL2CPP | Mono |
|
||||||
| ----------- | ------ | ---- |
|
| ----------- | ------ | ---- |
|
||||||
| [BepInEx](https://github.com/BepInEx/BepInEx) 6.X | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx6.Mono.zip) |
|
| [BepInEx](https://github.com/BepInEx/BepInEx) 6.X | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx6.Mono.zip) |
|
||||||
@ -20,6 +21,8 @@
|
|||||||
| [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3.0 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Mono.zip) |
|
| [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3.0 | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.MelonLoader_Legacy.Mono.zip) |
|
||||||
| Standalone | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Mono.zip) |
|
| Standalone | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Mono.zip) |
|
||||||
|
|
||||||
|
* [Click here for Bleeding Edge releases](https://github.com/sinai-dev/UnityExplorer/actions) (click on the latest workflow and scroll down to Artifacts)
|
||||||
|
|
||||||
### Known issues
|
### Known issues
|
||||||
* Any `MissingMethodException` or `NotSupportedException`: please report the issue and provide a copy of your mod loader log and/or Unity log.
|
* Any `MissingMethodException` or `NotSupportedException`: please report the issue and provide a copy of your mod loader log and/or Unity log.
|
||||||
* In IL2CPP, some IEnumerable and IDictionary types may fail enumeration. Waiting for the Unhollower rewrite to address this any further.
|
* In IL2CPP, some IEnumerable and IDictionary types may fail enumeration. Waiting for the Unhollower rewrite to address this any further.
|
||||||
@ -66,9 +69,8 @@ The standalone release can be used with any injector or loader of your choice, b
|
|||||||
|
|
||||||
The inspector is used to see detailed information on GameObjects (GameObject Inspector), C# objects (Reflection Inspector) and C# classes (Static Inspector).
|
The inspector is used to see detailed information on GameObjects (GameObject Inspector), C# objects (Reflection Inspector) and C# classes (Static Inspector).
|
||||||
|
|
||||||
For the GameObject Inspector, you can edit any of the input fields in the inspector (excluding readonly fields) and press <b>Enter</b> to apply your changes. You can also do this to the GameObject path as a way to change the GameObject's parent. Press the <b>Escape</b> key to cancel your edits.
|
* In the GameObject Inspector, you can edit any of the input fields in the inspector (excluding readonly fields) and press <b>Enter</b> to apply your changes. You can also do this to the GameObject path as a way to change the GameObject's parent. Press the <b>Escape</b> key to cancel your edits.
|
||||||
|
* In the Reflection Inspectors, automatic updating is not enabled by default, and you must press Apply for any changes you make to take effect.
|
||||||
In the Reflection Inspectors, automatic updating is not enabled by default, and you must press Apply for any changes you make to take effect.
|
|
||||||
|
|
||||||
### C# Console
|
### C# Console
|
||||||
|
|
||||||
@ -94,11 +96,18 @@ Depending on the release you are using, the config file will be found at:
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
If you fork the repository on GitHub you can build using the [dotnet workflow](https://github.com/sinai-dev/UnityExplorer/blob/master/.github/workflows/dotnet.yml):
|
||||||
|
|
||||||
|
0. Click on the Actions tab and enable workflows in your repository
|
||||||
|
1. Click on the "Build UnityExplorer" workflow, then click "Run Workflow" and run it manually, or make a new commit to trigger the workflow.
|
||||||
|
2. Take the artifact from the completed run.
|
||||||
|
|
||||||
|
For Visual Studio:
|
||||||
|
|
||||||
0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
|
0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
|
||||||
1. Open the `src\UnityExplorer.sln` project in Visual Studio.
|
1. Open the `src\UnityExplorer.sln` project.
|
||||||
2. Select `Solution 'UnityExplorer' (1 of 1 project)` in the Solution Explorer panel, and set the <b>Active config</b> property to the version you want to build, then build it. Alternatively, use "Batch Build" and select all releases.
|
2. Build `mcs`, and if using IL2CPP then build `UnhollowerBaseLib` as well.
|
||||||
3. The DLLs are built to the `Release\` folder in the root of the repository.
|
3. Build the UnityExplorer release(s) you want to use, either by selecting the config as the Active Config, or batch-building.
|
||||||
4. If ILRepack complains about an error, just change the Active config to a different release and then back again. This sometimes happens for the first time you build the project.
|
|
||||||
|
|
||||||
## Acknowledgments
|
## Acknowledgments
|
||||||
|
|
||||||
|
Submodule lib/HarmonyX deleted from 64462b3e31
@ -113,10 +113,11 @@ namespace UnityExplorer.Core.Config
|
|||||||
"The delay on startup before the UI is created.",
|
"The delay on startup before the UI is created.",
|
||||||
1f);
|
1f);
|
||||||
|
|
||||||
Reflection_Signature_Blacklist = new ConfigElement<string>("Reflection Signature Blacklist",
|
Reflection_Signature_Blacklist = new ConfigElement<string>("Member Signature Blacklist",
|
||||||
"Use this to blacklist certain member signatures if they are known to cause a crash or other issues." +
|
"Use this to blacklist certain member signatures if they are known to cause a crash or other issues.\r\n" +
|
||||||
"\r\nSeperate signatures with a semicolon ';'.",
|
"Seperate signatures with a semicolon ';'.\r\n" +
|
||||||
"DEFAULT");
|
"For example, to blacklist Camera.main, you would add 'Camera.main;'",
|
||||||
|
"");
|
||||||
|
|
||||||
// Internal configs (panel save data)
|
// Internal configs (panel save data)
|
||||||
|
|
||||||
|
@ -32,16 +32,32 @@ namespace UnityExplorer
|
|||||||
public ExplorerBehaviour(IntPtr ptr) : base(ptr) { }
|
public ExplorerBehaviour(IntPtr ptr) : base(ptr) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private static bool onPostRenderFailed;
|
||||||
|
|
||||||
internal void Awake()
|
internal void Awake()
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
#if CPP
|
#if CPP
|
||||||
Camera.onPostRender = Camera.onPostRender == null
|
Camera.onPostRender = Camera.onPostRender == null
|
||||||
? new Action<Camera>(OnPostRender)
|
? new Action<Camera>(OnPostRender)
|
||||||
: Il2CppSystem.Delegate.Combine(Camera.onPostRender, (Camera.CameraCallback)new Action<Camera>(OnPostRender)).Cast<Camera.CameraCallback>();
|
: Il2CppSystem.Delegate.Combine(Camera.onPostRender,
|
||||||
|
(Camera.CameraCallback)new Action<Camera>(OnPostRender)).Cast<Camera.CameraCallback>();
|
||||||
|
|
||||||
|
if (Camera.onPostRender == null || Camera.onPostRender.delegates == null)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning("Failed to add Camera.onPostRender listener, falling back to LateUpdate instead!");
|
||||||
|
onPostRenderFailed = true;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
Camera.onPostRender += OnPostRender;
|
Camera.onPostRender += OnPostRender;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception adding onPostRender listener: {ex.ReflectionExToString()}\r\nFalling back to LateUpdate!");
|
||||||
|
onPostRenderFailed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Update()
|
internal void Update()
|
||||||
@ -54,7 +70,13 @@ namespace UnityExplorer
|
|||||||
ExplorerCore.FixedUpdate();
|
ExplorerCore.FixedUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void OnPostRender(Camera camera)
|
internal void LateUpdate()
|
||||||
|
{
|
||||||
|
if (onPostRenderFailed)
|
||||||
|
OnPostRender(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnPostRender(Camera _)
|
||||||
{
|
{
|
||||||
ExplorerCore.OnPostRender();
|
ExplorerCore.OnPostRender();
|
||||||
}
|
}
|
||||||
|
@ -62,13 +62,13 @@ namespace UnityExplorer.Core.Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame();
|
private static WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame();
|
||||||
|
|
||||||
private static IEnumerator AggressiveUnlockCoroutine()
|
private static IEnumerator AggressiveUnlockCoroutine()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
yield return _waitForEndOfFrame;
|
yield return _waitForEndOfFrame ?? (_waitForEndOfFrame = new WaitForEndOfFrame());
|
||||||
|
|
||||||
if (UIManager.ShowMenu)
|
if (UIManager.ShowMenu)
|
||||||
UpdateCursorControl();
|
UpdateCursorControl();
|
||||||
|
@ -515,12 +515,12 @@ namespace UnityExplorer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Il2cpp reflection blacklist
|
#region Il2cpp reflection blacklist
|
||||||
|
|
||||||
public override string DefaultReflectionBlacklist => string.Join(";", defaultIl2CppBlacklist);
|
public override string[] DefaultReflectionBlacklist => defaultIl2CppBlacklist.ToArray();
|
||||||
|
|
||||||
// These methods currently cause a crash in most il2cpp games,
|
// These methods currently cause a crash in most il2cpp games,
|
||||||
// even from doing "GetParameters()" on the MemberInfo.
|
// even from doing "GetParameters()" on the MemberInfo.
|
||||||
|
@ -12,7 +12,6 @@ using UnityExplorer.Core.Config;
|
|||||||
|
|
||||||
namespace UnityExplorer
|
namespace UnityExplorer
|
||||||
{
|
{
|
||||||
|
|
||||||
public class ReflectionUtility
|
public class ReflectionUtility
|
||||||
{
|
{
|
||||||
public const BF FLAGS = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
|
public const BF FLAGS = BF.Public | BF.Instance | BF.NonPublic | BF.Static;
|
||||||
@ -434,31 +433,44 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
#region Reflection Blacklist
|
#region Reflection Blacklist
|
||||||
|
|
||||||
public virtual string DefaultReflectionBlacklist => string.Empty;
|
public virtual string[] DefaultReflectionBlacklist => new string[0];
|
||||||
|
|
||||||
public static void LoadBlacklistString(string blacklist)
|
public static void LoadBlacklistString(string blacklist)
|
||||||
{
|
{
|
||||||
if (string.Equals(blacklist, "DEFAULT", StringComparison.InvariantCultureIgnoreCase))
|
try
|
||||||
{
|
{
|
||||||
blacklist = Instance.DefaultReflectionBlacklist;
|
if (string.IsNullOrEmpty(blacklist) && !Instance.DefaultReflectionBlacklist.Any())
|
||||||
ConfigManager.Reflection_Signature_Blacklist.Value = blacklist;
|
return;
|
||||||
ConfigManager.Handler.SaveConfig();
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sigs = blacklist.Split(';');
|
||||||
|
foreach (var sig in sigs)
|
||||||
|
{
|
||||||
|
var s = sig.Trim();
|
||||||
|
if (string.IsNullOrEmpty(s))
|
||||||
|
continue;
|
||||||
|
if (!currentBlacklist.Contains(s))
|
||||||
|
currentBlacklist.Add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning($"Exception parsing blacklist string: {ex.ReflectionExToString()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var sig in Instance.DefaultReflectionBlacklist)
|
||||||
|
{
|
||||||
|
if (!currentBlacklist.Contains(sig))
|
||||||
|
currentBlacklist.Add(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mono.CSharp.IL2CPP.Blacklist.SignatureBlacklist = currentBlacklist;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
if (string.IsNullOrEmpty(blacklist))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var sigs = blacklist.Split(';');
|
|
||||||
foreach (var sig in sigs)
|
|
||||||
{
|
{
|
||||||
var s = sig.Trim();
|
ExplorerCore.LogWarning($"Exception setting up reflection blacklist: {ex.ReflectionExToString()}");
|
||||||
if (string.IsNullOrEmpty(s))
|
|
||||||
continue;
|
|
||||||
if (!currentBlacklist.Contains(s))
|
|
||||||
currentBlacklist.Add(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono.CSharp.IL2CPP.Blacklist.SignatureBlacklist = currentBlacklist;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsBlacklisted(MemberInfo member)
|
public static bool IsBlacklisted(MemberInfo member)
|
||||||
|
@ -43,9 +43,9 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
ExplorerCore.LogUnity(condition, type);
|
ExplorerCore.LogUnity(condition, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void StartCoroutine(IEnumerator routine)
|
public override void Update()
|
||||||
{
|
{
|
||||||
Il2CppCoroutine.Start(routine);
|
Il2CppCoroutine.Process();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void ProcessOnPostRender()
|
internal override void ProcessOnPostRender()
|
||||||
@ -53,9 +53,14 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp
|
|||||||
Il2CppCoroutine.ProcessWaitForEndOfFrame();
|
Il2CppCoroutine.ProcessWaitForEndOfFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
internal override void ProcessFixedUpdate()
|
||||||
{
|
{
|
||||||
Il2CppCoroutine.Process();
|
Il2CppCoroutine.ProcessWaitForFixedUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void StartCoroutine(IEnumerator routine)
|
||||||
|
{
|
||||||
|
Il2CppCoroutine.Start(routine);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override T AddComponent<T>(GameObject obj, Type type)
|
public override T AddComponent<T>(GameObject obj, Type type)
|
||||||
|
@ -20,7 +20,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.0.7";
|
public const string VERSION = "4.1.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";
|
||||||
|
|
||||||
|
@ -11,18 +11,17 @@
|
|||||||
|
|
||||||
<!-- MonoMod for MelonLoader 0.3.0 -->
|
<!-- MonoMod for MelonLoader 0.3.0 -->
|
||||||
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
|
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
|
||||||
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\Mono.Cecil.dll" />
|
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.dll" />
|
||||||
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\Mono.Cecil.Mdb.dll" />
|
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Mdb.dll" />
|
||||||
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\Mono.Cecil.Pdb.dll" />
|
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Pdb.dll" />
|
||||||
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\Mono.Cecil.Rocks.dll" />
|
<InputAssemblies Include="packages\Mono.Cecil.0.10.4\lib\net35\Mono.Cecil.Rocks.dll" />
|
||||||
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\MonoMod.RuntimeDetour.dll" />
|
<InputAssemblies Include="packages\MonoMod.RuntimeDetour.20.1.1.4\lib\net35\MonoMod.RuntimeDetour.dll" />
|
||||||
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\MonoMod.Utils.dll" />
|
<InputAssemblies Include="packages\MonoMod.Utils.20.1.1.4\lib\net35\MonoMod.Utils.dll" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Required references for ILRepack -->
|
<!-- Required references for ILRepack -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ReferenceFolders Include="..\lib\" />
|
<ReferenceFolders Include="packages\HarmonyX.2.4.2\lib\net35\" />
|
||||||
<ReferenceFolders Include="..\lib\HarmonyX\Harmony\bin\Release\net35\" />
|
|
||||||
<ReferenceFolders Include="..\lib\BepInEx.6.IL2CPP\" />
|
<ReferenceFolders Include="..\lib\BepInEx.6.IL2CPP\" />
|
||||||
<ReferenceFolders Include="..\lib\BepInEx.6.Mono\" />
|
<ReferenceFolders Include="..\lib\BepInEx.6.Mono\" />
|
||||||
<ReferenceFolders Include="..\lib\BepInEx.5\" />
|
<ReferenceFolders Include="..\lib\BepInEx.5\" />
|
||||||
@ -36,7 +35,8 @@
|
|||||||
LibraryPath="@(ReferenceFolders)"
|
LibraryPath="@(ReferenceFolders)"
|
||||||
InputAssemblies="@(InputAssemblies)"
|
InputAssemblies="@(InputAssemblies)"
|
||||||
TargetKind="Dll"
|
TargetKind="Dll"
|
||||||
OutputFile="$(OutputPath)$(AssemblyName).dll" />
|
OutputFile="$(OutputPath)$(AssemblyName).dll"
|
||||||
|
/>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -28,10 +28,11 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
object ret;
|
||||||
if (HasArguments)
|
if (HasArguments)
|
||||||
return PropertyInfo.GetValue(DeclaringInstance, this.Evaluator.TryParseArguments());
|
ret = PropertyInfo.GetValue(DeclaringInstance, this.Evaluator.TryParseArguments());
|
||||||
|
else
|
||||||
var ret = PropertyInfo.GetValue(DeclaringInstance, null);
|
ret = PropertyInfo.GetValue(DeclaringInstance, null);
|
||||||
HadException = false;
|
HadException = false;
|
||||||
LastException = null;
|
LastException = null;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -480,7 +480,7 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
private void SetUnityTargets()
|
private void SetUnityTargets()
|
||||||
{
|
{
|
||||||
if (!typeof(UnityEngine.Object).IsAssignableFrom(TargetType))
|
if (StaticOnly || !typeof(UnityEngine.Object).IsAssignableFrom(TargetType))
|
||||||
{
|
{
|
||||||
unityObjectRow.SetActive(false);
|
unityObjectRow.SetActive(false);
|
||||||
textureViewer.SetActive(false);
|
textureViewer.SetActive(false);
|
||||||
@ -617,12 +617,15 @@ namespace UnityExplorer.UI.Inspectors
|
|||||||
|
|
||||||
// Actual texture viewer
|
// Actual texture viewer
|
||||||
|
|
||||||
var imageObj = UIFactory.CreateUIObject("TextureViewerImage", textureViewer);
|
var imageViewport = UIFactory.CreateVerticalGroup(textureViewer, "Viewport", false, false, true, true);
|
||||||
textureImage = imageObj.AddComponent<Image>();
|
imageViewport.GetComponent<Image>().color = Color.white;
|
||||||
textureImageLayout = textureImage.gameObject.AddComponent<LayoutElement>();
|
imageViewport.AddComponent<Mask>().showMaskGraphic = false;
|
||||||
|
|
||||||
|
var imageObj = UIFactory.CreateUIObject("Image", imageViewport);
|
||||||
var fitter = imageObj.AddComponent<ContentSizeFitter>();
|
var fitter = imageObj.AddComponent<ContentSizeFitter>();
|
||||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||||
|
textureImage = imageObj.AddComponent<Image>();
|
||||||
|
textureImageLayout = UIFactory.SetLayoutElement(imageObj, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||||
|
|
||||||
textureViewer.SetActive(false);
|
textureViewer.SetActive(false);
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,8 @@ namespace UnityExplorer.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TextGenerator TextGenerator => Component.cachedInputTextGenerator;
|
public TextGenerator TextGenerator => Component.cachedInputTextGenerator;
|
||||||
public bool ReachedMaxVerts => TextGenerator.vertexCount >= UIManager.MAX_TEXT_VERTS;
|
|
||||||
|
|
||||||
|
public bool ReachedMaxVerts => TextGenerator.vertexCount >= UIManager.MAX_TEXT_VERTS;
|
||||||
|
|
||||||
private void OnInputChanged(string value)
|
private void OnInputChanged(string value)
|
||||||
{
|
{
|
||||||
|
@ -15,16 +15,16 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static Scene? SelectedScene
|
public static Scene? SelectedScene
|
||||||
{
|
{
|
||||||
get => m_selectedScene;
|
get => selectedScene;
|
||||||
internal set
|
internal set
|
||||||
{
|
{
|
||||||
if (m_selectedScene != null && m_selectedScene == value)
|
if (selectedScene != null && selectedScene == value)
|
||||||
return;
|
return;
|
||||||
m_selectedScene = value;
|
selectedScene = value;
|
||||||
OnInspectedSceneChanged?.Invoke((Scene)m_selectedScene);
|
OnInspectedSceneChanged?.Invoke((Scene)selectedScene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static Scene? m_selectedScene;
|
private static Scene? selectedScene;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The GameObjects in the currently inspected scene.
|
/// The GameObjects in the currently inspected scene.
|
||||||
@ -62,7 +62,7 @@ namespace UnityExplorer.UI.ObjectExplorer
|
|||||||
public static event Action<ReadOnlyCollection<Scene>> OnLoadedScenesChanged;
|
public static event Action<ReadOnlyCollection<Scene>> OnLoadedScenesChanged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Equivalent to <see cref="SceneManager.sceneCount"/> + 2, to include 'DontDestroyOnLoad'.
|
/// Equivalent to <see cref="SceneManager.sceneCount"/> + 2, to include 'DontDestroyOnLoad' and the 'None' scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static int LoadedSceneCount => SceneManager.sceneCount + 2;
|
public static int LoadedSceneCount => SceneManager.sceneCount + 2;
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ namespace UnityExplorer.UI.Panels
|
|||||||
{
|
{
|
||||||
// create navbar button
|
// create navbar button
|
||||||
|
|
||||||
NavButton = UIFactory.CreateButton(UIManager.NavbarButtonHolder, $"Button_{PanelType}", Name);
|
NavButton = UIFactory.CreateButton(UIManager.NavbarTabButtonHolder, $"Button_{PanelType}", Name);
|
||||||
var navBtn = NavButton.Component.gameObject;
|
var navBtn = NavButton.Component.gameObject;
|
||||||
navBtn.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
navBtn.AddComponent<ContentSizeFitter>().horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navBtn, false, true, true, true, 0, 0, 0, 5, 5, TextAnchor.MiddleCenter);
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navBtn, false, true, true, true, 0, 0, 0, 5, 5, TextAnchor.MiddleCenter);
|
||||||
|
@ -55,9 +55,15 @@ namespace UnityExplorer.UI
|
|||||||
internal static Shader BackupShader { get; private set; }
|
internal static Shader BackupShader { get; private set; }
|
||||||
|
|
||||||
public static RectTransform NavBarRect;
|
public static RectTransform NavBarRect;
|
||||||
public static GameObject NavbarButtonHolder;
|
public static GameObject NavbarTabButtonHolder;
|
||||||
public static Dropdown MouseInspectDropdown;
|
public static Dropdown MouseInspectDropdown;
|
||||||
|
|
||||||
|
private static ButtonRef closeBtn;
|
||||||
|
private static ButtonRef pauseBtn;
|
||||||
|
private static InputFieldRef timeInput;
|
||||||
|
private static bool pauseButtonPausing;
|
||||||
|
private static float lastTimeScale;
|
||||||
|
|
||||||
// defaults
|
// defaults
|
||||||
internal static readonly Color enabledButtonColor = new Color(0.2f, 0.4f, 0.28f);
|
internal static readonly Color enabledButtonColor = new Color(0.2f, 0.4f, 0.28f);
|
||||||
internal static readonly Color disabledButtonColor = new Color(0.25f, 0.25f, 0.25f);
|
internal static readonly Color disabledButtonColor = new Color(0.25f, 0.25f, 0.25f);
|
||||||
@ -80,6 +86,105 @@ namespace UnityExplorer.UI
|
|||||||
}
|
}
|
||||||
public static bool s_showMenu = true;
|
public static bool s_showMenu = true;
|
||||||
|
|
||||||
|
// Initialization
|
||||||
|
|
||||||
|
internal static void InitUI()
|
||||||
|
{
|
||||||
|
LoadBundle();
|
||||||
|
|
||||||
|
UIFactory.Init();
|
||||||
|
|
||||||
|
CreateRootCanvas();
|
||||||
|
|
||||||
|
// Global UI Pool Holder
|
||||||
|
PoolHolder = new GameObject("PoolHolder");
|
||||||
|
PoolHolder.transform.parent = CanvasRoot.transform;
|
||||||
|
PoolHolder.SetActive(false);
|
||||||
|
|
||||||
|
CreateTopNavBar();
|
||||||
|
|
||||||
|
UIPanels.Add(Panels.AutoCompleter, new AutoCompleteModal());
|
||||||
|
UIPanels.Add(Panels.ObjectExplorer, new ObjectExplorerPanel());
|
||||||
|
UIPanels.Add(Panels.Inspector, new InspectorPanel());
|
||||||
|
UIPanels.Add(Panels.CSConsole, new CSConsolePanel());
|
||||||
|
UIPanels.Add(Panels.ConsoleLog, new LogPanel());
|
||||||
|
UIPanels.Add(Panels.Options, new OptionsPanel());
|
||||||
|
UIPanels.Add(Panels.MouseInspector, new InspectUnderMouse());
|
||||||
|
|
||||||
|
foreach (var panel in UIPanels.Values)
|
||||||
|
panel.ConstructUI();
|
||||||
|
|
||||||
|
ConsoleController.Init();
|
||||||
|
|
||||||
|
ShowMenu = !ConfigManager.Hide_On_Startup.Value;
|
||||||
|
|
||||||
|
lastScreenWidth = Screen.width;
|
||||||
|
lastScreenHeight = Screen.height;
|
||||||
|
|
||||||
|
Initializing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main UI Update loop
|
||||||
|
|
||||||
|
private static int lastScreenWidth;
|
||||||
|
private static int lastScreenHeight;
|
||||||
|
|
||||||
|
public static void Update()
|
||||||
|
{
|
||||||
|
if (!CanvasRoot || Initializing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// if doing Mouse Inspect, update that and return.
|
||||||
|
if (InspectUnderMouse.Inspecting)
|
||||||
|
{
|
||||||
|
InspectUnderMouse.Instance.UpdateInspect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check master toggle
|
||||||
|
if (InputManager.GetKeyDown(ConfigManager.Master_Toggle.Value))
|
||||||
|
ShowMenu = !ShowMenu;
|
||||||
|
|
||||||
|
// return if menu closed
|
||||||
|
if (!ShowMenu)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check forceUnlockMouse toggle
|
||||||
|
if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value))
|
||||||
|
CursorUnlocker.Unlock = !CursorUnlocker.Unlock;
|
||||||
|
|
||||||
|
// check event system state
|
||||||
|
if (!ConfigManager.Disable_EventSystem_Override.Value && EventSystem.current != EventSys)
|
||||||
|
CursorUnlocker.SetEventSystem();
|
||||||
|
|
||||||
|
// update focused panel
|
||||||
|
UIPanel.UpdateFocus();
|
||||||
|
// update UI model instances
|
||||||
|
PanelDragger.UpdateInstances();
|
||||||
|
InputFieldRef.UpdateInstances();
|
||||||
|
UIBehaviourModel.UpdateInstances();
|
||||||
|
|
||||||
|
// update the timescale value
|
||||||
|
if (!timeInput.Component.isFocused && lastTimeScale != Time.timeScale)
|
||||||
|
{
|
||||||
|
if (pauseButtonPausing && Time.timeScale != 0.0f)
|
||||||
|
{
|
||||||
|
pauseButtonPausing = false;
|
||||||
|
OnPauseButtonToggled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pauseButtonPausing)
|
||||||
|
{
|
||||||
|
timeInput.Text = Time.timeScale.ToString("F2");
|
||||||
|
lastTimeScale = Time.timeScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check screen dimension change
|
||||||
|
if (Screen.width != lastScreenWidth || Screen.height != lastScreenHeight)
|
||||||
|
OnScreenDimensionsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
// Panels
|
// Panels
|
||||||
|
|
||||||
public static UIPanel GetPanel(Panels panel)
|
public static UIPanel GetPanel(Panels panel)
|
||||||
@ -120,91 +225,89 @@ namespace UnityExplorer.UI
|
|||||||
SetPanelActive(panel, value);
|
SetPanelActive(panel, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main UI Update loop
|
// navbar
|
||||||
|
|
||||||
private static int lastScreenWidth;
|
public static void SetNavBarAnchor()
|
||||||
private static int lastScreenHeight;
|
|
||||||
|
|
||||||
public static void Update()
|
|
||||||
{
|
{
|
||||||
if (!CanvasRoot || Initializing)
|
switch (NavbarAnchor)
|
||||||
return;
|
|
||||||
|
|
||||||
if (InspectUnderMouse.Inspecting)
|
|
||||||
{
|
{
|
||||||
InspectUnderMouse.Instance.UpdateInspect();
|
case VerticalAnchor.Top:
|
||||||
return;
|
NavBarRect.anchorMin = new Vector2(0.5f, 1f);
|
||||||
}
|
NavBarRect.anchorMax = new Vector2(0.5f, 1f);
|
||||||
|
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 0);
|
||||||
|
NavBarRect.sizeDelta = new Vector2(1000f, 35f);
|
||||||
|
break;
|
||||||
|
|
||||||
if (InputManager.GetKeyDown(ConfigManager.Master_Toggle.Value))
|
case VerticalAnchor.Bottom:
|
||||||
ShowMenu = !ShowMenu;
|
NavBarRect.anchorMin = new Vector2(0.5f, 0f);
|
||||||
|
NavBarRect.anchorMax = new Vector2(0.5f, 0f);
|
||||||
if (!ShowMenu)
|
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 35);
|
||||||
return;
|
NavBarRect.sizeDelta = new Vector2(1000f, 35f);
|
||||||
|
break;
|
||||||
if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value))
|
|
||||||
CursorUnlocker.Unlock = !CursorUnlocker.Unlock;
|
|
||||||
|
|
||||||
if (!ConfigManager.Disable_EventSystem_Override.Value && EventSystem.current != EventSys)
|
|
||||||
CursorUnlocker.SetEventSystem();
|
|
||||||
|
|
||||||
UIPanel.UpdateFocus();
|
|
||||||
PanelDragger.UpdateInstances();
|
|
||||||
InputFieldRef.UpdateInstances();
|
|
||||||
UIBehaviourModel.UpdateInstances();
|
|
||||||
|
|
||||||
if (Screen.width != lastScreenWidth || Screen.height != lastScreenHeight)
|
|
||||||
{
|
|
||||||
lastScreenWidth = Screen.width;
|
|
||||||
lastScreenHeight = Screen.height;
|
|
||||||
|
|
||||||
foreach (var panel in UIPanels)
|
|
||||||
{
|
|
||||||
panel.Value.EnsureValidSize();
|
|
||||||
UIPanel.EnsureValidPosition(panel.Value.Rect);
|
|
||||||
panel.Value.Dragger.OnEndResize();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialization and UI Construction
|
// listeners
|
||||||
|
|
||||||
internal static void InitUI()
|
private static void OnScreenDimensionsChanged()
|
||||||
{
|
{
|
||||||
LoadBundle();
|
|
||||||
|
|
||||||
UIFactory.Init();
|
|
||||||
|
|
||||||
CreateRootCanvas();
|
|
||||||
|
|
||||||
// Global UI Pool Holder
|
|
||||||
PoolHolder = new GameObject("PoolHolder");
|
|
||||||
PoolHolder.transform.parent = CanvasRoot.transform;
|
|
||||||
PoolHolder.SetActive(false);
|
|
||||||
|
|
||||||
CreateTopNavBar();
|
|
||||||
|
|
||||||
UIPanels.Add(Panels.AutoCompleter, new AutoCompleteModal());
|
|
||||||
UIPanels.Add(Panels.ObjectExplorer, new ObjectExplorerPanel());
|
|
||||||
UIPanels.Add(Panels.Inspector, new InspectorPanel());
|
|
||||||
UIPanels.Add(Panels.CSConsole, new CSConsolePanel());
|
|
||||||
UIPanels.Add(Panels.ConsoleLog, new LogPanel());
|
|
||||||
UIPanels.Add(Panels.Options, new OptionsPanel());
|
|
||||||
UIPanels.Add(Panels.MouseInspector, new InspectUnderMouse());
|
|
||||||
|
|
||||||
foreach (var panel in UIPanels.Values)
|
|
||||||
panel.ConstructUI();
|
|
||||||
|
|
||||||
ConsoleController.Init();
|
|
||||||
|
|
||||||
ShowMenu = !ConfigManager.Hide_On_Startup.Value;
|
|
||||||
|
|
||||||
lastScreenWidth = Screen.width;
|
lastScreenWidth = Screen.width;
|
||||||
lastScreenHeight = Screen.height;
|
lastScreenHeight = Screen.height;
|
||||||
|
|
||||||
Initializing = false;
|
foreach (var panel in UIPanels)
|
||||||
|
{
|
||||||
|
panel.Value.EnsureValidSize();
|
||||||
|
UIPanel.EnsureValidPosition(panel.Value.Rect);
|
||||||
|
panel.Value.Dragger.OnEndResize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void OnCloseButtonClicked()
|
||||||
|
{
|
||||||
|
ShowMenu = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Master_Toggle_OnValueChanged(KeyCode val)
|
||||||
|
{
|
||||||
|
closeBtn.ButtonText.text = val.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnTimeInputEndEdit(string val)
|
||||||
|
{
|
||||||
|
if (pauseButtonPausing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (float.TryParse(val, out float f))
|
||||||
|
{
|
||||||
|
Time.timeScale = f;
|
||||||
|
lastTimeScale = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeInput.Text = Time.timeScale.ToString("F2");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnPauseButtonClicked()
|
||||||
|
{
|
||||||
|
pauseButtonPausing = !pauseButtonPausing;
|
||||||
|
|
||||||
|
Time.timeScale = pauseButtonPausing ? 0f : lastTimeScale;
|
||||||
|
|
||||||
|
OnPauseButtonToggled();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnPauseButtonToggled()
|
||||||
|
{
|
||||||
|
timeInput.Component.text = Time.timeScale.ToString("F2");
|
||||||
|
timeInput.Component.readOnly = pauseButtonPausing;
|
||||||
|
timeInput.Component.textComponent.color = pauseButtonPausing ? Color.grey : Color.white;
|
||||||
|
|
||||||
|
Color color = pauseButtonPausing ? new Color(0.3f, 0.3f, 0.2f) : new Color(0.2f, 0.2f, 0.2f);
|
||||||
|
RuntimeProvider.Instance.SetColorBlock(pauseBtn.Component, color, color * 1.2f, color * 0.7f);
|
||||||
|
pauseBtn.ButtonText.text = pauseButtonPausing ? "►" : "||";
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI Construction
|
||||||
|
|
||||||
private static void CreateRootCanvas()
|
private static void CreateRootCanvas()
|
||||||
{
|
{
|
||||||
CanvasRoot = new GameObject("ExplorerCanvas");
|
CanvasRoot = new GameObject("ExplorerCanvas");
|
||||||
@ -239,30 +342,10 @@ namespace UnityExplorer.UI
|
|||||||
PanelHolder.transform.SetAsFirstSibling();
|
PanelHolder.transform.SetAsFirstSibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetNavBarAnchor()
|
|
||||||
{
|
|
||||||
switch (NavbarAnchor)
|
|
||||||
{
|
|
||||||
case VerticalAnchor.Top:
|
|
||||||
NavBarRect.anchorMin = new Vector2(0.5f, 1f);
|
|
||||||
NavBarRect.anchorMax = new Vector2(0.5f, 1f);
|
|
||||||
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 0);
|
|
||||||
NavBarRect.sizeDelta = new Vector2(900f, 35f);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VerticalAnchor.Bottom:
|
|
||||||
NavBarRect.anchorMin = new Vector2(0.5f, 0f);
|
|
||||||
NavBarRect.anchorMax = new Vector2(0.5f, 0f);
|
|
||||||
NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 35);
|
|
||||||
NavBarRect.sizeDelta = new Vector2(900f, 35f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CreateTopNavBar()
|
private static void CreateTopNavBar()
|
||||||
{
|
{
|
||||||
var navbarPanel = UIFactory.CreateUIObject("MainNavbar", CanvasRoot);
|
var navbarPanel = UIFactory.CreateUIObject("MainNavbar", CanvasRoot);
|
||||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navbarPanel, false, true, true, true, 5, 4, 4, 4, 4, TextAnchor.MiddleCenter);
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(navbarPanel, false, false, true, true, 5, 4, 4, 4, 4, TextAnchor.MiddleCenter);
|
||||||
navbarPanel.AddComponent<Image>().color = new Color(0.1f, 0.1f, 0.1f);
|
navbarPanel.AddComponent<Image>().color = new Color(0.1f, 0.1f, 0.1f);
|
||||||
NavBarRect = navbarPanel.GetComponent<RectTransform>();
|
NavBarRect = navbarPanel.GetComponent<RectTransform>();
|
||||||
NavBarRect.pivot = new Vector2(0.5f, 1f);
|
NavBarRect.pivot = new Vector2(0.5f, 1f);
|
||||||
@ -278,14 +361,28 @@ namespace UnityExplorer.UI
|
|||||||
// UnityExplorer title
|
// UnityExplorer title
|
||||||
|
|
||||||
string titleTxt = $"{ExplorerCore.NAME} <i><color=grey>{ExplorerCore.VERSION}</color></i>";
|
string titleTxt = $"{ExplorerCore.NAME} <i><color=grey>{ExplorerCore.VERSION}</color></i>";
|
||||||
var title = UIFactory.CreateLabel(navbarPanel, "Title", titleTxt, TextAnchor.MiddleLeft, default, true, 18);
|
var title = UIFactory.CreateLabel(navbarPanel, "Title", titleTxt, TextAnchor.MiddleLeft, default, true, 17);
|
||||||
UIFactory.SetLayoutElement(title.gameObject, minWidth: 180, flexibleWidth: 0);
|
UIFactory.SetLayoutElement(title.gameObject, minWidth: 170, flexibleWidth: 0);
|
||||||
|
|
||||||
// Navbar
|
// panel tabs
|
||||||
|
|
||||||
NavbarButtonHolder = UIFactory.CreateUIObject("NavButtonHolder", navbarPanel);
|
NavbarTabButtonHolder = UIFactory.CreateUIObject("NavTabButtonHolder", navbarPanel);
|
||||||
UIFactory.SetLayoutElement(NavbarButtonHolder, flexibleHeight: 999, flexibleWidth: 999);
|
UIFactory.SetLayoutElement(NavbarTabButtonHolder, minHeight: 25, flexibleHeight: 999, flexibleWidth: 999);
|
||||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(NavbarButtonHolder, false, true, true, true, 4, 2, 2, 2, 2);
|
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(NavbarTabButtonHolder, false, true, true, true, 4, 2, 2, 2, 2);
|
||||||
|
|
||||||
|
// Time controls
|
||||||
|
|
||||||
|
var timeLabel = UIFactory.CreateLabel(navbarPanel, "TimeLabel", "Time:", TextAnchor.MiddleRight, Color.grey);
|
||||||
|
UIFactory.SetLayoutElement(timeLabel.gameObject, minHeight: 25, minWidth: 50);
|
||||||
|
|
||||||
|
timeInput = UIFactory.CreateInputField(navbarPanel, "TimeInput", "timeScale");
|
||||||
|
UIFactory.SetLayoutElement(timeInput.Component.gameObject, minHeight: 25, minWidth: 40);
|
||||||
|
timeInput.Text = Time.timeScale.ToString("F2");
|
||||||
|
timeInput.Component.onEndEdit.AddListener(OnTimeInputEndEdit);
|
||||||
|
|
||||||
|
pauseBtn = UIFactory.CreateButton(navbarPanel, "PauseButton", "||", new Color(0.2f, 0.2f, 0.2f));
|
||||||
|
UIFactory.SetLayoutElement(pauseBtn.Component.gameObject, minHeight: 25, minWidth: 25);
|
||||||
|
pauseBtn.OnClick += OnPauseButtonClicked;
|
||||||
|
|
||||||
// Inspect under mouse dropdown
|
// Inspect under mouse dropdown
|
||||||
|
|
||||||
@ -298,14 +395,13 @@ namespace UnityExplorer.UI
|
|||||||
|
|
||||||
// Hide menu button
|
// Hide menu button
|
||||||
|
|
||||||
var closeBtn = UIFactory.CreateButton(navbarPanel, "CloseButton", ConfigManager.Master_Toggle.Value.ToString());
|
closeBtn = UIFactory.CreateButton(navbarPanel, "CloseButton", ConfigManager.Master_Toggle.Value.ToString());
|
||||||
UIFactory.SetLayoutElement(closeBtn.Component.gameObject, minHeight: 25, minWidth: 80, flexibleWidth: 0);
|
UIFactory.SetLayoutElement(closeBtn.Component.gameObject, minHeight: 25, minWidth: 80, flexibleWidth: 0);
|
||||||
RuntimeProvider.Instance.SetColorBlock(closeBtn.Component, new Color(0.63f, 0.32f, 0.31f),
|
RuntimeProvider.Instance.SetColorBlock(closeBtn.Component, new Color(0.63f, 0.32f, 0.31f),
|
||||||
new Color(0.81f, 0.25f, 0.2f), new Color(0.6f, 0.18f, 0.16f));
|
new Color(0.81f, 0.25f, 0.2f), new Color(0.6f, 0.18f, 0.16f));
|
||||||
|
|
||||||
ConfigManager.Master_Toggle.OnValueChanged += (KeyCode val) => { closeBtn.ButtonText.text = val.ToString(); };
|
ConfigManager.Master_Toggle.OnValueChanged += Master_Toggle_OnValueChanged;
|
||||||
|
closeBtn.OnClick += OnCloseButtonClicked;
|
||||||
closeBtn.OnClick += () => { ShowMenu = false; };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region UI AssetBundle
|
#region UI AssetBundle
|
||||||
|
@ -193,13 +193,12 @@ namespace UnityExplorer.UI.Widgets
|
|||||||
RuntimeProvider.Instance.StartCoroutine(InitCoroutine(onHeightChangedListener));
|
RuntimeProvider.Instance.StartCoroutine(InitCoroutine(onHeightChangedListener));
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
|
private WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame();
|
||||||
|
|
||||||
private IEnumerator InitCoroutine(Action onHeightChangedListener)
|
private IEnumerator InitCoroutine(Action onHeightChangedListener)
|
||||||
{
|
{
|
||||||
ScrollRect.content.anchoredPosition = Vector2.zero;
|
ScrollRect.content.anchoredPosition = Vector2.zero;
|
||||||
//yield return null;
|
yield return waitForEndOfFrame ?? (waitForEndOfFrame = new WaitForEndOfFrame());
|
||||||
yield return waitForEndOfFrame;
|
|
||||||
|
|
||||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||||
|
|
||||||
|
@ -143,12 +143,12 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- BepInEx universal refs -->
|
<!-- BepInEx universal refs -->
|
||||||
<ItemGroup Condition="'$(IsBepInEx)'=='true'">
|
<ItemGroup Condition="'$(IsBepInEx)'=='true'">
|
||||||
<Reference Include="0Harmony">
|
<Reference Include="0Harmony">
|
||||||
<HintPath>..\lib\HarmonyX\Harmony\bin\Release\net35\0Harmony.dll</HintPath>
|
<HintPath>packages\HarmonyX.2.4.2\lib\net35\0Harmony.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- BepInEx 5 Mono refs -->
|
<!-- BepInEx 5 Mono refs -->
|
||||||
<ItemGroup Condition="'$(IsBepInEx)|$(IsCpp)|$(Configuration)'=='true|false|Release_BIE5_Mono'">
|
<ItemGroup Condition="'$(IsBepInEx)|$(IsCpp)|$(Configuration)'=='true|false|Release_BIE5_Mono'">
|
||||||
<Reference Include="BepInEx">
|
<Reference Include="BepInEx">
|
||||||
@ -180,10 +180,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- Standalone refs -->
|
<!-- Standalone refs -->
|
||||||
<ItemGroup Condition="'$(IsStandalone)'=='true'">
|
<ItemGroup Condition="'$(IsStandalone)'=='true'">
|
||||||
<Reference Include="0Harmony">
|
<Reference Include="0Harmony">
|
||||||
<HintPath>..\lib\HarmonyX\Harmony\bin\Release\net35\0Harmony.dll</HintPath>
|
<HintPath>packages\HarmonyX.2.4.2\lib\net35\0Harmony.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- Mono refs -->
|
<!-- Mono refs -->
|
||||||
<ItemGroup Condition="'$(IsCpp)'=='false'">
|
<ItemGroup Condition="'$(IsCpp)'=='false'">
|
||||||
@ -366,11 +366,11 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets" Condition="Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets')" />
|
<Import Project="packages\ILRepack.Lib.MSBuild.Task.2.0.18.2\build\ILRepack.Lib.MSBuild.Task.targets" Condition="Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.2\build\ILRepack.Lib.MSBuild.Task.targets')" />
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Error Condition="!Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\ILRepack.Lib.MSBuild.Task.2.0.18.1\build\ILRepack.Lib.MSBuild.Task.targets'))" />
|
<Error Condition="!Exists('packages\ILRepack.Lib.MSBuild.Task.2.0.18.2\build\ILRepack.Lib.MSBuild.Task.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\ILRepack.Lib.MSBuild.Task.2.0.18.2\build\ILRepack.Lib.MSBuild.Task.targets'))" />
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 16
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 16.0.30128.74
|
VisualStudioVersion = 16.0.30128.74
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Harmony", "..\lib\HarmonyX\Harmony\Harmony.csproj", "{F2D7872C-5D4D-49EB-A656-C3D496DB4204}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnhollowerBaseLib", "..\lib\Il2CppAssemblyUnhollower\UnhollowerBaseLib\UnhollowerBaseLib.csproj", "{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnhollowerBaseLib", "..\lib\Il2CppAssemblyUnhollower\UnhollowerBaseLib\UnhollowerBaseLib.csproj", "{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mcs", "..\lib\mcs-unity\mcs\mcs.csproj", "{E4989E4C-0875-4528-9031-08E2C0E70103}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mcs", "..\lib\mcs-unity\mcs\mcs.csproj", "{E4989E4C-0875-4528-9031-08E2C0E70103}"
|
||||||
@ -24,24 +22,6 @@ Global
|
|||||||
Release_STANDALONE_Mono|Any CPU = Release_STANDALONE_Mono|Any CPU
|
Release_STANDALONE_Mono|Any CPU = Release_STANDALONE_Mono|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_BIE_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_BIE_Cpp|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_BIE5_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_BIE5_Mono|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_BIE6_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_BIE6_Mono|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_ML_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_ML_Cpp|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_ML_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_ML_Mono|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_MLLegacy_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_MLLegacy_Cpp|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_MLLegacy_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_MLLegacy_Mono|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_STANDALONE_Mono|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_BIE_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_BIE_Cpp|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_BIE_Cpp|Any CPU.Build.0 = Release|Any CPU
|
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_BIE_Cpp|Any CPU.Build.0 = Release|Any CPU
|
||||||
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_BIE5_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_BIE5_Mono|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="ILRepack.Lib.MSBuild.Task" version="2.0.18.1" targetFramework="net472" />
|
<package id="HarmonyX" version="2.4.2" targetFramework="net35" />
|
||||||
|
<package id="ILRepack.Lib.MSBuild.Task" version="2.0.18.2" targetFramework="net35" />
|
||||||
<package id="ini-parser" version="2.5.2" targetFramework="net35" />
|
<package id="ini-parser" version="2.5.2" targetFramework="net35" />
|
||||||
|
<package id="Mono.Cecil" version="0.10.4" targetFramework="net35" />
|
||||||
</packages>
|
</packages>
|
Reference in New Issue
Block a user