Compare commits

...

20 Commits
4.0.3 ... 4.0.6

Author SHA1 Message Date
b0bbeb3cf8 Cleanup and fix small issue with JumpToIndex 2021-05-26 18:32:47 +10:00
1a26623080 Add option to disable EventSystem override 2021-05-26 18:02:10 +10:00
041f2938f7 Implement jumping to index in TransformTree 2021-05-26 17:42:31 +10:00
9e7bb1a625 Cleanup 2021-05-26 17:42:14 +10:00
36f23b7cdc Move SceneHandler.cs 2021-05-26 17:41:51 +10:00
b51b743df4 Prevent very niche recursion situation 2021-05-26 17:41:38 +10:00
805aff07cc Update README.md 2021-05-26 17:41:19 +10:00
bcdaf3b97e Bump version 2021-05-26 17:41:14 +10:00
cb8e947fdf Namespace/structure cleanup 2021-05-26 17:40:09 +10:00
c8899be3ae Bump version 2021-05-26 03:59:50 +10:00
cd5c69c965 Add timer debug to deobfuscation cache 2021-05-26 03:59:45 +10:00
5427312f18 Filter UnityExplorer objects from search results 2021-05-26 03:59:17 +10:00
eb7e80d910 Make sure Mouse Inspect dropdown list gets destroyed after option chosen 2021-05-26 03:59:08 +10:00
a54888ae3a Make DataViewInfo a struct instead of class 2021-05-25 15:46:30 +10:00
4f0553d293 Remove formatting from ToStringUtility 2021-05-23 19:34:32 +10:00
9f0f7f9b57 Prevent some niche exceptions with EventSystem 2021-05-23 18:33:19 +10:00
383c6f19e8 Update README.md 2021-05-23 16:20:09 +10:00
428fab28f9 Cleanup HideAndDontSave detection and support 2021-05-23 16:16:32 +10:00
760b2981ad Update README.md 2021-05-23 13:59:29 +10:00
eee7d6bcc4 Add ML 0.3.0 build 2021-05-23 13:58:26 +10:00
58 changed files with 538 additions and 295 deletions

View File

@ -17,13 +17,13 @@
| [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) |
| [BepInEx](https://github.com/BepInEx/BepInEx) 5.X | ✖️ n/a | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx5.Mono.zip) | | [BepInEx](https://github.com/BepInEx/BepInEx) 5.X | ✖️ n/a | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.BepInEx5.Mono.zip) |
| [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3.1 | ✅ [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) | | [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3.1 | ✅ [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) |
| [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) |
### 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.
* The C# console may unexpectedly produce a GC Mark Overflow crash when calling certain outside methods. Not clear yet what is causing this, but it's being looked into.
* 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.
* In IL2CPP, the C# console might not suggest deobfuscated (or obfuscated) names. Being looked into. * The C# Console's completions have some minor issues such as not suggestion global classes which have no namespace, and erronously suggesting classes from using directives when they shouldn't be suggested. These are issues with mcs itself which I am looking into.
## How to install ## How to install
@ -36,7 +36,7 @@
### MelonLoader ### MelonLoader
1. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3.1+ for your game. This version can currently be obtained from [here](https://github.com/LavaGang/MelonLoader/actions). 1. Install [MelonLoader](https://github.com/HerpDerpinstine/MelonLoader) 0.3.1+ for your game (or use `MelonLoader_Legacy` for `0.3.0`). This version can currently be obtained from [here](https://github.com/LavaGang/MelonLoader/actions).
2. Download the UnityExplorer release for MelonLoader IL2CPP or Mono above. 2. Download the UnityExplorer release for MelonLoader IL2CPP or Mono above.
3. Take the `UnityExplorer.ML.___.dll` file and put it in the `[GameFolder]\Mods\` folder. 3. Take the `UnityExplorer.ML.___.dll` file and put it in the `[GameFolder]\Mods\` folder.

Binary file not shown.

View File

@ -21,6 +21,7 @@ namespace UnityExplorer.Core.Config
public static ConfigElement<bool> Force_Unlock_Mouse; public static ConfigElement<bool> Force_Unlock_Mouse;
public static ConfigElement<KeyCode> Force_Unlock_Toggle; public static ConfigElement<KeyCode> Force_Unlock_Toggle;
public static ConfigElement<bool> Aggressive_Mouse_Unlock; public static ConfigElement<bool> Aggressive_Mouse_Unlock;
public static ConfigElement<bool> Disable_EventSystem_Override;
public static ConfigElement<string> Default_Output_Path; public static ConfigElement<string> Default_Output_Path;
public static ConfigElement<bool> Log_Unity_Debug; public static ConfigElement<bool> Log_Unity_Debug;
public static ConfigElement<bool> Hide_On_Startup; public static ConfigElement<bool> Hide_On_Startup;
@ -93,7 +94,11 @@ namespace UnityExplorer.Core.Config
KeyCode.None); KeyCode.None);
Aggressive_Mouse_Unlock = new ConfigElement<bool>("Aggressive Mouse Unlock", Aggressive_Mouse_Unlock = new ConfigElement<bool>("Aggressive Mouse Unlock",
"Use WaitForEndOfFrame to aggressively force the Mouse to be unlocked (requires game restart).", "Use WaitForEndOfFrame to aggressively force the Mouse to be unlocked.\n<b>Requires restart to take effect.</b>",
false);
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); false);
Log_Unity_Debug = new ConfigElement<bool>("Log Unity Debug", Log_Unity_Debug = new ConfigElement<bool>("Log Unity Debug",

View File

@ -7,7 +7,7 @@ using UnityExplorer.Core.Config;
using UnityExplorer.Core; using UnityExplorer.Core;
using UnityExplorer.UI; using UnityExplorer.UI;
using System.Collections; using System.Collections;
using HarmonyLib;
namespace UnityExplorer.Core.Input namespace UnityExplorer.Core.Input
{ {
@ -37,12 +37,15 @@ namespace UnityExplorer.Core.Input
lastVisibleState = Cursor.visible; lastVisibleState = Cursor.visible;
SetupPatches(); SetupPatches();
UpdateCursorControl(); UpdateCursorControl();
// Hook up config values
// Force Unlock Mouse
Unlock = ConfigManager.Force_Unlock_Mouse.Value; Unlock = ConfigManager.Force_Unlock_Mouse.Value;
ConfigManager.Force_Unlock_Mouse.OnValueChanged += (bool val) => { Unlock = val; }; ConfigManager.Force_Unlock_Mouse.OnValueChanged += (bool val) => { Unlock = val; };
// Aggressive Mouse Unlock
if (ConfigManager.Aggressive_Mouse_Unlock.Value) if (ConfigManager.Aggressive_Mouse_Unlock.Value)
SetupAggressiveUnlock(); SetupAggressiveUnlock();
} }
@ -83,7 +86,7 @@ namespace UnityExplorer.Core.Input
Cursor.lockState = CursorLockMode.None; Cursor.lockState = CursorLockMode.None;
Cursor.visible = true; Cursor.visible = true;
if (UIManager.EventSys) if (!ConfigManager.Disable_EventSystem_Override.Value && UIManager.EventSys)
SetEventSystem(); SetEventSystem();
} }
else else
@ -91,7 +94,7 @@ namespace UnityExplorer.Core.Input
Cursor.lockState = lastLockMode; Cursor.lockState = lastLockMode;
Cursor.visible = lastVisibleState; Cursor.visible = lastVisibleState;
if (UIManager.EventSys) if (!ConfigManager.Disable_EventSystem_Override.Value && UIManager.EventSys)
ReleaseEventSystem(); ReleaseEventSystem();
} }
@ -160,28 +163,21 @@ namespace UnityExplorer.Core.Input
public static void Prefix_EventSystem_set_current(ref EventSystem value) public static void Prefix_EventSystem_set_current(ref EventSystem value)
{ {
if (!UIManager.EventSys) if (!settingEventSystem && value)
{
if (value)
{ {
lastEventSystem = value; lastEventSystem = value;
lastInputModule = value.currentInputModule; lastInputModule = value.currentInputModule;
} }
if (!UIManager.EventSys)
return; return;
}
if (!settingEventSystem && value != UIManager.EventSys) if (!settingEventSystem && ShouldActuallyUnlock && !ConfigManager.Disable_EventSystem_Override.Value)
{
lastEventSystem = value;
lastInputModule = value?.currentInputModule;
if (ShouldActuallyUnlock)
{ {
value = UIManager.EventSys; value = UIManager.EventSys;
value.enabled = true; value.enabled = true;
} }
} }
}
// Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true. // Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true.
// Also keep track of when anything else tries to set Cursor state, this will be the // Also keep track of when anything else tries to set Cursor state, this will be the

View File

@ -67,6 +67,8 @@ namespace UnityExplorer
private static void BuildDeobfuscationCache() private static void BuildDeobfuscationCache()
{ {
float start = UnityEngine.Time.realtimeSinceStartup;
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{ {
foreach (var type in asm.TryGetTypes()) foreach (var type in asm.TryGetTypes())
@ -74,7 +76,10 @@ namespace UnityExplorer
} }
if (DeobfuscatedTypes.Count > 0) if (DeobfuscatedTypes.Count > 0)
ExplorerCore.Log($"Built IL2CPP deobfuscation cache, initial count: {DeobfuscatedTypes.Count}"); {
ExplorerCore.Log($"Built deobfuscation cache in {UnityEngine.Time.realtimeSinceStartup - start} seconds, " +
$"initial count: {DeobfuscatedTypes.Count} ");
}
} }
private static void TryCacheDeobfuscatedType(Type type) private static void TryCacheDeobfuscatedType(Type type)

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.UI.IValues; using UnityExplorer.UI.CacheObject.IValues;
using System.Reflection; using System.Reflection;
using UnityExplorer.UI; using UnityExplorer.UI;
#if CPP #if CPP

View File

@ -13,7 +13,6 @@ namespace UnityExplorer
public static class ToStringUtility public static class ToStringUtility
{ {
internal static Dictionary<string, MethodInfo> toStringMethods = new Dictionary<string, MethodInfo>(); internal static Dictionary<string, MethodInfo> toStringMethods = new Dictionary<string, MethodInfo>();
internal static Dictionary<string, MethodInfo> toStringFormattedMethods = new Dictionary<string, MethodInfo>();
private const string nullString = "<color=grey>null</color>"; private const string nullString = "<color=grey>null</color>";
private const string nullUnknown = nullString + " (?)"; private const string nullUnknown = nullString + " (?)";
@ -132,23 +131,13 @@ namespace UnityExplorer
var type = value.GetActualType(); var type = value.GetActualType();
// Find and cache the relevant ToString method for this Type, if haven't already. // Find and cache the ToString method for this Type, if haven't already.
if (!toStringMethods.ContainsKey(type.AssemblyQualifiedName)) if (!toStringMethods.ContainsKey(type.AssemblyQualifiedName))
{
try
{
var formatMethod = type.GetMethod("ToString", ArgumentUtility.ParseArgs);
formatMethod.Invoke(value, new object[] { ParseUtility.NUMBER_FORMAT });
toStringFormattedMethods.Add(type.AssemblyQualifiedName, formatMethod);
toStringMethods.Add(type.AssemblyQualifiedName, null);
}
catch
{ {
var toStringMethod = type.GetMethod("ToString", ArgumentUtility.EmptyTypes); var toStringMethod = type.GetMethod("ToString", ArgumentUtility.EmptyTypes);
toStringMethods.Add(type.AssemblyQualifiedName, toStringMethod); toStringMethods.Add(type.AssemblyQualifiedName, toStringMethod);
} }
}
// Invoke the ToString method on the object // Invoke the ToString method on the object
@ -157,9 +146,6 @@ namespace UnityExplorer
string toString; string toString;
try try
{ {
if (toStringFormattedMethods.TryGetValue(type.AssemblyQualifiedName, out MethodInfo formatMethod))
toString = (string)formatMethod.Invoke(value, new object[] { ParseUtility.NUMBER_FORMAT });
else
toString = (string)toStringMethods[type.AssemblyQualifiedName].Invoke(value, ArgumentUtility.EmptyArgs); toString = (string)toStringMethods[type.AssemblyQualifiedName].Invoke(value, ArgumentUtility.EmptyArgs);
} }
catch (Exception ex) catch (Exception ex)

View File

@ -12,6 +12,7 @@ using UnityExplorer.Core.Runtime;
using UnityExplorer.Tests; using UnityExplorer.Tests;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Inspectors; using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.ObjectExplorer;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
namespace UnityExplorer namespace UnityExplorer
@ -19,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.3"; public const string VERSION = "4.0.6";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer"; public const string GUID = "com.sinai.unityexplorer";

View File

@ -2,11 +2,24 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="ILRepacker" AfterTargets="Build"> <Target Name="ILRepacker" AfterTargets="Build">
<!-- Actual merged assemblies -->
<ItemGroup> <ItemGroup>
<InputAssemblies Include="$(OutputPath)$(AssemblyName).dll" /> <InputAssemblies Include="$(OutputPath)$(AssemblyName).dll" />
<InputAssemblies Include="..\lib\mcs-unity\mcs\bin\Release\mcs.dll" /> <InputAssemblies Include="..\lib\mcs-unity\mcs\bin\Release\mcs.dll" />
<InputAssemblies Include="packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll" /> <InputAssemblies Include="packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll" />
</ItemGroup> </ItemGroup>
<!-- MonoMod for MelonLoader 0.3.0 -->
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\Mono.Cecil.dll" />
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\Mono.Cecil.Mdb.dll" />
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\Mono.Cecil.Pdb.dll" />
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\Mono.Cecil.Rocks.dll" />
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\MonoMod.RuntimeDetour.dll" />
<InputAssemblies Include="..\lib\HarmonyX\Harmony\bin\Release\net45\MonoMod.Utils.dll" />
</ItemGroup>
<!-- Required references for ILRepack -->
<ItemGroup> <ItemGroup>
<ReferenceFolders Include="..\lib\" /> <ReferenceFolders Include="..\lib\" />
<ReferenceFolders Include="..\lib\HarmonyX\Harmony\bin\Release\net35\" /> <ReferenceFolders Include="..\lib\HarmonyX\Harmony\bin\Release\net35\" />
@ -15,6 +28,7 @@
<ReferenceFolders Include="..\lib\BepInEx.5\" /> <ReferenceFolders Include="..\lib\BepInEx.5\" />
<ReferenceFolders Include="..\lib\MelonLoader\" /> <ReferenceFolders Include="..\lib\MelonLoader\" />
</ItemGroup> </ItemGroup>
<ILRepack <ILRepack
Parallel="true" Parallel="true"
Internalize="true" Internalize="true"

View File

@ -9,11 +9,15 @@ using UnityExplorer.Core;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.Core.Input; using UnityExplorer.Core.Input;
using UnityExplorer.Loader.ML; using UnityExplorer.Loader.ML;
#if ML_LEGACY
using Harmony;
#else
using HarmonyLib; using HarmonyLib;
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
#endif
[assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)] [assembly: MelonInfo(typeof(ExplorerMelonMod), ExplorerCore.NAME, ExplorerCore.VERSION, ExplorerCore.AUTHOR)]
[assembly: MelonGame(null, null)] [assembly: MelonGame(null, null)]
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]
[assembly: MelonColor(ConsoleColor.DarkCyan)] [assembly: MelonColor(ConsoleColor.DarkCyan)]
namespace UnityExplorer namespace UnityExplorer
@ -67,7 +71,11 @@ namespace UnityExplorer
try try
{ {
var prop = type.GetProperty(property); var prop = type.GetProperty(property);
#if ML_LEGACY
this.Harmony.Patch(prop.GetSetMethod(), prefix: prefix);
#else
HarmonyInstance.Patch(prop.GetSetMethod(), prefix: prefix); HarmonyInstance.Patch(prop.GetSetMethod(), prefix: prefix);
#endif
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -1,4 +1,7 @@
#if ML #if ML
#if !ML_LEGACY // ML 0.3.1+ config handler
using MelonLoader; using MelonLoader;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -75,4 +78,129 @@ namespace UnityExplorer.Loader.ML
} }
} }
#else // ML 0.3.0 config handler
using MelonLoader;
using MelonLoader.Tomlyn.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.Core;
using UnityExplorer.Core.Config;
namespace UnityExplorer.Loader.ML
{
public class MelonLoaderConfigHandler : ConfigHandler
{
internal const string CTG_NAME = "UnityExplorer";
internal MelonPreferences_Category prefCategory;
public override void Init()
{
prefCategory = MelonPreferences.CreateCategory(CTG_NAME, $"{CTG_NAME} Settings");
try { MelonPreferences.Mapper.RegisterMapper(KeycodeReader, KeycodeWriter); } catch { }
try { MelonPreferences.Mapper.RegisterMapper(AnchorReader, AnchorWriter); } catch { }
}
public override void LoadConfig()
{
foreach (var entry in ConfigManager.ConfigElements)
{
var key = entry.Key;
if (prefCategory.GetEntry(key) is MelonPreferences_Entry)
{
var config = entry.Value;
config.BoxedValue = config.GetLoaderConfigValue();
}
}
}
public override void RegisterConfigElement<T>(ConfigElement<T> config)
{
var entry = prefCategory.CreateEntry(config.Name, config.Value, null, config.IsInternal) as MelonPreferences_Entry<T>;
entry.OnValueChangedUntyped += () =>
{
if ((entry.Value == null && config.Value == null) || config.Value.Equals(entry.Value))
return;
config.Value = entry.Value;
};
}
public override void SetConfigValue<T>(ConfigElement<T> config, T value)
{
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
{
entry.Value = value;
entry.Save();
}
}
public override T GetConfigValue<T>(ConfigElement<T> config)
{
if (prefCategory.GetEntry<T>(config.Name) is MelonPreferences_Entry<T> entry)
return entry.Value;
return default;
}
public override void OnAnyConfigChanged()
{
}
public override void SaveConfig()
{
MelonPreferences.Save();
}
// Enum config handlers
public static KeyCode KeycodeReader(TomlObject value)
{
try
{
KeyCode kc = (KeyCode)Enum.Parse(typeof(KeyCode), (value as TomlString).Value);
if (kc == default)
throw new Exception();
return kc;
}
catch
{
return KeyCode.F7;
}
}
public static TomlObject KeycodeWriter(KeyCode value)
{
return MelonPreferences.Mapper.ToToml(value.ToString());
}
public static UI.UIManager.VerticalAnchor AnchorReader(TomlObject value)
{
try
{
return (UI.UIManager.VerticalAnchor)Enum.Parse(typeof(UI.UIManager.VerticalAnchor), (value as TomlString).Value);
}
catch
{
return UI.UIManager.VerticalAnchor.Top;
}
}
public static TomlObject AnchorWriter(UI.UIManager.VerticalAnchor anchor)
{
return MelonPreferences.Mapper.ToToml(anchor.ToString());
}
}
}
#endif
#endif #endif

View File

@ -11,6 +11,7 @@ using UnityExplorer.UI.CSConsole;
using UnityExplorer.Core.Input; using UnityExplorer.Core.Input;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
using System.Reflection;
namespace UnityExplorer.UI.CSConsole namespace UnityExplorer.UI.CSConsole
{ {
@ -247,6 +248,8 @@ namespace UnityExplorer.UI.CSConsole
UpdateCaret(out _); UpdateCaret(out _);
} }
private static float timeOfLastCtrlR;
public static void Update() public static void Update()
{ {
if (SRENotSupported) if (SRENotSupported)
@ -268,8 +271,10 @@ namespace UnityExplorer.UI.CSConsole
if (EnableCtrlRShortcut if (EnableCtrlRShortcut
&& (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl)) && (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl))
&& InputManager.GetKeyDown(KeyCode.R)) && InputManager.GetKeyDown(KeyCode.R)
&& timeOfLastCtrlR.OccuredEarlierThanDefault())
{ {
timeOfLastCtrlR = Time.realtimeSinceStartup;
Evaluate(Panel.Input.Text); Evaluate(Panel.Input.Text);
} }
} }
@ -328,15 +333,28 @@ namespace UnityExplorer.UI.CSConsole
RuntimeProvider.Instance.StartCoroutine(SetAutocompleteCaretCoro(caretPosition)); RuntimeProvider.Instance.StartCoroutine(SetAutocompleteCaretCoro(caretPosition));
} }
internal static PropertyInfo SelectionGuardProperty => selectionGuardPropInfo ?? GetSelectionGuardPropInfo();
private static PropertyInfo GetSelectionGuardPropInfo()
{
selectionGuardPropInfo = typeof(EventSystem).GetProperty("m_SelectionGuard");
if (selectionGuardPropInfo == null)
selectionGuardPropInfo = typeof(EventSystem).GetProperty("m_selectionGuard");
return selectionGuardPropInfo;
}
private static PropertyInfo selectionGuardPropInfo;
private static IEnumerator SetAutocompleteCaretCoro(int caretPosition) private static IEnumerator SetAutocompleteCaretCoro(int caretPosition)
{ {
var color = Input.Component.selectionColor; var color = Input.Component.selectionColor;
color.a = 0f; color.a = 0f;
Input.Component.selectionColor = color; Input.Component.selectionColor = color;
EventSystem.current.SetSelectedGameObject(null, null); try { EventSystem.current.SetSelectedGameObject(null, null); } catch { }
yield return null; yield return null;
EventSystem.current.SetSelectedGameObject(Input.UIRoot, null); try { SelectionGuardProperty.SetValue(EventSystem.current, false, null); } catch { }
try { EventSystem.current.SetSelectedGameObject(Input.UIRoot, null); } catch { }
Input.Component.Select(); Input.Component.Select();
yield return null; yield return null;

View File

@ -3,8 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using UnityExplorer.UI.CacheObject.Views; using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.IValues; using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.CacheObject namespace UnityExplorer.UI.CacheObject
{ {

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using UnityExplorer.UI.CacheObject.Views; using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.IValues; using UnityExplorer.UI.CacheObject.IValues;
namespace UnityExplorer.UI.CacheObject namespace UnityExplorer.UI.CacheObject
{ {

View File

@ -7,8 +7,7 @@ using UnityEngine;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.CacheObject.Views; using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.Inspectors; using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.CacheObject namespace UnityExplorer.UI.CacheObject
{ {

View File

@ -8,9 +8,8 @@ using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.CacheObject.Views; using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.IValues; using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.CacheObject namespace UnityExplorer.UI.CacheObject
{ {

View File

@ -6,7 +6,7 @@ using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
namespace UnityExplorer.UI.IValues namespace UnityExplorer.UI.CacheObject.IValues
{ {
public class InteractiveColor : InteractiveValue public class InteractiveColor : InteractiveValue
{ {

View File

@ -9,10 +9,9 @@ using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.CacheObject.Views; using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.Inspectors; using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.IValues namespace UnityExplorer.UI.CacheObject.IValues
{ {
public class InteractiveDictionary : InteractiveValue, ICellPoolDataSource<CacheKeyValuePairCell>, ICacheObjectController public class InteractiveDictionary : InteractiveValue, ICellPoolDataSource<CacheKeyValuePairCell>, ICacheObjectController
{ {

View File

@ -7,7 +7,7 @@ using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
namespace UnityExplorer.UI.IValues namespace UnityExplorer.UI.CacheObject.IValues
{ {
public class InteractiveEnum : InteractiveValue public class InteractiveEnum : InteractiveValue
{ {

View File

@ -9,10 +9,9 @@ using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.CacheObject.Views; using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.Inspectors; using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.IValues namespace UnityExplorer.UI.CacheObject.IValues
{ {
public class InteractiveList : InteractiveValue, ICellPoolDataSource<CacheListEntryCell>, ICacheObjectController public class InteractiveList : InteractiveValue, ICellPoolDataSource<CacheListEntryCell>, ICacheObjectController
{ {

View File

@ -9,7 +9,7 @@ using UnityExplorer.Core.Config;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.IValues namespace UnityExplorer.UI.CacheObject.IValues
{ {
public class InteractiveString : InteractiveValue public class InteractiveString : InteractiveValue
{ {

View File

@ -5,9 +5,9 @@ using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Models;
namespace UnityExplorer.UI.IValues namespace UnityExplorer.UI.CacheObject.IValues
{ {
public abstract class InteractiveValue : IPooledObject public abstract class InteractiveValue : IPooledObject
{ {

View File

@ -6,9 +6,8 @@ using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.IValues namespace UnityExplorer.UI.CacheObject.IValues
{ {
public class InteractiveValueStruct : InteractiveValue public class InteractiveValueStruct : InteractiveValue
{ {

View File

@ -5,7 +5,7 @@ using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.Inspectors; using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.IValues; using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.CacheObject.Views namespace UnityExplorer.UI.CacheObject.Views

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.IValues; using UnityExplorer.UI.CacheObject.IValues;
namespace UnityExplorer.UI.CacheObject.Views namespace UnityExplorer.UI.CacheObject.Views
{ {

View File

@ -5,9 +5,7 @@ using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.Inspectors; using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.IValues; using UnityExplorer.UI.CacheObject.IValues;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.CacheObject.Views namespace UnityExplorer.UI.CacheObject.Views

View File

@ -5,8 +5,7 @@ using System.Reflection;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
namespace UnityExplorer.UI.CacheObject.Views namespace UnityExplorer.UI.CacheObject.Views

View File

@ -6,9 +6,8 @@ using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Core.Input; using UnityExplorer.Core.Input;
using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
@ -221,8 +220,8 @@ namespace UnityExplorer.UI.Inspectors
public override GameObject CreateContent(GameObject parent) public override GameObject CreateContent(GameObject parent)
{ {
UIRoot = UIFactory.CreateVerticalGroup(Pool<GameObjectInspector>.Instance.InactiveHolder, UIRoot = UIFactory.CreateVerticalGroup(parent, "GameObjectInspector", true, false, true, true, 5,
"GameObjectInspector", true, false, true, true, 5, new Vector4(4, 4, 4, 4), new Color(0.065f, 0.065f, 0.065f)); new Vector4(4, 4, 4, 4), new Color(0.065f, 0.065f, 0.065f));
var scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out var scrollbar, var scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out var scrollbar,
new Color(0.065f, 0.065f, 0.065f)); new Color(0.065f, 0.065f, 0.065f));

View File

@ -232,6 +232,12 @@ namespace UnityExplorer.UI.Inspectors
} }
} }
private void OnExploreButtonClicked()
{
var panel = UIManager.GetPanel<Panels.ObjectExplorerPanel>(UIManager.Panels.ObjectExplorer);
panel.SceneExplorer.JumpToTransform(this.Parent.GOTarget.transform);
}
private void OnLayerDropdownChanged(int value) private void OnLayerDropdownChanged(int value)
{ {
GOTarget.layer = value; GOTarget.layer = value;
@ -533,6 +539,12 @@ namespace UnityExplorer.UI.Inspectors
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default); UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default);
UIFactory.SetLayoutElement(thirdrow, minHeight: 25, flexibleWidth: 9999); UIFactory.SetLayoutElement(thirdrow, minHeight: 25, flexibleWidth: 9999);
// Inspect in Explorer button
var explorerBtn = UIFactory.CreateButton(thirdrow, "ExploreBtn", "Show in Explorer", new Color(0.15f, 0.15f, 0.15f));
UIFactory.SetLayoutElement(explorerBtn.Component.gameObject, minHeight: 25, minWidth: 100);
explorerBtn.ButtonText.fontSize = 12;
explorerBtn.OnClick += OnExploreButtonClicked;
// Scene // Scene
var sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey); var 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);
@ -547,7 +559,7 @@ namespace UnityExplorer.UI.Inspectors
UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50); UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50);
var layerDrop = UIFactory.CreateDropdown(thirdrow, out LayerDropdown, "0", 14, OnLayerDropdownChanged); var layerDrop = UIFactory.CreateDropdown(thirdrow, out LayerDropdown, "0", 14, OnLayerDropdownChanged);
UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 120, flexibleWidth: 999); UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 110, flexibleWidth: 999);
LayerDropdown.captionText.color = SignatureHighlighter.EnumGreen; LayerDropdown.captionText.color = SignatureHighlighter.EnumGreen;
if (layerToNames == null) if (layerToNames == null)
GetLayerNames(); GetLayerNames();

View File

@ -64,7 +64,6 @@ namespace UnityExplorer.UI.Inspectors
internal static Camera MainCamera; internal static Camera MainCamera;
internal static GraphicRaycaster[] graphicRaycasters; internal static GraphicRaycaster[] graphicRaycasters;
public void StartInspect(MouseInspectMode mode) public void StartInspect(MouseInspectMode mode)
{ {
MainCamera = Camera.main; MainCamera = Camera.main;
@ -94,8 +93,14 @@ namespace UnityExplorer.UI.Inspectors
public void StopInspect() public void StopInspect()
{ {
Inspecting = false; Inspecting = false;
UIManager.NavBarRect.gameObject.SetActive(true); UIManager.NavBarRect.gameObject.SetActive(true);
UIManager.PanelHolder.SetActive(true); UIManager.PanelHolder.SetActive(true);
var drop = UIManager.MouseInspectDropdown;
if (drop.transform.Find("Dropdown List") is Transform list)
drop.DestroyDropdownList(list.gameObject);
UIRoot.SetActive(false); UIRoot.SetActive(false);
if (Mode == MouseInspectMode.UI) if (Mode == MouseInspectMode.UI)

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
namespace UnityExplorer.UI.Inspectors namespace UnityExplorer.UI.Inspectors

View File

@ -7,7 +7,7 @@ using UnityEngine.UI;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Inspectors; using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
namespace UnityExplorer namespace UnityExplorer

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Inspectors namespace UnityExplorer.UI.Inspectors

View File

@ -12,9 +12,7 @@ using UnityExplorer.Core.Config;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.CacheObject.Views; using UnityExplorer.UI.CacheObject.Views;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Inspectors namespace UnityExplorer.UI.Inspectors

View File

@ -16,8 +16,11 @@ namespace UnityExplorer.UI
{ {
if (inputsPendingUpdate.Any()) if (inputsPendingUpdate.Any())
{ {
foreach (var entry in inputsPendingUpdate) var array = inputsPendingUpdate.ToArray();
for (int i = array.Length - 1; i >= 0; i--)
{ {
var entry = array[i];
LayoutRebuilder.MarkLayoutForRebuild(entry.Rect); LayoutRebuilder.MarkLayoutForRebuild(entry.Rect);
entry.OnValueChanged?.Invoke(entry.Component.text); entry.OnValueChanged?.Invoke(entry.Component.text);
} }

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
namespace UnityExplorer.UI.ObjectPool namespace UnityExplorer.UI.Models
{ {
public interface IPooledObject public interface IPooledObject
{ {

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
namespace UnityExplorer.UI.ObjectPool namespace UnityExplorer.UI.Models
{ {
// Abstract non-generic class, handles the pool dictionary and interfacing with the generic pools. // Abstract non-generic class, handles the pool dictionary and interfacing with the generic pools.
public abstract class Pool public abstract class Pool

View File

@ -4,11 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;

View File

@ -58,6 +58,26 @@ namespace UnityExplorer.UI.ObjectExplorer
Tree.RefreshData(true); Tree.RefreshData(true);
} }
public void JumpToTransform(Transform transform)
{
if (!transform)
return;
UIManager.SetPanelActive(this.Parent, true);
this.Parent.SetTab(0);
// select the transform's scene
var go = transform.gameObject;
if (SceneHandler.SelectedScene != go.scene)
{
int idx = sceneDropdown.options.IndexOf(sceneToDropdownOption[go.scene.handle]);
sceneDropdown.value = idx;
}
// Let the TransformTree handle the rest
Tree.JumpAndExpandToTransform(transform);
}
private void OnDropdownChanged(int value) private void OnDropdownChanged(int value)
{ {
if (value < 0 || SceneHandler.LoadedScenes.Count <= value) if (value < 0 || SceneHandler.LoadedScenes.Count <= value)
@ -122,7 +142,7 @@ namespace UnityExplorer.UI.ObjectExplorer
{ {
if ((!string.IsNullOrEmpty(input) && !Tree.Filtering) || (string.IsNullOrEmpty(input) && Tree.Filtering)) if ((!string.IsNullOrEmpty(input) && !Tree.Filtering) || (string.IsNullOrEmpty(input) && Tree.Filtering))
{ {
Tree.displayedObjects.Clear(); Tree.cachedTransforms.Clear();
} }
Tree.CurrentFilter = input; Tree.CurrentFilter = input;

View File

@ -6,7 +6,7 @@ using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
namespace UnityExplorer.Core namespace UnityExplorer.UI.ObjectExplorer
{ {
public static class SceneHandler public static class SceneHandler
{ {
@ -82,25 +82,7 @@ namespace UnityExplorer.Core
} }
private static GameObject dontDestroyObject; private static GameObject dontDestroyObject;
public static bool InspectingAssetScene => SelectedScene == AssetScene; public static bool InspectingAssetScene => !SelectedScene?.IsValid() ?? false;
internal static Scene AssetScene => AssetObject.scene;
internal static int AssetHandle => AssetScene.handle;
internal static GameObject AssetObject
{
get
{
if (!assetObject)
{
assetObject = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GameObject))
.First(it => !it.TryCast<GameObject>().scene.IsValid())
.TryCast<GameObject>();
}
return assetObject;
}
}
private static GameObject assetObject;
internal static void Init() internal static void Init()
{ {
@ -122,7 +104,7 @@ namespace UnityExplorer.Core
catch (Exception ex) catch (Exception ex)
{ {
gotAllScenesInBuild = false; gotAllScenesInBuild = false;
ExplorerCore.Log($"Unable to generate list of all Scenes in the build: {ex}"); ExplorerCore.LogWarning($"Unable to generate list of all Scenes in the build: {ex}");
} }
} }
@ -131,7 +113,7 @@ namespace UnityExplorer.Core
int curHandle = SelectedScene?.handle ?? -1; int curHandle = SelectedScene?.handle ?? -1;
// DontDestroyOnLoad always exists, so default to true if our curHandle is that handle. // DontDestroyOnLoad always exists, so default to true if our curHandle is that handle.
// otherwise we will check while iterating. // otherwise we will check while iterating.
bool inspectedExists = curHandle == DontDestroyHandle || curHandle == AssetHandle; bool inspectedExists = curHandle == DontDestroyHandle || curHandle == 0;
// Quick sanity check if the loaded scenes changed // Quick sanity check if the loaded scenes changed
bool anyChange = LoadedSceneCount != allLoadedScenes.Count; bool anyChange = LoadedSceneCount != allLoadedScenes.Count;
@ -145,7 +127,7 @@ namespace UnityExplorer.Core
for (int i = 0; i < SceneManager.sceneCount; i++) for (int i = 0; i < SceneManager.sceneCount; i++)
{ {
Scene scene = SceneManager.GetSceneAt(i); Scene scene = SceneManager.GetSceneAt(i);
if (scene == default || scene.handle == -1 || !scene.isLoaded) if (scene == default || !scene.isLoaded)
continue; continue;
// If no changes yet, ensure the previous list contained this handle. // If no changes yet, ensure the previous list contained this handle.
@ -161,7 +143,7 @@ namespace UnityExplorer.Core
// Always add the DontDestroyOnLoad scene and the "none" scene. // Always add the DontDestroyOnLoad scene and the "none" scene.
allLoadedScenes.Add(DontDestroyScene); allLoadedScenes.Add(DontDestroyScene);
allLoadedScenes.Add(AssetScene); allLoadedScenes.Add(default);
// Default to first scene if none selected or previous selection no longer exists. // Default to first scene if none selected or previous selection no longer exists.
if (!inspectedExists) if (!inspectedExists)

View File

@ -45,9 +45,9 @@ namespace UnityExplorer.UI.ObjectExplorer
case SceneFilter.DontDestroyOnLoad: case SceneFilter.DontDestroyOnLoad:
return scene == SceneHandler.DontDestroyScene; return scene == SceneHandler.DontDestroyScene;
case SceneFilter.HideAndDontSave: case SceneFilter.HideAndDontSave:
return scene == SceneHandler.AssetScene; return scene == default;
case SceneFilter.ActivelyLoaded: case SceneFilter.ActivelyLoaded:
return scene != SceneHandler.DontDestroyScene && scene != SceneHandler.AssetScene; return scene != SceneHandler.DontDestroyScene && scene != default;
default: default:
return false; return false;
} }
@ -58,25 +58,13 @@ namespace UnityExplorer.UI.ObjectExplorer
{ {
var results = new List<object>(); var results = new List<object>();
Type searchType; Type searchType = null;
switch (context)
{
//case SearchContext.GameObject:
// searchType = typeof(GameObject);
// break;
case SearchContext.UnityObject:
default:
if (!string.IsNullOrEmpty(customTypeInput)) if (!string.IsNullOrEmpty(customTypeInput))
{ {
if (ReflectionUtility.GetTypeByName(customTypeInput) is Type customType) if (ReflectionUtility.GetTypeByName(customTypeInput) is Type customType)
{ {
if (typeof(UnityEngine.Object).IsAssignableFrom(customType)) if (typeof(UnityEngine.Object).IsAssignableFrom(customType))
{
searchType = customType; searchType = customType;
break;
}
else else
ExplorerCore.LogWarning($"Custom type '{customType.FullName}' is not assignable from UnityEngine.Object!"); ExplorerCore.LogWarning($"Custom type '{customType.FullName}' is not assignable from UnityEngine.Object!");
} }
@ -84,13 +72,8 @@ namespace UnityExplorer.UI.ObjectExplorer
ExplorerCore.LogWarning($"Could not find any type by name '{customTypeInput}'!"); ExplorerCore.LogWarning($"Could not find any type by name '{customTypeInput}'!");
} }
searchType = typeof(UnityEngine.Object);
break;
}
if (searchType == null) if (searchType == null)
return results; searchType = typeof(UnityEngine.Object);
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(searchType); var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(searchType);
@ -100,7 +83,7 @@ namespace UnityExplorer.UI.ObjectExplorer
if (!string.IsNullOrEmpty(input)) if (!string.IsNullOrEmpty(input))
nameFilter = input; nameFilter = input;
bool canGetGameObject = searchType == typeof(GameObject) || typeof(Component).IsAssignableFrom(searchType); bool shouldFilterGOs = searchType == typeof(GameObject) || typeof(Component).IsAssignableFrom(searchType);
foreach (var obj in allObjects) foreach (var obj in allObjects)
{ {
@ -108,13 +91,21 @@ namespace UnityExplorer.UI.ObjectExplorer
if (!string.IsNullOrEmpty(nameFilter) && !obj.name.ContainsIgnoreCase(nameFilter)) if (!string.IsNullOrEmpty(nameFilter) && !obj.name.ContainsIgnoreCase(nameFilter))
continue; continue;
if (canGetGameObject) GameObject go = null;
{ var type = obj.GetActualType();
var go = searchType == typeof(GameObject)
? obj.TryCast<GameObject>() if (type == typeof(GameObject))
: obj.TryCast<Component>().gameObject; go = obj.TryCast<GameObject>();
else if (typeof(Component).IsAssignableFrom(type))
go = obj.TryCast<Component>()?.gameObject;
if (go) if (go)
{
// hide unityexplorer objects
if (go.transform.root.name == "ExplorerCanvas")
continue;
if (shouldFilterGOs)
{ {
// scene check // scene check
if (sceneFilter != SceneFilter.Any) if (sceneFilter != SceneFilter.Any)

View File

@ -7,7 +7,7 @@ using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.UI.CSConsole; using UnityExplorer.UI.CSConsole;
using UnityExplorer.UI.Utility; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels
{ {

View File

@ -12,7 +12,6 @@ using UnityExplorer.Core;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
using UnityExplorer.UI.ObjectExplorer; using UnityExplorer.UI.ObjectExplorer;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels

View File

@ -8,7 +8,6 @@ using UnityEngine.UI;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.Core.Input; using UnityExplorer.Core.Input;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Panels namespace UnityExplorer.UI.Panels

View File

@ -5,7 +5,6 @@ using UnityEngine.UI;
using UnityExplorer.Core.Config; using UnityExplorer.Core.Config;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI namespace UnityExplorer.UI

View File

@ -12,7 +12,6 @@ using UnityExplorer.UI.CSConsole;
using UnityExplorer.UI.Inspectors; using UnityExplorer.UI.Inspectors;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete; using UnityExplorer.UI.Widgets.AutoComplete;
@ -146,7 +145,7 @@ namespace UnityExplorer.UI
if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value)) if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value))
CursorUnlocker.Unlock = !CursorUnlocker.Unlock; CursorUnlocker.Unlock = !CursorUnlocker.Unlock;
if (EventSystem.current != EventSys) if (!ConfigManager.Disable_EventSystem_Override.Value && EventSystem.current != EventSys)
CursorUnlocker.SetEventSystem(); CursorUnlocker.SetEventSystem();
UIPanel.UpdateFocus(); UIPanel.UpdateFocus();

View File

@ -7,7 +7,6 @@ using UnityEngine.UI;
using UnityExplorer.Core.Input; using UnityExplorer.Core.Input;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
namespace UnityExplorer.UI.Widgets.AutoComplete namespace UnityExplorer.UI.Widgets.AutoComplete

View File

@ -9,7 +9,6 @@ using UnityExplorer.Core.Input;
using UnityExplorer.Core.Runtime; using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Widgets.AutoComplete namespace UnityExplorer.UI.Widgets.AutoComplete
{ {

View File

@ -10,7 +10,7 @@ using UnityExplorer.Core;
using UnityExplorer.UI; using UnityExplorer.UI;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
namespace UnityExplorer.UI.Utility namespace UnityExplorer.UI.Widgets
{ {
public class AutoSliderScrollbar : UIBehaviourModel public class AutoSliderScrollbar : UIBehaviourModel
{ {

View File

@ -4,7 +4,6 @@ using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.ObjectPool;
namespace UnityExplorer.UI.Widgets namespace UnityExplorer.UI.Widgets
{ {

View File

@ -4,9 +4,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Widgets namespace UnityExplorer.UI.Widgets
{ {

View File

@ -9,7 +9,7 @@ using UnityEngine.EventSystems;
using UnityEngine.Events; using UnityEngine.Events;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
namespace UnityExplorer.UI.Utility namespace UnityExplorer.UI.Widgets
{ {
// To fix an issue with Input Fields and allow them to go inside a ScrollRect nicely. // To fix an issue with Input Fields and allow them to go inside a ScrollRect nicely.

View File

@ -6,13 +6,29 @@ using UnityEngine;
namespace UnityExplorer.UI.Widgets namespace UnityExplorer.UI.Widgets
{ {
public class DataViewInfo public struct DataViewInfo
{ {
public int dataIndex; // static
public float height, startPosition; public static DataViewInfo None => s_default;
public int normalizedSpread; private static DataViewInfo s_default = default;
public static implicit operator float(DataViewInfo it) => it.height; public static implicit operator float(DataViewInfo it) => it.height;
// instance
public int dataIndex, normalizedSpread;
public float height, startPosition;
public override bool Equals(object obj)
{
var other = (DataViewInfo)obj;
return this.dataIndex == other.dataIndex
&& this.height == other.height
&& this.startPosition == other.startPosition
&& this.normalizedSpread == other.normalizedSpread;
}
public override int GetHashCode() => base.GetHashCode();
} }
public class DataHeightCache<T> where T : ICell public class DataHeightCache<T> where T : ICell
@ -53,14 +69,8 @@ namespace UnityExplorer.UI.Widgets
/// <summary>Get the first range (division of DefaultHeight) which the position appears in.</summary> /// <summary>Get the first range (division of DefaultHeight) which the position appears in.</summary>
private int GetRangeFloorOfPosition(float position) => (int)Math.Floor((decimal)position / (decimal)DefaultHeight); private int GetRangeFloorOfPosition(float position) => (int)Math.Floor((decimal)position / (decimal)DefaultHeight);
/// <summary>Get the data index at the specified position of the total height cache.</summary> public int GetFirstDataIndexAtPosition(float desiredHeight)
public int GetFirstDataIndexAtPosition(float desiredHeight) => GetFirstDataIndexAtPosition(desiredHeight, out _);
/// <summary>Get the data index and DataViewInfo at the specified position of the total height cache.</summary>
public int GetFirstDataIndexAtPosition(float desiredHeight, out DataViewInfo cache)
{ {
cache = default;
if (!heightCache.Any()) if (!heightCache.Any())
return 0; return 0;
@ -72,12 +82,11 @@ namespace UnityExplorer.UI.Widgets
if (rangeIndex >= rangeCache.Count) if (rangeIndex >= rangeCache.Count)
{ {
int idx = ScrollPool.DataSource.ItemCount - 1; int idx = ScrollPool.DataSource.ItemCount - 1;
cache = heightCache[idx];
return idx; return idx;
} }
int dataIndex = rangeCache[rangeIndex]; int dataIndex = rangeCache[rangeIndex];
cache = heightCache[dataIndex]; var cache = heightCache[dataIndex];
// if the DataViewInfo is outdated, need to rebuild // if the DataViewInfo is outdated, need to rebuild
int expectedMin = GetRangeCeilingOfPosition(cache.startPosition); int expectedMin = GetRangeCeilingOfPosition(cache.startPosition);
@ -88,7 +97,7 @@ namespace UnityExplorer.UI.Widgets
rangeIndex = GetRangeFloorOfPosition(desiredHeight); rangeIndex = GetRangeFloorOfPosition(desiredHeight);
dataIndex = rangeCache[rangeIndex]; dataIndex = rangeCache[rangeIndex];
cache = heightCache[dataIndex]; //cache = heightCache[dataIndex];
} }
return dataIndex; return dataIndex;
@ -141,8 +150,7 @@ namespace UnityExplorer.UI.Widgets
if (!heightCache.Any()) if (!heightCache.Any())
return; return;
var val = heightCache[heightCache.Count - 1]; totalHeight -= heightCache[heightCache.Count - 1];
totalHeight -= val;
heightCache.RemoveAt(heightCache.Count - 1); heightCache.RemoveAt(heightCache.Count - 1);
int idx = heightCache.Count; int idx = heightCache.Count;
@ -214,6 +222,9 @@ namespace UnityExplorer.UI.Widgets
SetSpread(dataIndex, rangeIndex, spreadDiff); SetSpread(dataIndex, rangeIndex, spreadDiff);
} }
// set the struct back to the array (TODO necessary?)
heightCache[dataIndex] = cache;
} }
private void SetSpread(int dataIndex, int rangeIndex, int spreadDiff) private void SetSpread(int dataIndex, int rangeIndex, int spreadDiff)
@ -244,12 +255,12 @@ namespace UnityExplorer.UI.Widgets
return; return;
DataViewInfo cache; DataViewInfo cache;
DataViewInfo prev = null; DataViewInfo prev = DataViewInfo.None;
for (int i = 0; i <= toIndex && i < heightCache.Count; i++) for (int i = 0; i <= toIndex && i < heightCache.Count; i++)
{ {
cache = heightCache[i]; cache = heightCache[i];
if (prev != null) if (prev != DataViewInfo.None)
cache.startPosition = prev.startPosition + prev.height; cache.startPosition = prev.startPosition + prev.height;
else else
cache.startPosition = 0; cache.startPosition = 0;
@ -262,19 +273,5 @@ namespace UnityExplorer.UI.Widgets
prev = cache; prev = cache;
} }
} }
//private void HardRebuildRanges()
//{
// var tempList = new List<float>();
// for (int i = 0; i < heightCache.Count; i++)
// tempList.Add(heightCache[i]);
//
// heightCache.Clear();
// rangeCache.Clear();
// totalHeight = 0;
//
// for (int i = 0; i < tempList.Count; i++)
// SetIndex(i, tempList[i]);
//}
} }
} }

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Models;
namespace UnityExplorer.UI.Widgets namespace UnityExplorer.UI.Widgets
{ {

View File

@ -7,7 +7,6 @@ using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Core.Input; using UnityExplorer.Core.Input;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
namespace UnityExplorer.UI.Widgets namespace UnityExplorer.UI.Widgets
@ -20,7 +19,7 @@ namespace UnityExplorer.UI.Widgets
/// <summary> /// <summary>
/// An object-pooled ScrollRect, attempts to support content of any size and provide a scrollbar for it. /// An object-pooled ScrollRect, attempts to support content of any size and provide a scrollbar for it.
/// </summary> /// </summary>
public class ScrollPool<T> : UIBehaviourModel where T : ICell public class ScrollPool<T> : UIBehaviourModel, IEnumerable<CellInfo> where T : ICell
{ {
public ScrollPool(ScrollRect scrollRect) public ScrollPool(ScrollRect scrollRect)
{ {
@ -138,9 +137,40 @@ namespace UnityExplorer.UI.Widgets
RefreshCells(setCellData, true); RefreshCells(setCellData, true);
} }
// Initialize public void JumpToIndex(int index, Action<T> onJumped)
{
RefreshCells(true, true);
//private bool Initialized; // Slide to the normalized position of the index
float normalized = HeightCache[index].startPosition / HeightCache.TotalHeight;
RuntimeProvider.Instance.StartCoroutine(ForceDelayedJump(index, normalized, onJumped));
}
private IEnumerator ForceDelayedJump(int dataIndex, float normalizedPos, Action<T> onJumped)
{
// Yielding two frames seems necessary in case the Explorer tab had not been opened before the jump.
yield return null;
yield return null;
slider.value = normalizedPos;
// Get the cell containing the data index and invoke the onJumped listener for it
foreach (var cellInfo in this)
{
if (cellInfo.dataIndex == dataIndex)
{
onJumped?.Invoke(CellPool[cellInfo.cellIndex]);
break;
}
}
}
// IEnumerable
public IEnumerator<CellInfo> GetEnumerator() => EnumerateCellPool();
IEnumerator IEnumerable.GetEnumerator() => EnumerateCellPool();
// Initialize
/// <summary>Should be called only once, when the scroll pool is created.</summary> /// <summary>Should be called only once, when the scroll pool is created.</summary>
public void Initialize(ICellPoolDataSource<T> dataSource, Action onHeightChangedListener = null) public void Initialize(ICellPoolDataSource<T> dataSource, Action onHeightChangedListener = null)
@ -178,9 +208,8 @@ namespace UnityExplorer.UI.Widgets
// create initial cell pool and set cells // create initial cell pool and set cells
CreateCellPool(); CreateCellPool();
var enumerator = GetPoolEnumerator(); foreach (var cell in this)
while (enumerator.MoveNext()) SetCell(CellPool[cell.cellIndex], cell.dataIndex);
SetCell(CellPool[enumerator.Current.cellIndex], enumerator.Current.dataIndex);
LayoutRebuilder.ForceRebuildLayoutImmediate(Content); LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
prevContentHeight = Content.rect.height; prevContentHeight = Content.rect.height;
@ -217,18 +246,18 @@ namespace UnityExplorer.UI.Widgets
// Cell pool // Cell pool
private CellInfo _cellInfo = new CellInfo(); private CellInfo _current;
public IEnumerator<CellInfo> GetPoolEnumerator() private IEnumerator<CellInfo> EnumerateCellPool()
{ {
int cellIdx = topPoolIndex; int cellIdx = topPoolIndex;
int dataIndex = TopDataIndex; int dataIndex = TopDataIndex;
int iterated = 0; int iterated = 0;
while (iterated < CellPool.Count) while (iterated < CellPool.Count)
{ {
_cellInfo.cellIndex = cellIdx; _current.cellIndex = cellIdx;
_cellInfo.dataIndex = dataIndex; _current.dataIndex = dataIndex;
yield return _cellInfo; yield return _current;
cellIdx++; cellIdx++;
if (cellIdx >= CellPool.Count) if (cellIdx >= CellPool.Count)
@ -368,16 +397,13 @@ namespace UnityExplorer.UI.Widgets
CheckDataSourceCountChange(out bool jumpToBottom); CheckDataSourceCountChange(out bool jumpToBottom);
// update date height cache, and set cells if 'andReload' // update date height cache, and set cells if 'andReload'
var enumerator = GetPoolEnumerator(); foreach (var cellInfo in this)
while (enumerator.MoveNext())
{ {
var curr = enumerator.Current; var cell = CellPool[cellInfo.cellIndex];
var cell = CellPool[curr.cellIndex];
if (andReloadFromDataSource) if (andReloadFromDataSource)
SetCell(cell, curr.dataIndex); SetCell(cell, cellInfo.dataIndex);
else else
HeightCache.SetIndex(curr.dataIndex, cell.Rect.rect.height); HeightCache.SetIndex(cellInfo.dataIndex, cell.Rect.rect.height);
} }
// force check recycles // force check recycles
@ -405,12 +431,8 @@ namespace UnityExplorer.UI.Widgets
private void RefreshCellHeightsFast() private void RefreshCellHeightsFast()
{ {
var enumerator = GetPoolEnumerator(); foreach (var cellInfo in this)
while (enumerator.MoveNext()) HeightCache.SetIndex(cellInfo.dataIndex, CellPool[cellInfo.cellIndex].Rect.rect.height);
{
var curr = enumerator.Current;
HeightCache.SetIndex(curr.dataIndex, CellPool[curr.cellIndex].Rect.rect.height);
}
} }
private void SetCell(T cachedCell, int dataIndex) private void SetCell(T cachedCell, int dataIndex)
@ -619,12 +641,10 @@ namespace UnityExplorer.UI.Widgets
else else
{ {
bottomDataIndex = desiredBottomIndex; bottomDataIndex = desiredBottomIndex;
var enumerator = GetPoolEnumerator(); foreach (var info in this)
while (enumerator.MoveNext())
{ {
var curr = enumerator.Current; var cell = CellPool[info.cellIndex];
var cell = CellPool[curr.cellIndex]; SetCell(cell, info.dataIndex);
SetCell(cell, curr.dataIndex);
} }
} }

View File

@ -6,8 +6,6 @@ using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Widgets namespace UnityExplorer.UI.Widgets
{ {
@ -22,13 +20,17 @@ namespace UnityExplorer.UI.Widgets
/// Key: UnityEngine.Transform instance ID<br/> /// Key: UnityEngine.Transform instance ID<br/>
/// Value: CachedTransform /// Value: CachedTransform
/// </summary> /// </summary>
internal readonly OrderedDictionary displayedObjects = new OrderedDictionary(); internal readonly OrderedDictionary cachedTransforms = new OrderedDictionary();
// for keeping track of which actual transforms are expanded or not, outside of the cache data. // for keeping track of which actual transforms are expanded or not, outside of the cache data.
private readonly HashSet<int> expandedInstanceIDs = new HashSet<int>(); private readonly HashSet<int> expandedInstanceIDs = new HashSet<int>();
private readonly HashSet<int> autoExpandedIDs = new HashSet<int>(); private readonly HashSet<int> autoExpandedIDs = new HashSet<int>();
public int ItemCount => displayedObjects.Count; private readonly HashSet<int> visited = new HashSet<int>();
private bool needRefresh;
private int displayIndex;
public int ItemCount => cachedTransforms.Count;
public bool Filtering => !string.IsNullOrEmpty(currentFilter); public bool Filtering => !string.IsNullOrEmpty(currentFilter);
private bool wasFiltering; private bool wasFiltering;
@ -50,6 +52,25 @@ namespace UnityExplorer.UI.Widgets
} }
private string currentFilter; private string currentFilter;
public TransformTree(ScrollPool<TransformCell> scrollPool, Func<IEnumerable<GameObject>> getRootEntriesMethod)
{
ScrollPool = scrollPool;
GetRootEntriesMethod = getRootEntriesMethod;
}
public void OnCellBorrowed(TransformCell cell)
{
cell.OnExpandToggled += ToggleExpandCell;
cell.OnGameObjectClicked += OnGameObjectClicked;
}
private void OnGameObjectClicked(GameObject obj)
{
if (OnClickOverrideHandler != null)
OnClickOverrideHandler.Invoke(obj);
else
InspectorManager.Inspect(obj);
}
public void Init() public void Init()
{ {
@ -58,37 +79,65 @@ namespace UnityExplorer.UI.Widgets
public void Clear() public void Clear()
{ {
this.displayedObjects.Clear(); this.cachedTransforms.Clear();
displayIndex = 0; displayIndex = 0;
autoExpandedIDs.Clear(); autoExpandedIDs.Clear();
expandedInstanceIDs.Clear(); expandedInstanceIDs.Clear();
} }
public void OnGameObjectClicked(GameObject obj)
{
if (OnClickOverrideHandler != null)
{
OnClickOverrideHandler.Invoke(obj);
}
else
{
InspectorManager.Inspect(obj);
}
}
public TransformTree(ScrollPool<TransformCell> scrollPool, Func<IEnumerable<GameObject>> getRootEntriesMethod)
{
ScrollPool = scrollPool;
GetRootEntriesMethod = getRootEntriesMethod;
}
public bool IsCellExpanded(int instanceID) public bool IsCellExpanded(int instanceID)
{ {
return Filtering ? autoExpandedIDs.Contains(instanceID) return Filtering ? autoExpandedIDs.Contains(instanceID)
: expandedInstanceIDs.Contains(instanceID); : expandedInstanceIDs.Contains(instanceID);
} }
public void JumpAndExpandToTransform(Transform transform)
{
// make sure all parents of the object are expanded
var parent = transform.parent;
while (parent)
{
int pid = parent.GetInstanceID();
if (!expandedInstanceIDs.Contains(pid))
expandedInstanceIDs.Add(pid);
parent = parent.parent;
}
// Refresh cached transforms (no UI rebuild yet)
RefreshData(false);
int transformID = transform.GetInstanceID();
// find the index of our transform in the list and jump to it
int idx;
for (idx = 0; idx < cachedTransforms.Count; idx++)
{
var cache = (CachedTransform)cachedTransforms[idx];
if (cache.InstanceID == transformID)
break;
}
ScrollPool.JumpToIndex(idx, OnCellJumpedTo);
}
private void OnCellJumpedTo(TransformCell cell)
{
RuntimeProvider.Instance.StartCoroutine(HighlightCellCoroutine(cell));
}
private IEnumerator HighlightCellCoroutine(TransformCell cell)
{
var button = cell.NameButton.Component;
button.StartColorTween(new Color(0.2f, 0.3f, 0.2f), false);
float start = Time.realtimeSinceStartup;
while (Time.realtimeSinceStartup - start < 1.5f)
yield return null;
button.OnDeselect(null);
}
public void Rebuild() public void Rebuild()
{ {
autoExpandedIDs.Clear(); autoExpandedIDs.Clear();
@ -97,10 +146,6 @@ namespace UnityExplorer.UI.Widgets
RefreshData(true, true); RefreshData(true, true);
} }
private readonly HashSet<int> visited = new HashSet<int>();
private bool needRefresh;
private int displayIndex;
public void RefreshData(bool andReload = false, bool jumpToTop = false) public void RefreshData(bool andReload = false, bool jumpToTop = false)
{ {
visited.Clear(); visited.Clear();
@ -114,12 +159,12 @@ namespace UnityExplorer.UI.Widgets
if (obj) Traverse(obj.transform); if (obj) Traverse(obj.transform);
// Prune displayed transforms that we didnt visit in that traverse // Prune displayed transforms that we didnt visit in that traverse
for (int i = displayedObjects.Count - 1; i >= 0; i--) for (int i = cachedTransforms.Count - 1; i >= 0; i--)
{ {
var obj = (CachedTransform)displayedObjects[i]; var obj = (CachedTransform)cachedTransforms[i];
if (!visited.Contains(obj.InstanceID)) if (!visited.Contains(obj.InstanceID))
{ {
displayedObjects.Remove(obj.InstanceID); cachedTransforms.Remove(obj.InstanceID);
needRefresh = true; needRefresh = true;
} }
} }
@ -159,9 +204,9 @@ namespace UnityExplorer.UI.Widgets
visited.Add(instanceID); visited.Add(instanceID);
CachedTransform cached; CachedTransform cached;
if (displayedObjects.Contains(instanceID)) if (cachedTransforms.Contains(instanceID))
{ {
cached = (CachedTransform)displayedObjects[(object)instanceID]; cached = (CachedTransform)cachedTransforms[(object)instanceID];
if (cached.Update(transform, depth)) if (cached.Update(transform, depth))
needRefresh = true; needRefresh = true;
} }
@ -169,10 +214,10 @@ namespace UnityExplorer.UI.Widgets
{ {
needRefresh = true; needRefresh = true;
cached = new CachedTransform(this, transform, depth, parent); cached = new CachedTransform(this, transform, depth, parent);
if (displayedObjects.Count <= displayIndex) if (cachedTransforms.Count <= displayIndex)
displayedObjects.Add(instanceID, cached); cachedTransforms.Add(instanceID, cached);
else else
displayedObjects.Insert(displayIndex, instanceID, cached); cachedTransforms.Insert(displayIndex, instanceID, cached);
} }
displayIndex++; displayIndex++;
@ -201,9 +246,9 @@ namespace UnityExplorer.UI.Widgets
public void SetCell(TransformCell cell, int index) public void SetCell(TransformCell cell, int index)
{ {
if (index < displayedObjects.Count) if (index < cachedTransforms.Count)
{ {
cell.ConfigureCell((CachedTransform)displayedObjects[index], index); cell.ConfigureCell((CachedTransform)cachedTransforms[index], index);
if (Filtering) if (Filtering)
{ {
if (cell.cachedTransform.Name.ContainsIgnoreCase(currentFilter)) if (cell.cachedTransform.Name.ContainsIgnoreCase(currentFilter))
@ -226,16 +271,5 @@ namespace UnityExplorer.UI.Widgets
RefreshData(true); RefreshData(true);
} }
public void OnCellBorrowed(TransformCell cell)
{
cell.OnExpandToggled += ToggleExpandCell;
cell.OnGameObjectClicked += OnGameObjectClicked;
}
//public void ReleaseCell(TransformCell cell)
//{
// cell.OnExpandToggled -= ToggleExpandCell;
//}
} }
} }

View File

@ -93,6 +93,24 @@
<IsCpp>true</IsCpp> <IsCpp>true</IsCpp>
<IsStandalone>true</IsStandalone> <IsStandalone>true</IsStandalone>
</PropertyGroup> </PropertyGroup>
<!-- ML 0.3.0 CPP -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_MLLegacy_Cpp|AnyCPU'">
<OutputPath>..\Release\UnityExplorer.MelonLoader_Legacy.Il2Cpp\</OutputPath>
<DefineConstants>CPP,ML,ML_LEGACY</DefineConstants>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<AssemblyName>UnityExplorer.MLLEGACY.IL2CPP</AssemblyName>
<IsCpp>true</IsCpp>
<IsMelonLoaderLegacy>true</IsMelonLoaderLegacy>
</PropertyGroup>
<!-- ML 0.3.0 Mono -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_MLLegacy_Mono|AnyCPU'">
<OutputPath>..\Release\UnityExplorer.MelonLoader_Legacy.Mono\</OutputPath>
<DefineConstants>MONO,ML,ML_LEGACY</DefineConstants>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<AssemblyName>UnityExplorer.MLLEGACY.Mono</AssemblyName>
<IsCpp>false</IsCpp>
<IsMelonLoaderLegacy>true</IsMelonLoaderLegacy>
</PropertyGroup>
<!-- Global refs, Mono and Il2Cpp --> <!-- Global refs, Mono and Il2Cpp -->
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
@ -117,6 +135,13 @@
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<!-- MelonLoader Legacy refs -->
<ItemGroup Condition="'$(IsMelonLoaderLegacy)'=='true'">
<Reference Include="MelonLoader">
<HintPath>..\lib\MelonLoader_Legacy\MelonLoader.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<!-- BepInEx universal refs --> <!-- BepInEx universal refs -->
<ItemGroup Condition="'$(IsBepInEx)'=='true'"> <ItemGroup Condition="'$(IsBepInEx)'=='true'">
<Reference Include="0Harmony"> <Reference Include="0Harmony">
@ -256,17 +281,17 @@
<Compile Include="UI\Inspectors\InspectorManager.cs" /> <Compile Include="UI\Inspectors\InspectorManager.cs" />
<Compile Include="UI\Inspectors\InspectorTab.cs" /> <Compile Include="UI\Inspectors\InspectorTab.cs" />
<Compile Include="UI\Inspectors\InspectorBase.cs" /> <Compile Include="UI\Inspectors\InspectorBase.cs" />
<Compile Include="UI\IValues\InteractiveColor.cs" /> <Compile Include="UI\CacheObject\IValues\InteractiveColor.cs" />
<Compile Include="UI\IValues\InteractiveDictionary.cs" /> <Compile Include="UI\CacheObject\IValues\InteractiveDictionary.cs" />
<Compile Include="UI\IValues\InteractiveEnum.cs" /> <Compile Include="UI\CacheObject\IValues\InteractiveEnum.cs" />
<Compile Include="UI\IValues\InteractiveList.cs" /> <Compile Include="UI\CacheObject\IValues\InteractiveList.cs" />
<Compile Include="UI\IValues\InteractiveString.cs" /> <Compile Include="UI\CacheObject\IValues\InteractiveString.cs" />
<Compile Include="UI\IValues\InteractiveValue.cs" /> <Compile Include="UI\CacheObject\IValues\InteractiveValue.cs" />
<Compile Include="UI\Inspectors\ReflectionInspector.cs" /> <Compile Include="UI\Inspectors\ReflectionInspector.cs" />
<Compile Include="UI\IValues\InteractiveValueStruct.cs" /> <Compile Include="UI\CacheObject\IValues\InteractiveValueStruct.cs" />
<Compile Include="UI\Models\InputFieldRef.cs" /> <Compile Include="UI\Models\InputFieldRef.cs" />
<Compile Include="UI\ObjectPool\IPooledObject.cs" /> <Compile Include="UI\Models\ObjectPool\IPooledObject.cs" />
<Compile Include="UI\ObjectPool\Pool.cs" /> <Compile Include="UI\Models\ObjectPool\Pool.cs" />
<Compile Include="UI\Panels\LogPanel.cs" /> <Compile Include="UI\Panels\LogPanel.cs" />
<Compile Include="UI\Panels\CSConsolePanel.cs" /> <Compile Include="UI\Panels\CSConsolePanel.cs" />
<Compile Include="Core\Utility\IOUtility.cs" /> <Compile Include="Core\Utility\IOUtility.cs" />
@ -294,7 +319,7 @@
<Compile Include="Core\Runtime\RuntimeContext.cs" /> <Compile Include="Core\Runtime\RuntimeContext.cs" />
<Compile Include="Core\Runtime\RuntimeProvider.cs" /> <Compile Include="Core\Runtime\RuntimeProvider.cs" />
<Compile Include="Core\Runtime\TextureUtilProvider.cs" /> <Compile Include="Core\Runtime\TextureUtilProvider.cs" />
<Compile Include="Core\SceneHandler.cs" /> <Compile Include="UI\ObjectExplorer\SceneHandler.cs" />
<Compile Include="UI\ObjectExplorer\SearchProvider.cs" /> <Compile Include="UI\ObjectExplorer\SearchProvider.cs" />
<Compile Include="Core\Tests\TestClass.cs" /> <Compile Include="Core\Tests\TestClass.cs" />
<Compile Include="Core\Utility\UnityHelpers.cs" /> <Compile Include="Core\Utility\UnityHelpers.cs" />

View File

@ -18,6 +18,8 @@ Global
Release_BIE6_Mono|Any CPU = Release_BIE6_Mono|Any CPU Release_BIE6_Mono|Any CPU = Release_BIE6_Mono|Any CPU
Release_ML_Cpp|Any CPU = Release_ML_Cpp|Any CPU Release_ML_Cpp|Any CPU = Release_ML_Cpp|Any CPU
Release_ML_Mono|Any CPU = Release_ML_Mono|Any CPU Release_ML_Mono|Any CPU = Release_ML_Mono|Any CPU
Release_MLLegacy_Cpp|Any CPU = Release_MLLegacy_Cpp|Any CPU
Release_MLLegacy_Mono|Any CPU = Release_MLLegacy_Mono|Any CPU
Release_STANDALONE_Cpp|Any CPU = Release_STANDALONE_Cpp|Any CPU Release_STANDALONE_Cpp|Any CPU = Release_STANDALONE_Cpp|Any CPU
Release_STANDALONE_Mono|Any CPU = Release_STANDALONE_Mono|Any CPU Release_STANDALONE_Mono|Any CPU = Release_STANDALONE_Mono|Any CPU
EndGlobalSection EndGlobalSection
@ -32,6 +34,10 @@ Global
{F2D7872C-5D4D-49EB-A656-C3D496DB4204}.Release_ML_Cpp|Any CPU.Build.0 = 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.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_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.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_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.ActiveCfg = Release|Any CPU
@ -46,6 +52,10 @@ Global
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_ML_Cpp|Any CPU.Build.0 = Release|Any CPU {7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_ML_Cpp|Any CPU.Build.0 = Release|Any CPU
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_ML_Mono|Any CPU.ActiveCfg = Release|Any CPU {7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_ML_Mono|Any CPU.ActiveCfg = Release|Any CPU
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_ML_Mono|Any CPU.Build.0 = Release|Any CPU {7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_ML_Mono|Any CPU.Build.0 = Release|Any CPU
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_MLLegacy_Cpp|Any CPU.ActiveCfg = Release|Any CPU
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_MLLegacy_Cpp|Any CPU.Build.0 = Release|Any CPU
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_MLLegacy_Mono|Any CPU.ActiveCfg = Release|Any CPU
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_MLLegacy_Mono|Any CPU.Build.0 = Release|Any CPU
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release|Any CPU {7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release|Any CPU
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release|Any CPU {7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release|Any CPU
{7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release|Any CPU {7B7E5024-385D-4A46-9196-A6AF8F7FBDD5}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release|Any CPU
@ -60,6 +70,10 @@ Global
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_ML_Cpp|Any CPU.Build.0 = Release|Any CPU {E4989E4C-0875-4528-9031-08E2C0E70103}.Release_ML_Cpp|Any CPU.Build.0 = Release|Any CPU
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_ML_Mono|Any CPU.ActiveCfg = Release|Any CPU {E4989E4C-0875-4528-9031-08E2C0E70103}.Release_ML_Mono|Any CPU.ActiveCfg = Release|Any CPU
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_ML_Mono|Any CPU.Build.0 = Release|Any CPU {E4989E4C-0875-4528-9031-08E2C0E70103}.Release_ML_Mono|Any CPU.Build.0 = Release|Any CPU
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_MLLegacy_Cpp|Any CPU.ActiveCfg = Release|Any CPU
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_MLLegacy_Cpp|Any CPU.Build.0 = Release|Any CPU
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_MLLegacy_Mono|Any CPU.ActiveCfg = Release|Any CPU
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_MLLegacy_Mono|Any CPU.Build.0 = Release|Any CPU
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release|Any CPU {E4989E4C-0875-4528-9031-08E2C0E70103}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release|Any CPU
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release|Any CPU {E4989E4C-0875-4528-9031-08E2C0E70103}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release|Any CPU
{E4989E4C-0875-4528-9031-08E2C0E70103}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release|Any CPU {E4989E4C-0875-4528-9031-08E2C0E70103}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release|Any CPU
@ -74,6 +88,10 @@ Global
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Cpp|Any CPU.Build.0 = Release_ML_Cpp|Any CPU {B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Cpp|Any CPU.Build.0 = Release_ML_Cpp|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Mono|Any CPU.ActiveCfg = Release_ML_Mono|Any CPU {B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Mono|Any CPU.ActiveCfg = Release_ML_Mono|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Mono|Any CPU.Build.0 = Release_ML_Mono|Any CPU {B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_ML_Mono|Any CPU.Build.0 = Release_ML_Mono|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_MLLegacy_Cpp|Any CPU.ActiveCfg = Release_MLLegacy_Cpp|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_MLLegacy_Cpp|Any CPU.Build.0 = Release_MLLegacy_Cpp|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_MLLegacy_Mono|Any CPU.ActiveCfg = Release_MLLegacy_Mono|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_MLLegacy_Mono|Any CPU.Build.0 = Release_MLLegacy_Mono|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release_STANDALONE_Cpp|Any CPU {B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Cpp|Any CPU.ActiveCfg = Release_STANDALONE_Cpp|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release_STANDALONE_Cpp|Any CPU {B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Cpp|Any CPU.Build.0 = Release_STANDALONE_Cpp|Any CPU
{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release_STANDALONE_Mono|Any CPU {B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}.Release_STANDALONE_Mono|Any CPU.ActiveCfg = Release_STANDALONE_Mono|Any CPU