Compare commits

...

27 Commits
4.4.1 ... 4.5.1

Author SHA1 Message Date
177b78f4e7 Bump UniverseLib 2022-01-23 23:12:06 +11:00
3804d0aab0 Update ConfigManager.cs 2022-01-23 23:09:01 +11:00
97a82c1661 Make sure mouse is in target display for resize/dragging/panel operations 2022-01-23 23:08:34 +11:00
96a1cc69fb Bump UniverseLib 2022-01-23 17:44:01 +11:00
589abe6193 Fix panel draggers on display change 2022-01-22 21:44:22 +11:00
91bb58b020 Fix panel resizing on alternate monitors 2022-01-22 21:08:12 +11:00
d67507ead2 Implement DisplayManager, ability to use other monitors 2022-01-22 20:20:44 +11:00
d730fbe49c Update FUNDING.yml 2022-01-19 18:25:16 +11:00
9e0784ce54 Create FUNDING.yml 2022-01-19 18:24:49 +11:00
67c602b32f Use Tomlet for Standalone config, fix ML double reference 2022-01-19 18:20:26 +11:00
8fb7d87ca6 Use Tomlet, simplify panel data saving 2022-01-19 17:34:53 +11:00
c740c3c54d Update README.md 2022-01-18 20:34:15 +11:00
ea7b91f7fd Implement Clipboard and Notifications, misc cleanups 2022-01-18 20:19:20 +11:00
c79223f537 Move MouseInspector dropdown to Inspector panel 2022-01-17 21:00:55 +11:00
aae248bf69 Bump UniverseLib to 1.0.4, use HighlightMethod, add Clipboard (unfinished) 2022-01-17 20:23:58 +11:00
a73e992a0c Remove "Core" namespace, move everything in it up one level 2022-01-17 19:42:05 +11:00
3984550bb6 Bump Unhollower to latest 2022-01-17 19:41:00 +11:00
7928363aeb Bumped UniverseLib to 1.0.3 2022-01-11 05:54:38 +11:00
12758606fa Bump UniverseLib to 1.0.2 2022-01-09 19:56:59 +11:00
c927ac54be Fix potential NullReference in UpdateMouseInspect 2022-01-09 19:20:17 +11:00
9f1df11940 Add some more tests 2022-01-08 17:56:56 +11:00
62354b6aa2 Fix disposed TextWriter bug, add System.Collections to default using 2022-01-08 17:56:48 +11:00
44e57c32c3 Raise LangVersion to 9.0 2022-01-08 17:56:33 +11:00
274352d665 fix ParameterHandler parsing Types 2022-01-02 19:55:09 +11:00
7b477a8b0e Rewrite EvaluateWidget, add BaseArgumentHandler, use autocomplete for InteractiveEnum 2022-01-02 19:43:55 +11:00
e585fc6da0 Allow evaluating non-primitive methods 2022-01-01 21:40:47 +11:00
0dd19345ed Fix FPS drop with MelonLoader 2021-12-28 23:24:44 +11:00
70 changed files with 1692 additions and 1113 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,3 @@
# These are supported funding model platforms
ko_fi: sinaidev

View File

@ -57,7 +57,7 @@ Although UnityExplorer should work out of the box for most Unity games, in some
To adjust the settings, open the config file:
* BepInEx: `BepInEx\config\com.sinai.unityexplorer.cfg`
* MelonLoader: `UserData\MelonPreferences.cfg`
* Standalone: `UnityExplorer\config.ini`
* Standalone: `UnityExplorer\config.cfg`
Try adjusting the following settings and see if it fixes your issues:
* `Startup_Delay_Time` - increase to 5-10 seconds (or more as needed), can fix issues with UnityExplorer being destroyed or corrupted during startup.
@ -109,16 +109,24 @@ The inspector is used to see detailed information on objects of any type and man
### Mouse-Inspect
* The "Mouse Inspect" dropdown on the main UnityExplorer navbar allows you to inspect objects under the mouse.
* The "Mouse Inspect" dropdown in the "Inspector" panel allows you to inspect objects under the mouse.
* <b>World</b>: uses Physics.Raycast to look for Colliders
* <b>UI</b>: uses GraphicRaycasters to find UI objects
### Clipboard
* The "Clipboard" panel allows you to see your current paste value, or clear it (resets it to `null`)
* Can copy the value from any member in a Reflection Inspector, Enumerable or Dictionary, and from the target of any Inspector tab
* Can paste values onto any member in a Reflection Inspector
* Non-parsable arguments in Method/Property Evaluators allow pasting values
* The C# Console has helper methods `Copy(obj)` and `Paste()` for accessing the Clipboard
### Settings
* You can change the settings via the "Options" tab of the menu, or directly from the config file.
* BepInEx: `BepInEx\config\com.sinai.unityexplorer.cfg`
* MelonLoader: `UserData\MelonPreferences.cfg`
* Standalone `{DLL_location}\UnityExplorer\config.ini`
* Standalone `{DLL_location}\UnityExplorer\config.cfg`
# Building

View File

@ -27,6 +27,7 @@ namespace UnityExplorer.CSConsole
private static HashSet<string> usingDirectives;
private static StringBuilder evaluatorOutput;
private static StringWriter evaluatorStringWriter;
public static CSConsolePanel Panel => UIManager.GetPanel<CSConsolePanel>(UIManager.Panels.CSConsole);
public static InputFieldRef Input => Panel.Input;
@ -46,6 +47,7 @@ namespace UnityExplorer.CSConsole
"System",
"System.Linq",
"System.Text",
"System.Collections",
"System.Collections.Generic",
"UnityEngine",
#if CPP
@ -130,6 +132,12 @@ namespace UnityExplorer.CSConsole
#region Evaluating
private static void GenerateTextWriter()
{
evaluatorOutput = new StringBuilder();
evaluatorStringWriter = new StringWriter(evaluatorOutput);
}
public static void ResetConsole() => ResetConsole(true);
public static void ResetConsole(bool logSuccess = true)
@ -140,8 +148,8 @@ namespace UnityExplorer.CSConsole
if (Evaluator != null)
Evaluator.Dispose();
evaluatorOutput = new StringBuilder();
Evaluator = new ScriptEvaluator(new StringWriter(evaluatorOutput))
GenerateTextWriter();
Evaluator = new ScriptEvaluator(evaluatorStringWriter)
{
InteractiveBaseClass = typeof(ScriptInteraction)
};
@ -176,6 +184,12 @@ namespace UnityExplorer.CSConsole
if (SRENotSupported)
return;
if (evaluatorStringWriter == null || evaluatorOutput == null)
{
GenerateTextWriter();
Evaluator._textWriter = evaluatorStringWriter;
}
try
{
// Compile the code. If it returned a CompiledMethod, it is REPL.
@ -589,7 +603,7 @@ If the game was built with Unity's stubbed netstandard 2.0 runtime, you can fix
}
}
private static readonly Dictionary<string, string> helpDict = new Dictionary<string, string>();
private static readonly Dictionary<string, string> helpDict = new();
public static void SetupHelpInteraction()
{
@ -644,15 +658,17 @@ var x = 5;
++x;
/* The following helpers are available in REPL mode:
* GetUsing(); - prints the current using directives to the console log
* GetVars(); - prints the names and values of the REPL variables you have defined
* GetClasses(); - prints the names and members of the classes you have defined
* Log(obj); - prints a message to the console log
* CurrentTarget; - System.Object, the target of the active Inspector tab
* AllTargets; - System.Object[], the targets of all Inspector tabs
* Log(obj); - prints a message to the console log
* Inspect(obj); - inspect the object with the Inspector
* Inspect(someType); - inspect a Type with static reflection
* Start(enumerator); - starts the IEnumerator as a Coroutine
* Copy(obj); - copies the object to the UnityExplorer Clipboard
* Paste(); - System.Object, the contents of the Clipboard.
* GetUsing(); - prints the current using directives to the console log
* GetVars(); - prints the names and values of the REPL variables you have defined
* GetClasses(); - prints the names and members of the classes you have defined
* help; - the default REPL help command, contains additional helpers.
*/";

View File

@ -5,41 +5,40 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Runtime;
using UnityExplorer.UI.Panels;
using UniverseLib;
namespace UnityExplorer.CSConsole
{
public class ScriptInteraction : InteractiveBase
{
public static object CurrentTarget
=> InspectorManager.ActiveInspector?.Target;
public static object[] AllTargets
=> InspectorManager.Inspectors.Select(it => it.Target).ToArray();
public static void Log(object message)
{
ExplorerCore.Log(message);
}
public static object CurrentTarget => InspectorManager.ActiveInspector?.Target;
public static object[] AllTargets => InspectorManager.Inspectors.Select(it => it.Target).ToArray();
=> ExplorerCore.Log(message);
public static void Inspect(object obj)
{
InspectorManager.Inspect(obj);
}
=> InspectorManager.Inspect(obj);
public static void Inspect(Type type)
{
InspectorManager.Inspect(type);
}
=> InspectorManager.Inspect(type);
public static void Start(IEnumerator ienumerator)
{
RuntimeProvider.Instance.StartCoroutine(ienumerator);
}
=> RuntimeProvider.Instance.StartCoroutine(ienumerator);
public static void Copy(object obj)
=> ClipboardPanel.Copy(obj);
public static object Paste()
=> ClipboardPanel.Current;
public static void GetUsing()
{
Log(Evaluator.GetUsing());
}
=> Log(Evaluator.GetUsing());
public static void GetVars()
{

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.CacheObject.Views;
namespace UnityExplorer.CacheObject
@ -44,6 +44,6 @@ namespace UnityExplorer.CacheObject
RefConfigElement.BoxedValue = value;
}
protected override bool SetCellEvaluateState(CacheObjectCell cell) => false;
protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell) => true;
}
}

View File

@ -92,10 +92,6 @@ namespace UnityExplorer.CacheObject
}
protected override bool SetCellEvaluateState(CacheObjectCell cell)
{
// not needed
return false;
}
protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell) => true;
}
}

View File

@ -13,7 +13,7 @@ namespace UnityExplorer.CacheObject
public override bool ShouldAutoEvaluate => true;
public override bool HasArguments => false;
public override bool CanWrite => Owner.CanWrite;
public override bool CanWrite => Owner?.CanWrite ?? false;
public void SetListOwner(InteractiveList list, int listIndex)
{
@ -37,11 +37,6 @@ namespace UnityExplorer.CacheObject
(Owner as InteractiveList).TrySetValueToIndex(value, this.ListIndex);
}
protected override bool SetCellEvaluateState(CacheObjectCell cell)
{
// not needed
return false;
}
protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell) => true;
}
}

View File

@ -4,13 +4,14 @@ using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Runtime;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Inspectors;
using UniverseLib.UI.Models;
using UnityExplorer.UI;
using UniverseLib;
using UniverseLib.UI;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.CacheObject
{
@ -31,7 +32,9 @@ namespace UnityExplorer.CacheObject
public virtual void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member)
{
this.Owner = inspector;
this.NameLabelText = SignatureHighlighter.Parse(member.DeclaringType, false, member);
this.NameLabelText = this is CacheMethod
? SignatureHighlighter.HighlightMethod(member as MethodInfo)
: SignatureHighlighter.Parse(member.DeclaringType, false, member);
this.NameForFiltering = $"{member.DeclaringType.Name}.{member.Name}";
this.NameLabelTextRaw = NameForFiltering;
}
@ -92,7 +95,7 @@ namespace UnityExplorer.CacheObject
private static readonly Color evalEnabledColor = new Color(0.15f, 0.25f, 0.15f);
private static readonly Color evalDisabledColor = new Color(0.15f, 0.15f, 0.15f);
protected override bool SetCellEvaluateState(CacheObjectCell objectcell)
protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell objectcell)
{
var cell = objectcell as CacheMemberCell;
@ -123,13 +126,13 @@ namespace UnityExplorer.CacheObject
SetValueState(cell, ValueStateArgs.Default);
cell.RefreshSubcontentButton();
return true;
return false;
}
if (State == ValueState.NotEvaluated)
Evaluate();
return false;
return true;
}
public void OnEvaluateClicked()
@ -145,7 +148,7 @@ namespace UnityExplorer.CacheObject
this.Evaluator = Pool<EvaluateWidget>.Borrow();
Evaluator.OnBorrowedFromPool(this);
Evaluator.UIRoot.transform.SetParent((CellView as CacheMemberCell).EvaluateHolder.transform, false);
SetCellEvaluateState(CellView);
TryAutoEvaluateIfUnitialized(CellView);
}
else
{
@ -154,7 +157,7 @@ namespace UnityExplorer.CacheObject
else
Evaluator.UIRoot.SetActive(true);
SetCellEvaluateState(CellView);
TryAutoEvaluateIfUnitialized(CellView);
}
}
}
@ -162,22 +165,22 @@ namespace UnityExplorer.CacheObject
#region Cache Member Util
public static bool CanParseArgs(ParameterInfo[] parameters)
{
foreach (var param in parameters)
{
var pType = param.ParameterType;
if (pType.IsByRef && pType.HasElementType)
pType = pType.GetElementType();
if (pType != null && ParseUtility.CanParse(pType))
continue;
else
return false;
}
return true;
}
//public static bool CanParseArgs(ParameterInfo[] parameters)
//{
// foreach (var param in parameters)
// {
// var pType = param.ParameterType;
//
// if (pType.IsByRef && pType.HasElementType)
// pType = pType.GetElementType();
//
// if (pType != null && ParseUtility.CanParse(pType))
// continue;
// else
// return false;
// }
// return true;
//}
public static List<CacheMember> GetCacheMembers(object inspectorTarget, Type _type, ReflectionInspector _inspector)
{
@ -250,11 +253,11 @@ namespace UnityExplorer.CacheObject
&& (mi.Name.StartsWith("get_") || mi.Name.StartsWith("set_")))
return;
var args = mi.GetParameters();
if (!CanParseArgs(args))
return;
//var args = mi.GetParameters();
//if (!CanParseArgs(args))
// return;
sig += GetArgumentString(args);
sig += GetArgumentString(mi.GetParameters());
if (cachedSigs.Contains(sig))
return;
@ -267,9 +270,9 @@ namespace UnityExplorer.CacheObject
{
var pi = member as PropertyInfo;
var args = pi.GetIndexParameters();
if (!CanParseArgs(args))
return;
//var args = pi.GetIndexParameters();
//if (!CanParseArgs(args))
// return;
if (!pi.CanRead && pi.CanWrite)
{
@ -280,7 +283,7 @@ namespace UnityExplorer.CacheObject
return;
}
sig += GetArgumentString(args);
sig += GetArgumentString(pi.GetIndexParameters());
if (cachedSigs.Contains(sig))
return;

View File

@ -6,7 +6,7 @@ using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Runtime;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.CacheObject.Views;
using UniverseLib.UI.Models;
@ -254,8 +254,8 @@ namespace UnityExplorer.CacheObject
// Setting cell state from our model
/// <summary>Return true if SetCell should abort, false if it should continue.</summary>
protected abstract bool SetCellEvaluateState(CacheObjectCell cell);
/// <summary>Return false if SetCell should abort, true if it should continue.</summary>
protected abstract bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell);
public virtual void SetDataToCell(CacheObjectCell cell)
{
@ -271,9 +271,21 @@ namespace UnityExplorer.CacheObject
IValue.SetLayout();
}
if (SetCellEvaluateState(cell))
bool evaluated = TryAutoEvaluateIfUnitialized(cell);
if (cell.CopyButton != null)
{
bool hasEvaluated = State != ValueState.NotEvaluated && State != ValueState.Exception;
cell.CopyButton.Component.gameObject.SetActive(hasEvaluated);
cell.PasteButton.Component.gameObject.SetActive(hasEvaluated && this.CanWrite);
}
if (!evaluated)
return;
// The following only executes if the object has evaluated.
// For members and properties with args, they will return by default now.
switch (State)
{
case ValueState.Exception:

View File

@ -7,6 +7,8 @@ using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.UI;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib;
using UniverseLib.UI;
namespace UnityExplorer.CacheObject.IValues
@ -20,10 +22,10 @@ namespace UnityExplorer.CacheObject.IValues
public OrderedDictionary CurrentValues;
public CachedEnumValue ValueAtIdx(int idx) => (CachedEnumValue)CurrentValues[idx];
public CachedEnumValue ValueAtKey(object key) => (CachedEnumValue)CurrentValues[key];
private InputFieldRef inputField;
private ButtonRef enumHelperButton;
private EnumCompleter enumCompleter;
private Dropdown enumDropdown;
private GameObject toggleHolder;
private readonly List<Toggle> flagToggles = new List<Toggle>();
private readonly List<Text> flagTexts = new List<Text>();
@ -35,38 +37,68 @@ namespace UnityExplorer.CacheObject.IValues
if (lastType != EnumType)
{
CurrentValues = GetEnumValues(EnumType, out IsFlags);
CurrentValues = GetEnumValues(EnumType);
IsFlags = EnumType.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] fa && fa.Any();
if (IsFlags)
SetupTogglesForEnumType();
else
SetupDropdownForEnumType();
{
inputField.Component.gameObject.SetActive(true);
enumHelperButton.Component.gameObject.SetActive(true);
toggleHolder.SetActive(false);
}
enumCompleter.EnumType = EnumType;
enumCompleter.CacheEnumValues();
lastType = EnumType;
}
// setup ui for changes
if (IsFlags)
SetTogglesForValue(value);
if (!IsFlags)
inputField.Text = value.ToString();
else
SetDropdownForValue(value);
SetTogglesForValue(value);
this.enumCompleter.chosenSuggestion = value.ToString();
AutoCompleteModal.Instance.ReleaseOwnership(this.enumCompleter);
}
private void SetTogglesForValue(object value)
{
try
{
var split = value.ToString().Split(',');
var set = new HashSet<string>();
foreach (var s in split)
set.Add(s.Trim());
for (int i = 0; i < CurrentValues.Count; i++)
flagToggles[i].isOn = set.Contains(ValueAtIdx(i).Name);
}
catch (Exception ex)
{
ExplorerCore.LogWarning("Exception setting flag toggles: " + ex);
}
}
// Setting value to owner
private void OnApplyClicked()
{
if (IsFlags)
SetValueFromFlags();
else
SetValueFromDropdown();
}
private void SetValueFromDropdown()
{
try
{
CurrentOwner.SetUserValue(ValueAtIdx(enumDropdown.value).ActualValue);
if (!IsFlags)
{
if (ParseUtility.TryParse(this.inputField.Text, EnumType, out object value, out Exception ex))
CurrentOwner.SetUserValue(value);
else
throw ex;
}
else
{
SetValueFromFlags();
}
}
catch (Exception ex)
{
@ -93,59 +125,53 @@ namespace UnityExplorer.CacheObject.IValues
}
}
// setting UI state for value
// UI Construction
private void SetDropdownForValue(object value)
private void EnumHelper_OnClick()
{
if (CurrentValues.Contains(value))
{
var cached = ValueAtKey(value);
enumDropdown.value = cached.EnumIndex;
enumDropdown.RefreshShownValue();
}
else
ExplorerCore.LogWarning("CurrentValues does not contain key '" + value?.ToString() ?? "<null>" + "'");
enumCompleter.HelperButtonClicked();
}
private void SetTogglesForValue(object value)
public override GameObject CreateContent(GameObject parent)
{
try
{
var split = value.ToString().Split(',');
var set = new HashSet<string>();
foreach (var s in split)
set.Add(s.Trim());
UIRoot = UIFactory.CreateVerticalGroup(parent, "InteractiveEnum", false, false, true, true, 3, new Vector4(4, 4, 4, 4),
new Color(0.06f, 0.06f, 0.06f));
UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleHeight: 9999, flexibleWidth: 9999);
for (int i = 0; i < CurrentValues.Count; i++)
flagToggles[i].isOn = set.Contains(ValueAtIdx(i).Name);
}
catch (Exception ex)
{
ExplorerCore.LogWarning("Exception setting flag toggles: " + ex);
}
var hori = UIFactory.CreateUIObject("Hori", UIRoot);
UIFactory.SetLayoutElement(hori, minHeight: 25, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(hori, false, false, true, true, 2);
var applyButton = UIFactory.CreateButton(hori, "ApplyButton", "Apply", new Color(0.2f, 0.27f, 0.2f));
UIFactory.SetLayoutElement(applyButton.Component.gameObject, minHeight: 25, minWidth: 100);
applyButton.OnClick += OnApplyClicked;
inputField = UIFactory.CreateInputField(hori, "InputField", "Enter name or underlying value...");
UIFactory.SetLayoutElement(inputField.UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000);
inputField.Component.lineType = InputField.LineType.MultiLineNewline;
inputField.UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
enumHelperButton = UIFactory.CreateButton(hori, "EnumHelper", "▼");
UIFactory.SetLayoutElement(enumHelperButton.Component.gameObject, minWidth: 25, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
enumHelperButton.OnClick += EnumHelper_OnClick;
enumCompleter = new EnumCompleter(this.EnumType, this.inputField);
toggleHolder = UIFactory.CreateUIObject("ToggleHolder", UIRoot);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(toggleHolder, false, false, true, true, 4);
UIFactory.SetLayoutElement(toggleHolder, minHeight: 25, flexibleWidth: 9999, flexibleHeight: 9999);
return UIRoot;
}
// Setting up the UI for the enum type when it changes or is first set
private void SetupDropdownForEnumType()
{
toggleHolder.SetActive(false);
enumDropdown.gameObject.SetActive(true);
// create dropdown entries
enumDropdown.options.Clear();
foreach (CachedEnumValue entry in CurrentValues.Values)
enumDropdown.options.Add(new Dropdown.OptionData(entry.Name));
enumDropdown.value = 0;
enumDropdown.RefreshShownValue();
}
public CachedEnumValue ValueAtIdx(int idx) => (CachedEnumValue)CurrentValues[idx];
public CachedEnumValue ValueAtKey(object key) => (CachedEnumValue)CurrentValues[key];
private void SetupTogglesForEnumType()
{
toggleHolder.SetActive(true);
enumDropdown.gameObject.SetActive(false);
inputField.Component.gameObject.SetActive(false);
enumHelperButton.Component.gameObject.SetActive(false);
// create / set / hide toggles
for (int i = 0; i < CurrentValues.Count || i < flagToggles.Count; i++)
@ -180,54 +206,13 @@ namespace UnityExplorer.CacheObject.IValues
flagTexts.Add(toggleText);
}
// UI Construction
public override GameObject CreateContent(GameObject parent)
{
UIRoot = UIFactory.CreateVerticalGroup(parent, "InteractiveEnum", false, false, true, true, 3, new Vector4(4, 4, 4, 4),
new Color(0.06f, 0.06f, 0.06f));
UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleHeight: 9999, flexibleWidth: 9999);
var hori = UIFactory.CreateUIObject("Hori", UIRoot);
UIFactory.SetLayoutElement(hori, minHeight: 25, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(hori, false, false, true, true, 2);
var applyButton = UIFactory.CreateButton(hori, "ApplyButton", "Apply", new Color(0.2f, 0.27f, 0.2f));
UIFactory.SetLayoutElement(applyButton.Component.gameObject, minHeight: 25, minWidth: 100);
applyButton.OnClick += OnApplyClicked;
var dropdownObj = UIFactory.CreateDropdown(hori, out enumDropdown, "not set", 14, null);
UIFactory.SetLayoutElement(dropdownObj, minHeight: 25, flexibleWidth: 600);
toggleHolder = UIFactory.CreateUIObject("ToggleHolder", UIRoot);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(toggleHolder, false, false, true, true, 4);
UIFactory.SetLayoutElement(toggleHolder, minHeight: 25, flexibleWidth: 9999, flexibleHeight: 9999);
return UIRoot;
}
#region Enum cache
public struct CachedEnumValue
{
public CachedEnumValue(object value, int index, string name)
{
EnumIndex = index;
Name = name;
ActualValue = value;
}
public readonly object ActualValue;
public int EnumIndex;
public readonly string Name;
}
internal static readonly Dictionary<string, OrderedDictionary> enumCache = new Dictionary<string, OrderedDictionary>();
internal static OrderedDictionary GetEnumValues(Type enumType, out bool isFlags)
internal static OrderedDictionary GetEnumValues(Type enumType)
{
isFlags = enumType.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] fa && fa.Any();
//isFlags = enumType.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] fa && fa.Any();
if (!enumCache.ContainsKey(enumType.AssemblyQualifiedName))
{
@ -254,4 +239,18 @@ namespace UnityExplorer.CacheObject.IValues
#endregion
}
public struct CachedEnumValue
{
public CachedEnumValue(object value, int index, string name)
{
EnumIndex = index;
Name = name;
ActualValue = value;
}
public readonly object ActualValue;
public int EnumIndex;
public readonly string Name;
}
}

View File

@ -32,11 +32,13 @@ namespace UnityExplorer.CacheObject.IValues
private PropertyInfo genericIndexer;
public int ItemCount => cachedEntries.Count;
private readonly List<CacheListEntry> cachedEntries = new List<CacheListEntry>();
private readonly List<CacheListEntry> cachedEntries = new();
public ScrollPool<CacheListEntryCell> ListScrollPool { get; private set; }
public Text TopLabel;
private LayoutElement scrollLayout;
private Text NotSupportedLabel;
public override void OnBorrowed(CacheObjectBase owner)
{
@ -65,6 +67,28 @@ namespace UnityExplorer.CacheObject.IValues
cachedEntries.Clear();
}
// List entry scroll pool
public override void SetLayout()
{
var minHeight = 5f;
foreach (var cell in ListScrollPool.CellPool)
{
if (cell.Enabled)
minHeight += cell.Rect.rect.height;
}
this.scrollLayout.minHeight = Math.Min(InspectorPanel.CurrentPanelHeight - 400f, minHeight);
}
public void OnCellBorrowed(CacheListEntryCell cell) { } // not needed
public void SetCell(CacheListEntryCell cell, int index)
{
CacheObjectControllerHelper.SetCell(cell, index, cachedEntries, null);
}
// Setting the List value itself to this model
public override void SetValue(object value)
{
@ -212,32 +236,6 @@ namespace UnityExplorer.CacheObject.IValues
}
}
// List entry scroll pool
public override void SetLayout()
{
var minHeight = 5f;
foreach (var cell in ListScrollPool.CellPool)
{
if (cell.Enabled)
minHeight += cell.Rect.rect.height;
}
this.scrollLayout.minHeight = Math.Min(InspectorPanel.CurrentPanelHeight - 400f, minHeight);
}
public void OnCellBorrowed(CacheListEntryCell cell) { } // not needed
public void SetCell(CacheListEntryCell cell, int index)
{
CacheObjectControllerHelper.SetCell(cell, index, cachedEntries, null);
}
private LayoutElement scrollLayout;
private Text NotSupportedLabel;
public override GameObject CreateContent(GameObject parent)
{
UIRoot = UIFactory.CreateVerticalGroup(parent, "InteractiveList", true, true, true, true, 6, new Vector4(10, 3, 15, 4),

View File

@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.CacheObject;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI;

View File

@ -12,15 +12,11 @@ namespace UnityExplorer.CacheObject.Views
{
public class CacheMemberCell : CacheObjectCell
{
//public ReflectionInspector Owner { get; set; }
public CacheMember MemberOccupant => Occupant as CacheMember;
public GameObject EvaluateHolder;
public ButtonRef EvaluateButton;
//public Toggle UpdateToggle;
protected virtual void EvaluateClicked()
{
this.MemberOccupant.OnEvaluateClicked();
@ -38,16 +34,5 @@ namespace UnityExplorer.CacheObject.Views
UIFactory.SetLayoutElement(EvaluateButton.Component.gameObject, minWidth: 100, minHeight: 25);
EvaluateButton.OnClick += EvaluateClicked;
}
//protected override void ConstructUpdateToggle(GameObject parent)
//{
// // Auto-update toggle
//
// var updateToggle = UIFactory.CreateToggle(parent, "AutoUpdate", out UpdateToggle, out Text autoText);
// UIFactory.SetLayoutElement(updateToggle, minHeight: 25, minWidth: 30, flexibleWidth: 0, flexibleHeight: 0);
// GameObject.Destroy(autoText);
// UpdateToggle.isOn = false;
// UpdateToggle.onValueChanged.AddListener((bool val) => { MemberOccupant.AutoUpdateWanted = val; });
//}
}
}

View File

@ -7,6 +7,7 @@ using UnityEngine.UI;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.Inspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UniverseLib;
using UniverseLib.UI;
@ -45,10 +46,12 @@ namespace UnityExplorer.CacheObject.Views
public bool SubContentActive => SubContentHolder.activeSelf;
public LayoutElement NameLayout;
public GameObject RightGroupContent;
public LayoutElement RightGroupLayout;
public GameObject SubContentHolder;
public Text NameLabel;
public InputFieldRef HiddenNameLabel;
public InputFieldRef HiddenNameLabel; // for selecting the name label
public Text TypeLabel;
public Text ValueLabel;
public Toggle Toggle;
@ -59,7 +62,11 @@ namespace UnityExplorer.CacheObject.Views
public ButtonRef SubContentButton;
public ButtonRef ApplyButton;
public GameObject SubContentHolder;
public ButtonRef CopyButton;
public ButtonRef PasteButton;
public readonly Color subInactiveColor = new(0.23f, 0.23f, 0.23f);
public readonly Color subActiveColor = new(0.23f, 0.33f, 0.23f);
protected virtual void ApplyClicked()
{
@ -81,26 +88,26 @@ namespace UnityExplorer.CacheObject.Views
this.Occupant.OnCellSubContentToggle();
}
public readonly Color subInactiveColor = new Color(0.23f, 0.23f, 0.23f);
public readonly Color subActiveColor = new Color(0.23f, 0.33f, 0.23f);
protected virtual void OnCopyClicked()
{
ClipboardPanel.Copy(this.Occupant.Value);
}
protected virtual void OnPasteClicked()
{
if (ClipboardPanel.TryPaste(this.Occupant.FallbackType, out object paste))
this.Occupant.SetUserValue(paste);
}
public void RefreshSubcontentButton()
{
if (!this.SubContentHolder.activeSelf)
{
this.SubContentButton.ButtonText.text = "▲";
RuntimeProvider.Instance.SetColorBlock(SubContentButton.Component, subInactiveColor, subInactiveColor * 1.3f);
}
else
{
this.SubContentButton.ButtonText.text = "▼";
RuntimeProvider.Instance.SetColorBlock(SubContentButton.Component, subActiveColor, subActiveColor * 1.3f);
}
this.SubContentButton.ButtonText.text = SubContentHolder.activeSelf ? "▼" : "▲";
Color color = SubContentHolder.activeSelf ? subActiveColor : subInactiveColor;
RuntimeProvider.Instance.SetColorBlock(SubContentButton.Component, color, color * 1.3f);
}
protected abstract void ConstructEvaluateHolder(GameObject parent);
public virtual GameObject CreateContent(GameObject parent)
{
// Main layout
@ -136,16 +143,16 @@ namespace UnityExplorer.CacheObject.Views
// Right vertical group
var rightGroupHolder = UIFactory.CreateUIObject("RightGroup", horiRow);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(rightGroupHolder, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
UIFactory.SetLayoutElement(rightGroupHolder, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800);
RightGroupLayout = rightGroupHolder.GetComponent<LayoutElement>();
RightGroupContent = UIFactory.CreateUIObject("RightGroup", horiRow);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(RightGroupContent, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
UIFactory.SetLayoutElement(RightGroupContent, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800);
RightGroupLayout = RightGroupContent.GetComponent<LayoutElement>();
ConstructEvaluateHolder(rightGroupHolder);
ConstructEvaluateHolder(RightGroupContent);
// Right horizontal group
var rightHoriGroup = UIFactory.CreateUIObject("RightHoriGroup", rightGroupHolder);
var rightHoriGroup = UIFactory.CreateUIObject("RightHoriGroup", RightGroupContent);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(rightHoriGroup, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
UIFactory.SetLayoutElement(rightHoriGroup, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800);
@ -157,7 +164,7 @@ namespace UnityExplorer.CacheObject.Views
TypeLabel = UIFactory.CreateLabel(rightHoriGroup, "ReturnLabel", "<notset>", TextAnchor.MiddleLeft);
TypeLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
UIFactory.SetLayoutElement(TypeLabel.gameObject, minHeight: 25, flexibleHeight: 150, minWidth: 60, flexibleWidth: 0);
UIFactory.SetLayoutElement(TypeLabel.gameObject, minHeight: 25, flexibleHeight: 150, minWidth: 45, flexibleWidth: 0);
// Bool and number value interaction
@ -187,6 +194,24 @@ namespace UnityExplorer.CacheObject.Views
ValueLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
UIFactory.SetLayoutElement(ValueLabel.gameObject, minHeight: 25, flexibleHeight: 150, flexibleWidth: 9999);
// Copy and Paste buttons
var buttonHolder = UIFactory.CreateHorizontalGroup(rightHoriGroup, "CopyPasteButtons", false, false, true, true, 4,
bgColor: new(1,1,1,0), childAlignment: TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(buttonHolder, minWidth: 60, flexibleWidth: 0);
CopyButton = UIFactory.CreateButton(buttonHolder, "CopyButton", "Copy", new Color(0.13f, 0.13f, 0.13f, 1f));
UIFactory.SetLayoutElement(CopyButton.Component.gameObject, minHeight: 25, minWidth: 28, flexibleWidth: 0);
CopyButton.ButtonText.color = Color.yellow;
CopyButton.ButtonText.fontSize = 10;
CopyButton.OnClick += OnCopyClicked;
PasteButton = UIFactory.CreateButton(buttonHolder, "PasteButton", "Paste", new Color(0.13f, 0.13f, 0.13f, 1f));
UIFactory.SetLayoutElement(PasteButton.Component.gameObject, minHeight: 25, minWidth: 28, flexibleWidth: 0);
PasteButton.ButtonText.color = Color.green;
PasteButton.ButtonText.fontSize = 10;
PasteButton.OnClick += OnPasteClicked;
// Subcontent
SubContentHolder = UIFactory.CreateUIObject("SubContent", UIRoot);

View File

@ -1,289 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib;
namespace UnityExplorer.CacheObject.Views
{
public class EvaluateWidget : IPooledObject
{
public CacheMember Owner { get; set; }
public GameObject UIRoot { get; set; }
public float DefaultHeight => -1f;
private ParameterInfo[] arguments;
private string[] argumentInput;
private GameObject argHolder;
private readonly List<GameObject> argRows = new List<GameObject>();
private readonly List<Text> argLabels = new List<Text>();
private Type[] genericArguments;
private string[] genericInput;
private GameObject genericArgHolder;
private readonly List<GameObject> genericArgRows = new List<GameObject>();
private readonly List<Text> genericArgLabels = new List<Text>();
private readonly List<TypeCompleter> genericAutocompleters = new List<TypeCompleter>();
//private readonly List<InputFieldRef> inputFields = new List<InputFieldRef>();
private readonly List<InputFieldRef> argInputFields = new List<InputFieldRef>();
private readonly List<InputFieldRef> genericInputFields = new List<InputFieldRef>();
public void OnBorrowedFromPool(CacheMember owner)
{
this.Owner = owner;
arguments = owner.Arguments;
argumentInput = new string[arguments.Length];
genericArguments = owner.GenericArguments;
genericInput = new string[genericArguments.Length];
SetArgRows();
this.UIRoot.SetActive(true);
}
public void OnReturnToPool()
{
foreach (var input in argInputFields)
input.Text = "";
foreach (var input in genericInputFields)
input.Text = "";
this.Owner = null;
}
public Type[] TryParseGenericArguments()
{
Type[] outArgs = new Type[genericArguments.Length];
for (int i = 0; i < genericArguments.Length; i++)
{
outArgs[i] = ReflectionUtility.GetTypeByName(genericInput[i])
?? throw new Exception($"Could not find any type by name '{genericInput[i]}'!");
}
return outArgs;
}
public object[] TryParseArguments()
{
object[] outArgs = new object[arguments.Length];
for (int i = 0; i < arguments.Length; i++)
{
var arg = arguments[i];
var input = argumentInput[i];
var type = arg.ParameterType;
if (type.IsByRef)
type = type.GetElementType();
if (type == typeof(string))
{
outArgs[i] = input;
continue;
}
if (string.IsNullOrEmpty(input))
{
if (arg.IsOptional)
outArgs[i] = arg.DefaultValue;
else
outArgs[i] = null;
continue;
}
if (!ParseUtility.TryParse(input, type, out outArgs[i], out Exception ex))
{
outArgs[i] = null;
ExplorerCore.LogWarning($"Cannot parse argument '{arg.Name}' ({arg.ParameterType.Name})" +
$"{(ex == null ? "" : $", {ex.GetType().Name}: {ex.Message}")}");
}
}
return outArgs;
}
private void SetArgRows()
{
if (genericArguments.Any())
{
genericArgHolder.SetActive(true);
SetGenericRows();
}
else
genericArgHolder.SetActive(false);
if (arguments.Any())
{
argHolder.SetActive(true);
SetNormalArgRows();
}
else
argHolder.SetActive(false);
}
private void SetGenericRows()
{
for (int i = 0; i < genericArguments.Length || i < genericArgRows.Count; i++)
{
if (i >= genericArguments.Length)
{
if (i >= genericArgRows.Count)
break;
else
// exceeded actual args, but still iterating so there must be views left, disable them
genericArgRows[i].SetActive(false);
continue;
}
var arg = genericArguments[i];
if (i >= genericArgRows.Count)
AddArgRow(i, true);
genericArgRows[i].SetActive(true);
var autoCompleter = genericAutocompleters[i];
autoCompleter.BaseType = arg;
autoCompleter.CacheTypes();
var constraints = arg.GetGenericParameterConstraints();
autoCompleter.GenericConstraints = constraints;
var sb = new StringBuilder($"<color={SignatureHighlighter.CONST}>{arg.Name}</color>");
for (int j = 0; j < constraints.Length; j++)
{
if (j == 0) sb.Append(' ').Append('(');
else sb.Append(',').Append(' ');
sb.Append(SignatureHighlighter.Parse(constraints[j], false));
if (j + 1 == constraints.Length)
sb.Append(')');
}
genericArgLabels[i].text = sb.ToString();
}
}
private void SetNormalArgRows()
{
for (int i = 0; i < arguments.Length || i < argRows.Count; i++)
{
if (i >= arguments.Length)
{
if (i >= argRows.Count)
break;
else
// exceeded actual args, but still iterating so there must be views left, disable them
argRows[i].SetActive(false);
continue;
}
var arg = arguments[i];
if (i >= argRows.Count)
AddArgRow(i, false);
argRows[i].SetActive(true);
argLabels[i].text = $"{SignatureHighlighter.Parse(arg.ParameterType, false)} <color={SignatureHighlighter.LOCAL_ARG}>{arg.Name}</color>";
if (arg.ParameterType == typeof(string))
argInputFields[i].PlaceholderText.text = "";
else
{
var elemType = arg.ParameterType;
if (elemType.IsByRef)
elemType = elemType.GetElementType();
argInputFields[i].PlaceholderText.text = $"eg. {ParseUtility.GetExampleInput(elemType)}";
}
}
}
private void AddArgRow(int index, bool generic)
{
if (!generic)
AddArgRow(index, argHolder, argRows, argLabels, argumentInput, false);
else
AddArgRow(index, genericArgHolder, genericArgRows, genericArgLabels, genericInput, true);
}
private void AddArgRow(int index, GameObject parent, List<GameObject> objectList, List<Text> labelList, string[] inputArray, bool generic)
{
var horiGroup = UIFactory.CreateUIObject("ArgRow_" + index, parent);
UIFactory.SetLayoutElement(horiGroup, minHeight: 25, flexibleHeight: 50, minWidth: 50, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(horiGroup, false, false, true, true, 5);
horiGroup.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
objectList.Add(horiGroup);
var label = UIFactory.CreateLabel(horiGroup, "ArgLabel", "not set", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(label.gameObject, minWidth: 40, flexibleWidth: 90, minHeight: 25, flexibleHeight: 50);
labelList.Add(label);
label.horizontalOverflow = HorizontalWrapMode.Wrap;
var inputField = UIFactory.CreateInputField(horiGroup, "InputField", "...");
UIFactory.SetLayoutElement(inputField.UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000);
inputField.Component.lineType = InputField.LineType.MultiLineNewline;
inputField.UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
inputField.OnValueChanged += (string val) => { inputArray[index] = val; };
if (!generic)
argInputFields.Add(inputField);
else
genericInputFields.Add(inputField);
if (generic)
genericAutocompleters.Add(new TypeCompleter(null, inputField));
}
public GameObject CreateContent(GameObject parent)
{
UIRoot = UIFactory.CreateVerticalGroup(parent, "EvaluateWidget", false, false, true, true, 3, new Vector4(2, 2, 2, 2),
new Color(0.15f, 0.15f, 0.15f));
UIFactory.SetLayoutElement(UIRoot, minWidth: 50, flexibleWidth: 9999, minHeight: 50, flexibleHeight: 800);
//UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// generic args
this.genericArgHolder = UIFactory.CreateUIObject("GenericHolder", UIRoot);
UIFactory.SetLayoutElement(genericArgHolder, flexibleWidth: 1000);
var genericsTitle = UIFactory.CreateLabel(genericArgHolder, "GenericsTitle", "Generic Arguments", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(genericsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(genericArgHolder, false, false, true, true, 3);
UIFactory.SetLayoutElement(genericArgHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
//genericArgHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// args
this.argHolder = UIFactory.CreateUIObject("ArgHolder", UIRoot);
UIFactory.SetLayoutElement(argHolder, flexibleWidth: 1000);
var argsTitle = UIFactory.CreateLabel(argHolder, "ArgsTitle", "Arguments", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(argsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(argHolder, false, false, true, true, 3);
UIFactory.SetLayoutElement(argHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
//argHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// evaluate button
var evalButton = UIFactory.CreateButton(UIRoot, "EvaluateButton", "Evaluate", new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(evalButton.Component.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0);
evalButton.OnClick += () =>
{
Owner.EvaluateAndSetCell();
};
return UIRoot;
}
}
}

View File

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

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UnityExplorer.Core.Config
namespace UnityExplorer.Config
{
public abstract class ConfigHandler
{

View File

@ -8,15 +8,20 @@ using System.Text;
using UnityEngine;
using UnityExplorer.UI;
namespace UnityExplorer.Core.Config
namespace UnityExplorer.Config
{
public static class ConfigManager
{
internal static readonly Dictionary<string, IConfigElement> ConfigElements = new();
internal static readonly Dictionary<string, IConfigElement> InternalConfigs = new();
// Each Mod Loader has its own ConfigHandler.
// See the UnityExplorer.Loader namespace for the implementations.
public static ConfigHandler Handler { get; private set; }
// Actual UE Settings
public static ConfigElement<KeyCode> Master_Toggle;
public static ConfigElement<int> Target_Display;
public static ConfigElement<UIManager.VerticalAnchor> Main_Navbar_Anchor;
public static ConfigElement<bool> Force_Unlock_Mouse;
public static ConfigElement<KeyCode> Force_Unlock_Toggle;
@ -26,21 +31,18 @@ namespace UnityExplorer.Core.Config
public static ConfigElement<bool> Log_Unity_Debug;
public static ConfigElement<bool> Hide_On_Startup;
public static ConfigElement<float> Startup_Delay_Time;
public static ConfigElement<string> Reflection_Signature_Blacklist;
// internal configs
internal static InternalConfigHandler InternalHandler { get; private set; }
internal static readonly Dictionary<UIManager.Panels, ConfigElement<string>> PanelSaveData = new();
public static ConfigElement<string> ObjectExplorerData;
public static ConfigElement<string> InspectorData;
public static ConfigElement<string> CSConsoleData;
public static ConfigElement<string> OptionsPanelData;
public static ConfigElement<string> ConsoleLogData;
public static ConfigElement<string> HookManagerData;
internal static readonly Dictionary<string, IConfigElement> ConfigElements = new Dictionary<string, IConfigElement>();
internal static readonly Dictionary<string, IConfigElement> InternalConfigs = new Dictionary<string, IConfigElement>();
internal static ConfigElement<string> GetPanelSaveData(UIManager.Panels panel)
{
if (!PanelSaveData.ContainsKey(panel))
PanelSaveData.Add(panel, new ConfigElement<string>(panel.ToString(), string.Empty, string.Empty, true));
return PanelSaveData[panel];
}
public static void Init(ConfigHandler configHandler)
{
@ -78,6 +80,11 @@ namespace UnityExplorer.Core.Config
"The key to enable or disable UnityExplorer's menu and features.",
KeyCode.F7);
Target_Display = new ConfigElement<int>("Target Display",
"The monitor index for UnityExplorer to use, if you have multiple. 0 is the default display, 1 is secondary, etc. " +
"Restart recommended when changing this setting. Make sure your extra monitors are the same resolution as your primary monitor.",
0);
Main_Navbar_Anchor = new ConfigElement<UIManager.VerticalAnchor>("Main Navbar Anchor",
"The vertical anchor of the main UnityExplorer Navbar, in case you want to move it.",
UIManager.VerticalAnchor.Top);
@ -123,15 +130,6 @@ namespace UnityExplorer.Core.Config
"Seperate signatures with a semicolon ';'.\r\n" +
"For example, to blacklist Camera.main, you would add 'UnityEngine.Camera.main;'",
"");
// Internal configs (panel save data)
ObjectExplorerData = new ConfigElement<string>("ObjectExplorer", "", "", true);
InspectorData = new ConfigElement<string>("Inspector", "", "", true);
CSConsoleData = new ConfigElement<string>("CSConsole", "", "", true);
OptionsPanelData = new ConfigElement<string>("OptionsPanel", "", "", true);
ConsoleLogData = new ConfigElement<string>("ConsoleLog", "", "", true);
HookManagerData = new ConfigElement<string>("HookManager", "", "", true);
}
}
}

View File

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

View File

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.UI;
using Tomlet;
using Tomlet.Models;
namespace UnityExplorer.Config
{
public class InternalConfigHandler : ConfigHandler
{
internal static string CONFIG_PATH;
public override void Init()
{
CONFIG_PATH = Path.Combine(ExplorerCore.Loader.ExplorerFolder, "data.cfg");
}
public override void LoadConfig()
{
if (!TryLoadConfig())
SaveConfig();
}
public override void RegisterConfigElement<T>(ConfigElement<T> element)
{
// Not necessary
}
public override void SetConfigValue<T>(ConfigElement<T> element, T value)
{
// Not necessary
}
// Not necessary, just return the value.
public override T GetConfigValue<T>(ConfigElement<T> element) => element.Value;
// Always just auto-save.
public override void OnAnyConfigChanged() => SaveConfig();
public bool TryLoadConfig()
{
try
{
if (!File.Exists(CONFIG_PATH))
return false;
TomlDocument document = TomlParser.ParseFile(CONFIG_PATH);
foreach (var key in document.Keys)
{
var panelKey = (UIManager.Panels)Enum.Parse(typeof(UIManager.Panels), key);
ConfigManager.GetPanelSaveData(panelKey).Value = document.GetString(key);
}
return true;
}
catch (Exception ex)
{
ExplorerCore.LogWarning("Error loading internal data: " + ex.ToString());
return false;
}
}
public override void SaveConfig()
{
if (UIManager.Initializing)
return;
var tomlDocument = TomlDocument.CreateEmpty();
foreach (var entry in ConfigManager.InternalConfigs)
tomlDocument.Put(entry.Key, entry.Value.BoxedValue as string, false);
File.WriteAllText(CONFIG_PATH, tomlDocument.SerializedValue);
}
}
}

View File

@ -1,105 +0,0 @@
using IniParser.Parser;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.UI;
namespace UnityExplorer.Core.Config
{
public class InternalConfigHandler : ConfigHandler
{
internal static IniDataParser _parser;
internal static string INI_PATH;
public override void Init()
{
INI_PATH = Path.Combine(ExplorerCore.Loader.ExplorerFolder, "data.ini");
_parser = new IniDataParser();
_parser.Configuration.CommentString = "#";
}
public override void LoadConfig()
{
if (!TryLoadConfig())
SaveConfig();
}
public override void RegisterConfigElement<T>(ConfigElement<T> element)
{
// Not necessary
}
public override void SetConfigValue<T>(ConfigElement<T> element, T value)
{
// Not necessary
}
public override T GetConfigValue<T>(ConfigElement<T> element)
{
// Not necessary, just return the value.
return element.Value;
}
public override void OnAnyConfigChanged()
{
SaveConfig();
}
public bool TryLoadConfig()
{
try
{
if (!File.Exists(INI_PATH))
return false;
string ini = File.ReadAllText(INI_PATH);
var data = _parser.Parse(ini);
foreach (var config in data.Sections["Config"])
{
if (ConfigManager.InternalConfigs.TryGetValue(config.KeyName, out IConfigElement configElement))
configElement.BoxedValue = StringToConfigValue(config.Value, configElement.ElementType);
}
return true;
}
catch (Exception ex)
{
ExplorerCore.LogWarning("Error loading internal data: " + ex.ToString());
return false;
}
}
public override void SaveConfig()
{
if (UIManager.Initializing)
return;
var data = new IniParser.Model.IniData();
data.Sections.AddSection("Config");
var sec = data.Sections["Config"];
foreach (var entry in ConfigManager.InternalConfigs)
sec.AddKey(entry.Key, entry.Value.BoxedValue.ToString());
File.WriteAllText(INI_PATH, data.ToString());
}
public object StringToConfigValue(string value, Type elementType)
{
if (elementType.IsEnum)
return Enum.Parse(elementType, value);
else if (elementType == typeof(bool))
return bool.Parse(value);
else if (elementType == typeof(int))
return int.Parse(value);
else
return value;
}
}
}

View File

@ -4,11 +4,11 @@ using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.UI;
using UnityExplorer.ObjectExplorer;
using UnityExplorer.UI.Panels;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Runtime;
using UniverseLib.Input;
namespace UnityExplorer
@ -16,7 +16,7 @@ namespace UnityExplorer
public static class ExplorerCore
{
public const string NAME = "UnityExplorer";
public const string VERSION = "4.4.1";
public const string VERSION = "4.5.1";
public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer";
@ -45,14 +45,12 @@ namespace UnityExplorer
RuntimeHelper.Init();
ExplorerBehaviour.Setup();
UniverseLib.Universe.Init(ConfigManager.Startup_Delay_Time.Value, LateInit, Log, new UniverseLib.Config.UUConfig
UniverseLib.Universe.Init(ConfigManager.Startup_Delay_Time.Value, LateInit, Log, new()
{
Disable_EventSystem_Override = ConfigManager.Disable_EventSystem_Override.Value,
Force_Unlock_Mouse = ConfigManager.Force_Unlock_Mouse.Value,
Unhollowed_Modules_Folder = loader.UnhollowedModulesFolder
});
Log($"Finished core setup, waiting for late setup...");
}
// Do a delayed setup so that objects aren't destroyed instantly.
@ -69,6 +67,8 @@ namespace UnityExplorer
UIManager.InitUI();
Log($"{NAME} {VERSION} initialized.");
//InspectorManager.Inspect(typeof(Tests.TestClass));
}
/// <summary>

View File

@ -6,7 +6,7 @@ using System.Reflection;
using System.Text;
using HarmonyLib;
using UnityEngine;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Runtime;
using UnityExplorer.CSConsole;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
@ -84,7 +84,7 @@ namespace UnityExplorer.Hooks
cell.CurrentDisplayedIndex = index;
var hook = (HookInstance)this.currentHooks[index];
cell.MethodNameLabel.text = HighlightMethod(hook.TargetMethod);
cell.MethodNameLabel.text = SignatureHighlighter.HighlightMethod(hook.TargetMethod);
cell.ToggleActiveButton.ButtonText.text = hook.Enabled ? "Enabled" : "Disabled";
RuntimeProvider.Instance.SetColorBlockAuto(cell.ToggleActiveButton.Component,
@ -183,7 +183,7 @@ namespace UnityExplorer.Hooks
cell.CurrentDisplayedIndex = index;
var method = this.filteredEligableMethods[index];
cell.MethodNameLabel.text = HighlightMethod(method);
cell.MethodNameLabel.text = SignatureHighlighter.HighlightMethod(method);
var sig = method.FullDescription();
if (hookedSignatures.Contains(sig))
@ -225,50 +225,5 @@ namespace UnityExplorer.Hooks
Panel.SetPage(HookManagerPanel.Pages.CurrentHooks);
}
}
// ~~~~~~~~~~ Method syntax highlighting
private static readonly Dictionary<string, string> highlightedMethods = new Dictionary<string, string>();
private string HighlightMethod(MethodInfo method)
{
var sig = method.FullDescription();
if (highlightedMethods.ContainsKey(sig))
return highlightedMethods[sig];
var sb = new StringBuilder();
// declaring type
sb.Append(SignatureHighlighter.Parse(method.DeclaringType, false));
sb.Append('.');
// method name
var color = !method.IsStatic
? SignatureHighlighter.METHOD_INSTANCE
: SignatureHighlighter.METHOD_STATIC;
sb.Append($"<color={color}>{method.Name}</color>");
// arguments
sb.Append('(');
var args = method.GetParameters();
if (args != null && args.Any())
{
int i = 0;
foreach (var param in args)
{
sb.Append(SignatureHighlighter.Parse(param.ParameterType, false));
sb.Append(' ');
sb.Append($"<color={SignatureHighlighter.LOCAL_ARG}>{param.Name}</color>");
i++;
if (i < args.Length)
sb.Append(", ");
}
}
sb.Append(')');
var ret = sb.ToString();
highlightedMethods.Add(sig, ret);
return ret;
}
}
}

View File

@ -6,7 +6,7 @@
<ItemGroup>
<InputAssemblies Include="$(OutputPath)$(AssemblyName).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\Samboy063.Tomlet.3.1.3\lib\net35\Tomlet.dll" />
</ItemGroup>
<!-- Required references for ILRepack -->

View File

@ -241,7 +241,6 @@ namespace UnityExplorer.Inspectors
}
}
#region UI Construction
public override GameObject CreateContent(GameObject parent)

View File

@ -8,6 +8,7 @@ using UniverseLib.Input;
using UnityExplorer.UI;
using UniverseLib.UI;
using UniverseLib;
using UnityExplorer.UI.Panels;
namespace UnityExplorer.Inspectors
{
@ -51,6 +52,11 @@ namespace UnityExplorer.Inspectors
ConstructTransformControls();
}
private void OnCopyClicked()
{
ClipboardPanel.Copy(this.GOTarget);
}
#region GO Controls
private string lastGoName;
@ -467,6 +473,11 @@ namespace UnityExplorer.Inspectors
UIFactory.SetLayoutElement(PathInput.UIRoot, minHeight: 25, minWidth: 100, flexibleWidth: 9999);
PathInput.Component.lineType = InputField.LineType.MultiLineSubmit;
var copyButton = UIFactory.CreateButton(firstRow, "CopyButton", "Copy to Clipboard", new Color(0.2f, 0.2f, 0.2f, 1));
copyButton.ButtonText.color = Color.yellow;
UIFactory.SetLayoutElement(copyButton.Component.gameObject, minHeight: 25, minWidth: 120);
copyButton.OnClick += OnCopyClicked;
//var pathApplyBtn = UIFactory.CreateButton(firstRow, "PathButton", "Set Parent Path", new Color(0.2f, 0.2f, 0.2f));
//UIFactory.SetLayoutElement(pathApplyBtn.Component.gameObject, minHeight: 25, minWidth: 120);
//pathApplyBtn.OnClick += () => { OnPathEndEdit(PathInput.Text); };

View File

@ -5,9 +5,8 @@ using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Core;
using UniverseLib.Input;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Runtime;
using UnityExplorer.Inspectors.MouseInspectors;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
@ -32,24 +31,18 @@ namespace UnityExplorer.Inspectors
public static bool Inspecting { get; set; }
public static MouseInspectMode Mode { get; set; }
public MouseInspectorBase CurrentInspector => Mode switch
{
MouseInspectMode.UI => uiInspector,
MouseInspectMode.World => worldInspector,
_ => null,
};
private static Vector3 lastMousePos;
public MouseInspectorBase CurrentInspector
{
get
{
switch (Mode)
{
case MouseInspectMode.UI:
return uiInspector;
case MouseInspectMode.World:
return worldInspector;
}
return null;
}
}
// UIPanel
private UIBase inspectorUIBase;
public override string Name => "Inspect Under Mouse";
public override UIManager.Panels PanelType => UIManager.Panels.MouseInspector;
public override int MinWidth => -1;
@ -78,7 +71,7 @@ namespace UnityExplorer.Inspectors
case 1: Instance.StartInspect(MouseInspectMode.World); break;
case 2: Instance.StartInspect(MouseInspectMode.UI); break;
}
UIManager.MouseInspectDropdown.value = 0;
InspectorPanel.Instance.MouseInspectDropdown.value = 0;
}
public void StartInspect(MouseInspectMode mode)
@ -112,7 +105,7 @@ namespace UnityExplorer.Inspectors
UIManager.NavBarRect.gameObject.SetActive(true);
UIManager.PanelHolder.SetActive(true);
var drop = UIManager.MouseInspectDropdown;
var drop = InspectorPanel.Instance.MouseInspectDropdown;
if (drop.transform.Find("Dropdown List") is Transform list)
drop.DestroyDropdownList(list.gameObject);
@ -165,7 +158,7 @@ namespace UnityExplorer.Inspectors
mousePos.y -= 10;
// calculate and set our UI position
var inversePos = UIManager.UIRoot.transform.InverseTransformPoint(mousePos);
var inversePos = inspectorUIBase.RootObject.transform.InverseTransformPoint(mousePos);
UIRoot.transform.localPosition = new Vector3(inversePos.x, inversePos.y, 0);
}
@ -208,10 +201,12 @@ namespace UnityExplorer.Inspectors
UIFactory.SetLayoutElement(objPathLabel.gameObject, minHeight: 75);
UIRoot.SetActive(false);
// Create a new canvas for this panel to live on.
// It needs to always be shown on the main display, other panels can move displays.
inspectorUIBase = UniversalUI.RegisterUI($"{ExplorerCore.GUID}.MouseInspector", null);
UIRoot.transform.SetParent(inspectorUIBase.RootObject.transform);
}
public override void DoSaveToConfigElement() { }
public override string GetSaveDataFromConfigManager() => null;
}
}

View File

@ -23,6 +23,8 @@ namespace UnityExplorer
public static float PanelWidth;
public static event Action OnInspectedTabsChanged;
public static void Inspect(object obj, CacheObjectBase sourceCache = null)
{
if (obj.IsNullOrDestroyed())
@ -111,6 +113,8 @@ namespace UnityExplorer
inspector.OnBorrowedFromPool(target);
SetInspectorActive(inspector);
OnInspectedTabsChanged?.Invoke();
}
internal static void ReleaseInspector<T>(T inspector) where T : InspectorBase
@ -144,6 +148,8 @@ namespace UnityExplorer
UIManager.SetPanelActive(UIManager.Panels.Inspector, false);
}
}
OnInspectedTabsChanged?.Invoke();
}
internal static void Update()

View File

@ -9,52 +9,49 @@ using UniverseLib.UI.Models;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI;
using UniverseLib;
using UnityExplorer.UI.Panels;
namespace UnityExplorer.Inspectors
{
public class InspectorTab : IPooledObject
{
public GameObject UIRoot { get; set; }
public float DefaultHeight => 25f;
public ButtonRef TabButton;
public Text TabText;
public ButtonRef CloseButton;
private static readonly Color _enabledTabColor = new Color(0.15f, 0.22f, 0.15f);
private static readonly Color _disabledTabColor = new Color(0.13f, 0.13f, 0.13f);
private static readonly Color enabledTabColor = new(0.15f, 0.22f, 0.15f);
private static readonly Color disabledTabColor = new(0.13f, 0.13f, 0.13f);
public void SetTabColor(bool active)
{
if (active)
RuntimeProvider.Instance.SetColorBlock(TabButton.Component, _enabledTabColor, _enabledTabColor * 1.2f);
else
RuntimeProvider.Instance.SetColorBlock(TabButton.Component, _disabledTabColor, _disabledTabColor * 1.2f);
Color color = active ? enabledTabColor : disabledTabColor;
RuntimeProvider.Instance.SetColorBlock(TabButton.Component, color, color * 1.2f);
}
public GameObject CreateContent(GameObject parent)
{
UIRoot = UIFactory.CreateHorizontalGroup(parent, "TabObject", false, true, true, true, 0,
UIRoot = UIFactory.CreateHorizontalGroup(parent, "TabObject", false, true, true, true, 1,
default, new Color(0.13f, 0.13f, 0.13f), childAlignment: TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(UIRoot, minWidth: 200, flexibleWidth: 0);
UIRoot.AddComponent<Mask>();
UIRoot.AddComponent<Outline>();
TabButton = UIFactory.CreateButton(UIRoot, "TabButton", "");
UIFactory.SetLayoutElement(TabButton.Component.gameObject, minWidth: 175, flexibleWidth: 0);
UIFactory.SetLayoutElement(TabButton.Component.gameObject, minWidth: 173, flexibleWidth: 0);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(TabButton.Component.gameObject, false, false, true, true, 0, 0, 0, 3);
TabText = TabButton.Component.GetComponentInChildren<Text>();
UIFactory.SetLayoutElement(TabText.gameObject, minHeight: 25, minWidth: 175, flexibleWidth: 0);
UIFactory.SetLayoutElement(TabText.gameObject, minHeight: 25, minWidth: 173, flexibleWidth: 0);
TabText.alignment = TextAnchor.MiddleLeft;
TabText.fontSize = 12;
TabText.horizontalOverflow = HorizontalWrapMode.Overflow;
CloseButton = UIFactory.CreateButton(UIRoot, "CloseButton", "X", new Color(0.2f, 0.2f, 0.2f, 1));
CloseButton = UIFactory.CreateButton(UIRoot, "CloseButton", "X", new Color(0.15f, 0.15f, 0.15f, 1));
UIFactory.SetLayoutElement(CloseButton.Component.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0);
var closeBtnText = CloseButton.Component.GetComponentInChildren<Text>();
closeBtnText.color = Color.red;
CloseButton.ButtonText.color = Color.red;
return UIRoot;
}

View File

@ -35,6 +35,15 @@ namespace UnityExplorer.Inspectors.MouseInspectors
public override void UpdateMouseInspect(Vector2 mousePos)
{
if (!MainCamera)
MainCamera = Camera.main;
if (!MainCamera)
{
ExplorerCore.LogWarning("No Main Camera was found, unable to inspect world!");
InspectUnderMouse.Instance.StopInspect();
return;
}
var ray = MainCamera.ScreenPointToRay(mousePos);
Physics.Raycast(ray, out RaycastHit hit, 1000f);

View File

@ -8,8 +8,8 @@ using System.Reflection.Emit;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Config;
using UnityExplorer.Runtime;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.UI.Panels;
@ -327,6 +327,11 @@ namespace UnityExplorer.Inspectors
cell.Occupant.IValue.SetLayout();
}
private void OnCopyClicked()
{
ClipboardPanel.Copy(this.Target ?? this.TargetType);
}
// UI Construction
private GameObject mainContentHolder;
@ -338,7 +343,10 @@ namespace UnityExplorer.Inspectors
// Class name, assembly
var titleHolder = UIFactory.CreateUIObject("TitleHolder", UIRoot);
var topRow = UIFactory.CreateHorizontalGroup(UIRoot, "TopRow", false, false, true, true, 4, default, new(1, 1, 1, 0), TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(topRow, minHeight: 25, flexibleWidth: 9999);
var titleHolder = UIFactory.CreateUIObject("TitleHolder", topRow);
UIFactory.SetLayoutElement(titleHolder, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999);
NameText = UIFactory.CreateLabel(titleHolder, "VisibleTitle", "NotSet", TextAnchor.MiddleLeft);
@ -360,6 +368,11 @@ namespace UnityExplorer.Inspectors
HiddenNameText.Component.textComponent.color = Color.clear;
UIFactory.SetLayoutElement(HiddenNameText.Component.gameObject, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999);
var copyButton = UIFactory.CreateButton(topRow, "CopyButton", "Copy to Clipboard", new Color(0.2f, 0.2f, 0.2f, 1));
copyButton.ButtonText.color = Color.yellow;
UIFactory.SetLayoutElement(copyButton.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 0);
copyButton.OnClick += OnCopyClicked;
AssemblyText = UIFactory.CreateLabel(UIRoot, "AssemblyLabel", "not set", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(AssemblyText.gameObject, minHeight: 25, flexibleWidth: 9999);

View File

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

View File

@ -9,8 +9,7 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityExplorer.Core;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UniverseLib.Input;
using UnityExplorer.Loader.BIE;
#if CPP

View File

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

View File

@ -3,7 +3,7 @@ using System;
using System.IO;
using MelonLoader;
using UnityExplorer;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.Loader.ML;
[assembly: MelonPlatformDomain(MelonPlatformDomainAttribute.CompatibleDomains.UNIVERSAL)]

View File

@ -5,8 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.Core;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
namespace UnityExplorer.Loader.ML
{

View File

@ -4,11 +4,10 @@ using System;
using System.IO;
using System.Reflection;
using UnityEngine;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.Loader.STANDALONE;
using UnityEngine.EventSystems;
using UniverseLib.Input;
using UnityExplorer.Core;
#if CPP
using UnhollowerRuntimeLib;
#endif

View File

@ -3,23 +3,21 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.Core.Config;
using IniParser.Parser;
using UnityExplorer.Config;
using System.IO;
using UnityEngine;
using Tomlet;
using Tomlet.Models;
namespace UnityExplorer.Loader.STANDALONE
{
public class StandaloneConfigHandler : ConfigHandler
{
internal static IniDataParser _parser;
internal static string CONFIG_PATH;
public override void Init()
{
CONFIG_PATH = Path.Combine(ExplorerCore.Loader.ExplorerFolder, "config.ini");
_parser = new IniDataParser();
_parser.Configuration.CommentString = "#";
CONFIG_PATH = Path.Combine(ExplorerCore.Loader.ExplorerFolder, "config.cfg");
}
public override void LoadConfig()
@ -52,14 +50,11 @@ namespace UnityExplorer.Loader.STANDALONE
if (!File.Exists(CONFIG_PATH))
return false;
string ini = File.ReadAllText(CONFIG_PATH);
var data = _parser.Parse(ini);
foreach (var config in data.Sections["Config"])
var document = TomlParser.ParseFile(CONFIG_PATH);
foreach (var key in document.Keys)
{
if (ConfigManager.ConfigElements.TryGetValue(config.KeyName, out IConfigElement configElement))
configElement.BoxedValue = StringToConfigValue(config.Value, configElement.ElementType);
var config = ConfigManager.ConfigElements[key];
config.BoxedValue = StringToConfigValue(document.GetValue(key).StringValue, config.ElementType);
}
return true;
@ -89,18 +84,14 @@ namespace UnityExplorer.Loader.STANDALONE
public override void SaveConfig()
{
var data = new IniParser.Model.IniData();
data.Sections.AddSection("Config");
var sec = data.Sections["Config"];
foreach (var entry in ConfigManager.ConfigElements)
sec.AddKey(entry.Key, entry.Value.BoxedValue.ToString());
var document = TomlDocument.CreateEmpty();
foreach (var config in ConfigManager.ConfigElements)
document.Put(config.Key, config.Value.BoxedValue.ToString());
if (!Directory.Exists(ExplorerCore.Loader.ExplorerFolder))
Directory.CreateDirectory(ExplorerCore.Loader.ExplorerFolder);
File.WriteAllText(CONFIG_PATH, data.ToString());
File.WriteAllText(CONFIG_PATH, document.SerializedValue);
}
}
}

View File

@ -7,13 +7,13 @@ using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI;
using UniverseLib;
using System.Collections;
namespace UnityExplorer.ObjectExplorer
{
@ -254,6 +254,21 @@ namespace UnityExplorer.ObjectExplorer
// Scene Loader
ConstructSceneLoader();
RuntimeProvider.Instance.StartCoroutine(TempFixCoro());
}
// To "fix" a strange FPS drop issue with MelonLoader.
private IEnumerator TempFixCoro()
{
float start = Time.realtimeSinceStartup;
while (Time.realtimeSinceStartup - start < 2.5f)
yield return null;
// Select "HideAndDontSave" and then go back to first scene.
this.sceneDropdown.value = sceneDropdown.options.Count - 1;
this.sceneDropdown.value = 0;
}
private const string DEFAULT_LOAD_TEXT = "[Select a scene]";

View File

@ -133,10 +133,11 @@ namespace UnityExplorer.ObjectExplorer
LoadedScenes.Add(scene);
}
bool anyChange = confirmedCount != LoadedScenes.Count;
LoadedScenes.Add(DontDestroyScene);
LoadedScenes.Add(default);
bool anyChange = confirmedCount != LoadedScenes.Count;
previousLoadedScenes = new HashSet<Scene>(LoadedScenes);
// Default to first scene if none selected or previous selection no longer exists.

View File

@ -5,8 +5,7 @@ using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityExplorer.Core;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Runtime;
using UniverseLib;
namespace UnityExplorer.ObjectExplorer

View File

@ -14,7 +14,7 @@ using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace UnityExplorer.Core.Runtime
namespace UnityExplorer.Runtime
{
public class Il2CppProvider : RuntimeHelper
{

View File

@ -12,7 +12,7 @@ using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer;
namespace UnityExplorer.Core.Runtime
namespace UnityExplorer.Runtime
{
public class MonoProvider : RuntimeHelper
{

View File

@ -8,10 +8,10 @@ using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UniverseLib;
namespace UnityExplorer.Core.Runtime
namespace UnityExplorer.Runtime
{
public abstract class RuntimeHelper
{

View File

@ -14,7 +14,7 @@ using UnhollowerBaseLib;
namespace UnityExplorer.Tests
{
public static class TestClass
public class TestClass
{
static TestClass()
{
@ -24,21 +24,31 @@ namespace UnityExplorer.Tests
#endif
}
public static object LiterallyAnything = null;
// Test enumerables
public static int[,,] MultiDimensionalArray = new int[45, 45, 45];
public static List<object> ListOfInts;
public static List<List<List<string>>> NestedList;
public static IDictionary MixedDictionary;
public static Hashtable Hashtable;
public static byte[] ByteArray = new byte[16];
public static List<short> ABigList = new List<short>(10000);
public static List<short> ABigList = new(10000);
// Test const behaviour (should be a readonly field)
public const int ConstantInt5 = 5;
// Testing other InteractiveValues
public static BindingFlags EnumTest;
public static CameraClearFlags EnumTest2;
public static Color Color = Color.magenta;
public static Color32 Color32 = Color.red;
public static string ALongString = new string('#', 10000);
public static string ALongString = new('#', 10000);
public static float[] AParseTest(ref List<float[,,]> arg0, ref float[,] arg1)
{
return new float[] { 1, 2, 3 };
}
public static List<object> RandomList
{
@ -52,25 +62,27 @@ namespace UnityExplorer.Tests
}
}
public int this[int index]
{
get => UnityEngine.Random.Range(0, int.MaxValue);
set => ExplorerCore.Log(index);
}
// Test methods
private static object GetRandomObject()
{
object ret = null;
int ran = UnityEngine.Random.Range(0, 7);
switch (ran)
return UnityEngine.Random.Range(0, 7) switch
{
case 0: return null;
case 1: return 123;
case 2: return true;
case 3: return "hello";
case 4: return 50.5f;
case 5: return CameraClearFlags.Color;
case 6: return new List<string> { "one", "two" };
}
return ret;
0 => null,
1 => 123,
2 => true,
3 => "hello",
4 => 50.5f,
5 => CameraClearFlags.Color,
6 => new List<string> { "one", "two" },
_ => null,
};
}
public static void TestComponent<T>() where T : Component
@ -78,9 +90,19 @@ namespace UnityExplorer.Tests
ExplorerCore.Log($"Test3 {typeof(T).FullName}");
}
public static void TestArgumentParse(string s, int i, Color color, CameraClearFlags flags, Vector3 vector, Quaternion quaternion)
public static void TestArgumentParse(string _string,
int integer,
Color color,
CameraClearFlags flags,
Vector3 vector,
Quaternion quaternion,
object obj,
Type type,
GameObject go)
{
ExplorerCore.Log($"{s}, {i}, {color.ToString()}, {flags}, {vector.ToString()}, {quaternion.ToString()}");
ExplorerCore.Log($"_string: {_string}, integer: {integer}, color: {color.ToString()}, flags: {flags}, " +
$"vector: {vector.ToString()}, quaternion: {quaternion.ToString()}, obj: {obj?.ToString() ?? "null"}," +
$"type: {type?.FullName ?? "null"}, go: {go?.ToString() ?? "null"}");
}
private static void Init_Mono()

80
src/UI/DisplayManager.cs Normal file
View File

@ -0,0 +1,80 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.Config;
using UniverseLib;
using UniverseLib.Input;
namespace UnityExplorer.UI
{
public static class DisplayManager
{
public static int ActiveDisplayIndex { get; private set; }
public static Display ActiveDisplay => Display.displays[ActiveDisplayIndex];
public static int Width => ActiveDisplay.renderingWidth;
public static int Height => ActiveDisplay.renderingHeight;
public static Vector3 MousePosition => Display.RelativeMouseAt(InputManager.MousePosition);
public static bool MouseInTargetDisplay => MousePosition.z == ActiveDisplayIndex;
private static Camera canvasCamera;
internal static void Init()
{
SetDisplay(ConfigManager.Target_Display.Value);
ConfigManager.Target_Display.OnValueChanged += SetDisplay;
}
public static void SetDisplay(int display)
{
if (ActiveDisplayIndex == display)
return;
if (Display.displays.Length <= display)
{
ExplorerCore.LogWarning($"Cannot set display index to {display} as there are not enough monitors connected!");
if (ConfigManager.Target_Display.Value == display)
ConfigManager.Target_Display.Value = 0;
return;
}
ActiveDisplayIndex = display;
ActiveDisplay.Activate();
UIManager.UICanvas.targetDisplay = display;
// ensure a camera is targeting the display
if (!Camera.main || Camera.main.targetDisplay != display)
{
if (!canvasCamera)
{
canvasCamera = new GameObject("UnityExplorer_CanvasCamera").AddComponent<Camera>();
GameObject.DontDestroyOnLoad(canvasCamera.gameObject);
canvasCamera.hideFlags = HideFlags.HideAndDontSave;
}
canvasCamera.targetDisplay = display;
}
RuntimeProvider.Instance.StartCoroutine(FixPanels());
}
private static IEnumerator FixPanels()
{
yield return null;
yield return null;
foreach (var panel in UIManager.UIPanels.Values)
{
panel.EnsureValidSize();
panel.EnsureValidPosition();
panel.Dragger.OnEndResize();
}
}
}
}

55
src/UI/Notification.cs Normal file
View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UniverseLib.Input;
using UniverseLib.UI;
namespace UnityExplorer.UI
{
public static class Notification
{
private static Text popupLabel;
private static string _currentNotification;
private static float _timeOfLastNotification;
public static void Init()
{
ConstructUI();
}
public static void ShowMessage(string message)
{
popupLabel.text = message;
_currentNotification = message;
_timeOfLastNotification = Time.realtimeSinceStartup;
popupLabel.transform.localPosition = UIManager.UIRootRect.InverseTransformPoint(DisplayManager.MousePosition) + (Vector3.up * 25);
}
public static void Update()
{
if (_currentNotification != null)
{
if (Time.realtimeSinceStartup - _timeOfLastNotification > 2f)
{
_currentNotification = null;
popupLabel.text = "";
}
}
}
private static void ConstructUI()
{
popupLabel = UIFactory.CreateLabel(UIManager.UIRoot, "ClipboardNotification", "", TextAnchor.MiddleCenter);
popupLabel.rectTransform.sizeDelta = new(500, 100);
popupLabel.gameObject.AddComponent<Outline>();
var popupGroup = popupLabel.gameObject.AddComponent<CanvasGroup>();
popupGroup.blocksRaycasts = false;
}
}
}

View File

@ -6,7 +6,7 @@ using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.CSConsole;
using UnityExplorer.UI.Widgets;
using UniverseLib;
@ -55,15 +55,6 @@ namespace UnityExplorer.UI.Panels
ConsoleController.Update();
}
// Saving
public override void DoSaveToConfigElement()
{
ConfigManager.CSConsoleData.Value = this.ToSaveData();
}
public override string GetSaveDataFromConfigManager() => ConfigManager.CSConsoleData.Value;
// UI Construction
public override void OnFinishResize(RectTransform panel)

View File

@ -0,0 +1,118 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.Config;
using UniverseLib;
using UniverseLib.Input;
using UniverseLib.UI;
using UniverseLib.UI.Widgets;
namespace UnityExplorer.UI.Panels
{
public class ClipboardPanel : UIPanel
{
public static object Current { get; private set; }
public override UIManager.Panels PanelType => UIManager.Panels.Clipboard;
public override string Name => "Clipboard";
public override int MinWidth => 500;
public override int MinHeight => 95;
public override bool CanDragAndResize => true;
public override bool NavButtonWanted => true;
public override bool ShouldSaveActiveState => true;
public override bool ShowByDefault => true;
private static Text CurrentPasteLabel;
public static void Copy(object obj)
{
Current = obj;
Notification.ShowMessage("Copied!");
UpdateCurrentPasteInfo();
}
public static bool TryPaste(Type targetType, out object paste)
{
paste = Current;
var pasteType = Current?.GetActualType();
if (Current != null && !targetType.IsAssignableFrom(pasteType))
{
Notification.ShowMessage($"Cannot assign '{pasteType.Name}' to '{targetType.Name}'!");
return false;
}
Notification.ShowMessage("Pasted!");
return true;
}
public static void ClearClipboard()
{
Current = null;
UpdateCurrentPasteInfo();
}
private static void UpdateCurrentPasteInfo()
{
CurrentPasteLabel.text = ToStringUtility.ToStringWithType(Current, typeof(object), false);
}
private static void InspectClipboard()
{
if (Current.IsNullOrDestroyed())
{
Notification.ShowMessage("Cannot inspect a null or destroyed object!");
return;
}
InspectorManager.Inspect(Current);
}
protected internal override void DoSetDefaultPosAndAnchors()
{
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth);
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
this.Rect.anchorMin = new Vector2(0.1f, 0.05f);
this.Rect.anchorMax = new Vector2(0.4f, 0.15f);
}
public override void ConstructPanelContent()
{
this.UIRoot.GetComponent<Image>().color = new(0.1f, 0.1f, 0.1f);
// Actual panel content
var firstRow = UIFactory.CreateHorizontalGroup(UIRoot, "FirstRow", false, false, true, true, 5, new(2,2,2,2), new(1,1,1,0));
UIFactory.SetLayoutElement(firstRow, minHeight: 25, flexibleWidth: 999);
// Title for "Current Paste:"
var currentPasteTitle = UIFactory.CreateLabel(firstRow, "CurrentPasteTitle", "Current paste:", TextAnchor.MiddleLeft, color: Color.grey);
UIFactory.SetLayoutElement(currentPasteTitle.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999);
// Clear clipboard button
var clearButton = UIFactory.CreateButton(firstRow, "ClearPasteButton", "Clear Clipboard");
UIFactory.SetLayoutElement(clearButton.Component.gameObject, minWidth: 120, minHeight: 25, flexibleWidth: 0);
clearButton.OnClick += () => Copy(null);
// Current Paste info row
var currentPasteHolder = UIFactory.CreateHorizontalGroup(UIRoot, "SecondRow", false, false, true, true, 0,
new(2, 2, 2, 2), childAlignment: TextAnchor.UpperCenter);
// Actual current paste info label
CurrentPasteLabel = UIFactory.CreateLabel(currentPasteHolder, "CurrentPasteInfo", "not set", TextAnchor.UpperLeft);
UIFactory.SetLayoutElement(CurrentPasteLabel.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999, flexibleHeight: 999);
UpdateCurrentPasteInfo();
// Inspect button
var inspectButton = UIFactory.CreateButton(currentPasteHolder, "InspectButton", "Inspect");
UIFactory.SetLayoutElement(inspectButton.Component.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 80, flexibleWidth: 0);
inspectButton.OnClick += InspectClipboard;
}
}
}

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.Hooks;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete;
@ -46,10 +46,6 @@ namespace UnityExplorer.UI.Panels
public Text EditorInputText { get; private set; }
public Text EditorHighlightText { get; private set; }
public override string GetSaveDataFromConfigManager() => ConfigManager.HookManagerData.Value;
public override void DoSaveToConfigElement() => ConfigManager.HookManagerData.Value = this.ToSaveData();
private void OnClassInputAddClicked()
{
HookManager.Instance.OnClassSelectedForHooks(this.classSelectorInputField.Text);

View File

@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.Inspectors;
using UniverseLib.UI;
@ -24,6 +24,7 @@ namespace UnityExplorer.UI.Panels
public override int MinHeight => 350;
public GameObject NavbarHolder;
public Dropdown MouseInspectDropdown;
public GameObject ContentHolder;
public RectTransform ContentRect;
@ -43,13 +44,6 @@ namespace UnityExplorer.UI.Panels
InspectorManager.OnPanelResized(panel.rect.width);
}
public override string GetSaveDataFromConfigManager() => ConfigManager.InspectorData.Value;
public override void DoSaveToConfigElement()
{
ConfigManager.InspectorData.Value = this.ToSaveData();
}
protected internal override void DoSetDefaultPosAndAnchors()
{
Rect.localPosition = Vector2.zero;
@ -60,9 +54,21 @@ namespace UnityExplorer.UI.Panels
public override void ConstructPanelContent()
{
var closeHolder = this.titleBar.transform.Find("CloseHolder").gameObject;
// Inspect under mouse dropdown on title bar
var mouseDropdown = UIFactory.CreateDropdown(closeHolder, out MouseInspectDropdown, "Mouse Inspect", 14,
InspectUnderMouse.OnDropdownSelect);
UIFactory.SetLayoutElement(mouseDropdown, minHeight: 25, minWidth: 140);
MouseInspectDropdown.options.Add(new Dropdown.OptionData("Mouse Inspect"));
MouseInspectDropdown.options.Add(new Dropdown.OptionData("World"));
MouseInspectDropdown.options.Add(new Dropdown.OptionData("UI"));
mouseDropdown.transform.SetSiblingIndex(0);
// add close all button to titlebar
var closeAllBtn = UIFactory.CreateButton(this.titleBar.transform.Find("CloseHolder").gameObject, "CloseAllBtn", "Close All",
var closeAllBtn = UIFactory.CreateButton(closeHolder.gameObject, "CloseAllBtn", "Close All",
new Color(0.3f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(closeAllBtn.Component.gameObject, minHeight: 25, minWidth: 80);
closeAllBtn.Component.transform.SetSiblingIndex(closeAllBtn.Component.transform.GetSiblingIndex() - 1);

View File

@ -6,7 +6,7 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.UI.Widgets;
using UniverseLib;
using UniverseLib.UI;
@ -144,18 +144,6 @@ namespace UnityExplorer.UI.Panels
RuntimeProvider.Instance.SetColorBlock(cell.Input.Component, color);
}
// Panel save data
public override string GetSaveDataFromConfigManager()
{
return ConfigManager.ConsoleLogData.Value;
}
public override void DoSaveToConfigElement()
{
ConfigManager.ConsoleLogData.Value = this.ToSaveData();
}
protected internal override void DoSetDefaultPosAndAnchors()
{
Rect.localPosition = Vector2.zero;

View File

@ -8,8 +8,7 @@ using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UniverseLib.UI.Models;
using UnityExplorer.ObjectExplorer;
using UnityExplorer.UI.Widgets;
@ -47,7 +46,7 @@ namespace UnityExplorer.UI.Panels
RuntimeProvider.Instance.SetColorBlock(button.Component, UniversalUI.enabledButtonColor, UniversalUI.enabledButtonColor * 1.2f);
SelectedTab = tabIndex;
SaveToConfigManager();
SaveInternalData();
}
private void DisableTab(int tabIndex)
@ -64,21 +63,12 @@ namespace UnityExplorer.UI.Panels
ObjectSearch.Update();
}
public override string GetSaveDataFromConfigManager() => ConfigManager.ObjectExplorerData.Value;
public override void DoSaveToConfigElement()
{
ConfigManager.ObjectExplorerData.Value = this.ToSaveData();
}
public override string ToSaveData()
{
string ret = base.ToSaveData();
ret += "|" + SelectedTab;
return ret;
return string.Join("|", new string[] { base.ToSaveData(), SelectedTab.ToString() });
}
public override void ApplySaveData(string data)
protected override void ApplySaveData(string data)
{
base.ApplySaveData(data);

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.CacheObject;
using UnityExplorer.CacheObject.Views;
using UnityExplorer.UI.Widgets;
@ -55,17 +55,7 @@ namespace UnityExplorer.UI.Panels
CacheObjectControllerHelper.SetCell(cell, index, this.configEntries, null);
}
// Panel save data
public override string GetSaveDataFromConfigManager()
{
return ConfigManager.OptionsPanelData.Value;
}
public override void DoSaveToConfigElement()
{
ConfigManager.OptionsPanelData.Value = this.ToSaveData();
}
// UI Construction
protected internal override void DoSetDefaultPosAndAnchors()
{
@ -76,8 +66,6 @@ namespace UnityExplorer.UI.Panels
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 600f);
}
// UI Construction
public override void ConstructPanelContent()
{
// Save button

View File

@ -15,15 +15,33 @@ namespace UnityExplorer.UI.Panels
{
public class PanelDragger
{
private enum MouseState
{
Down,
Held,
NotPressed
}
#region Static
public static bool Resizing { get; private set; }
public static bool ResizePrompting => resizeCursorObj && resizeCursorObj.activeSelf;
public static bool ResizePrompting => s_resizeCursorObj && s_resizeCursorObj.activeSelf;
public static GameObject resizeCursorObj;
internal static bool wasAnyDragging;
internal static List<PanelDragger> Instances = new();
private static bool handledInstanceThisFrame;
static PanelDragger()
{
UIPanel.OnPanelsReordered += OnPanelsReordered;
}
internal static void ForceEnd()
{
s_resizeCursorObj.SetActive(false);
resizeCursorObj.SetActive(false);
wasAnyDragging = false;
Resizing = false;
@ -34,13 +52,6 @@ namespace UnityExplorer.UI.Panels
}
}
internal static List<PanelDragger> Instances = new List<PanelDragger>();
static PanelDragger()
{
UIPanel.OnPanelsReordered += OnPanelsReordered;
}
public static void OnPanelsReordered()
{
Instances.Sort((a, b) => b.Panel.GetSiblingIndex().CompareTo(a.Panel.GetSiblingIndex()));
@ -54,18 +65,12 @@ namespace UnityExplorer.UI.Panels
}
}
private enum MouseState
{
Down,
Held,
NotPressed
}
private static bool handledInstanceThisFrame;
public static void UpdateInstances()
{
if (!s_resizeCursorObj)
if (!DisplayManager.MouseInTargetDisplay)
return;
if (!resizeCursorObj)
CreateCursorUI();
MouseState state;
@ -76,7 +81,7 @@ namespace UnityExplorer.UI.Panels
else
state = MouseState.NotPressed;
var mousePos = InputManager.MousePosition;
var mousePos = DisplayManager.MousePosition;
handledInstanceThisFrame = false;
foreach (var instance in Instances)
@ -99,10 +104,6 @@ namespace UnityExplorer.UI.Panels
#endregion
public static GameObject s_resizeCursorObj;
internal static bool wasAnyDragging;
// Instance
public UIPanel UIPanel { get; private set; }
@ -112,27 +113,23 @@ namespace UnityExplorer.UI.Panels
public event Action<RectTransform> OnFinishResize;
public event Action<RectTransform> OnFinishDrag;
private readonly RectTransform canvasTransform;
// Dragging
public RectTransform DragableArea { get; set; }
public bool WasDragging { get; set; }
private Vector2 m_lastDragPosition;
private Vector2 lastDragPosition;
// Resizing
private const int RESIZE_THICKNESS = 10;
//internal readonly Vector2 minResize = new Vector2(200, 50);
private bool WasResizing { get; set; }
private ResizeTypes m_currentResizeType = ResizeTypes.NONE;
private Vector2 m_lastResizePos;
private ResizeTypes currentResizeType = ResizeTypes.NONE;
private Vector2 lastResizePos;
private bool WasHoveringResize => s_resizeCursorObj.activeInHierarchy;
private bool WasHoveringResize => resizeCursorObj.activeInHierarchy;
private ResizeTypes m_lastResizeHoverType;
private ResizeTypes lastResizeHoverType;
private Rect m_totalResizeRect;
private Rect totalResizeRect;
public PanelDragger(RectTransform dragArea, RectTransform panelToDrag, UIPanel panel)
{
@ -141,16 +138,13 @@ namespace UnityExplorer.UI.Panels
DragableArea = dragArea;
Panel = panelToDrag;
if (!canvasTransform)
canvasTransform = Panel.GetComponentInParent<Canvas>().GetComponent<RectTransform>();
UpdateResizeCache();
}
public void Destroy()
{
if (s_resizeCursorObj)
GameObject.Destroy(s_resizeCursorObj);
if (resizeCursorObj)
GameObject.Destroy(resizeCursorObj);
if (Instances.Contains(this))
Instances.Remove(this);
@ -166,7 +160,7 @@ namespace UnityExplorer.UI.Panels
Vector3 dragPos = DragableArea.InverseTransformPoint(rawMousePos);
bool inDragPos = DragableArea.rect.Contains(dragPos);
if (WasHoveringResize && s_resizeCursorObj)
if (WasHoveringResize && resizeCursorObj)
UpdateHoverImagePos();
switch (state)
@ -243,15 +237,15 @@ namespace UnityExplorer.UI.Panels
{
wasAnyDragging = true;
WasDragging = true;
m_lastDragPosition = InputManager.MousePosition;
lastDragPosition = DisplayManager.MousePosition;
}
public void OnDrag()
{
var mousePos = InputManager.MousePosition;
var mousePos = DisplayManager.MousePosition;
Vector2 diff = (Vector2)mousePos - m_lastDragPosition;
m_lastDragPosition = mousePos;
Vector2 diff = (Vector2)mousePos - lastDragPosition;
lastDragPosition = mousePos;
Panel.localPosition = Panel.localPosition + (Vector3)diff;
@ -269,7 +263,7 @@ namespace UnityExplorer.UI.Panels
#region RESIZE
private readonly Dictionary<ResizeTypes, Rect> m_resizeMask = new Dictionary<ResizeTypes, Rect>
private readonly Dictionary<ResizeTypes, Rect> m_resizeMask = new()
{
{ ResizeTypes.Top, default },
{ ResizeTypes.Left, default },
@ -296,7 +290,7 @@ namespace UnityExplorer.UI.Panels
private void UpdateResizeCache()
{
m_totalResizeRect = new Rect(Panel.rect.x - RESIZE_THICKNESS + 1,
totalResizeRect = new Rect(Panel.rect.x - RESIZE_THICKNESS + 1,
Panel.rect.y - RESIZE_THICKNESS + 1,
Panel.rect.width + DBL_THICKESS - 2,
Panel.rect.height + DBL_THICKESS - 2);
@ -305,34 +299,34 @@ namespace UnityExplorer.UI.Panels
if (AllowDragAndResize)
{
m_resizeMask[ResizeTypes.Bottom] = new Rect(
m_totalResizeRect.x,
m_totalResizeRect.y,
m_totalResizeRect.width,
totalResizeRect.x,
totalResizeRect.y,
totalResizeRect.width,
RESIZE_THICKNESS);
m_resizeMask[ResizeTypes.Left] = new Rect(
m_totalResizeRect.x,
m_totalResizeRect.y,
totalResizeRect.x,
totalResizeRect.y,
RESIZE_THICKNESS,
m_totalResizeRect.height);
totalResizeRect.height);
m_resizeMask[ResizeTypes.Top] = new Rect(
m_totalResizeRect.x,
totalResizeRect.x,
Panel.rect.y + Panel.rect.height - 2,
m_totalResizeRect.width,
totalResizeRect.width,
RESIZE_THICKNESS);
m_resizeMask[ResizeTypes.Right] = new Rect(
m_totalResizeRect.x + Panel.rect.width + RESIZE_THICKNESS - 2,
m_totalResizeRect.y,
totalResizeRect.x + Panel.rect.width + RESIZE_THICKNESS - 2,
totalResizeRect.y,
RESIZE_THICKNESS,
m_totalResizeRect.height);
totalResizeRect.height);
}
}
private bool MouseInResizeArea(Vector2 mousePos)
{
return m_totalResizeRect.Contains(mousePos);
return totalResizeRect.Contains(mousePos);
}
private ResizeTypes GetResizeType(Vector2 mousePos)
@ -361,16 +355,16 @@ namespace UnityExplorer.UI.Panels
public void OnHoverResize(ResizeTypes resizeType)
{
if (WasHoveringResize && m_lastResizeHoverType == resizeType)
if (WasHoveringResize && lastResizeHoverType == resizeType)
return;
// we are entering resize, or the resize type has changed.
//WasHoveringResize = true;
m_lastResizeHoverType = resizeType;
lastResizeHoverType = resizeType;
s_resizeCursorObj.SetActive(true);
s_resizeCursorObj.transform.SetAsLastSibling();
resizeCursorObj.SetActive(true);
resizeCursorObj.transform.SetAsLastSibling();
// set the rotation for the resize icon
float iconRotation = 0f;
@ -387,9 +381,9 @@ namespace UnityExplorer.UI.Panels
iconRotation = 135f; break;
}
Quaternion rot = s_resizeCursorObj.transform.rotation;
Quaternion rot = resizeCursorObj.transform.rotation;
rot.eulerAngles = new Vector3(0, 0, iconRotation);
s_resizeCursorObj.transform.rotation = rot;
resizeCursorObj.transform.rotation = rot;
UpdateHoverImagePos();
}
@ -397,50 +391,50 @@ namespace UnityExplorer.UI.Panels
// update the resize icon position to be above the mouse
private void UpdateHoverImagePos()
{
s_resizeCursorObj.transform.localPosition = canvasTransform.InverseTransformPoint(InputManager.MousePosition);
resizeCursorObj.transform.localPosition = UIManager.UIRootRect.InverseTransformPoint(DisplayManager.MousePosition);
}
public void OnHoverResizeEnd()
{
//WasHoveringResize = false;
s_resizeCursorObj.SetActive(false);
resizeCursorObj.SetActive(false);
}
public void OnBeginResize(ResizeTypes resizeType)
{
m_currentResizeType = resizeType;
m_lastResizePos = InputManager.MousePosition;
currentResizeType = resizeType;
lastResizePos = DisplayManager.MousePosition;
WasResizing = true;
Resizing = true;
}
public void OnResize()
{
Vector3 mousePos = InputManager.MousePosition;
Vector2 diff = m_lastResizePos - (Vector2)mousePos;
Vector3 mousePos = DisplayManager.MousePosition;
Vector2 diff = lastResizePos - (Vector2)mousePos;
if ((Vector2)mousePos == m_lastResizePos)
if ((Vector2)mousePos == lastResizePos)
return;
if (mousePos.x < 0 || mousePos.y < 0 || mousePos.x > Screen.width || mousePos.y > Screen.height)
if (mousePos.x < 0 || mousePos.y < 0 || mousePos.x > DisplayManager.Width || mousePos.y > DisplayManager.Height)
return;
m_lastResizePos = mousePos;
lastResizePos = mousePos;
float diffX = (float)((decimal)diff.x / Screen.width);
float diffY = (float)((decimal)diff.y / Screen.height);
float diffX = (float)((decimal)diff.x / DisplayManager.Width);
float diffY = (float)((decimal)diff.y / DisplayManager.Height);
Vector2 anchorMin = Panel.anchorMin;
Vector2 anchorMax = Panel.anchorMax;
if (m_currentResizeType.HasFlag(ResizeTypes.Left))
if (currentResizeType.HasFlag(ResizeTypes.Left))
anchorMin.x -= diffX;
else if (m_currentResizeType.HasFlag(ResizeTypes.Right))
else if (currentResizeType.HasFlag(ResizeTypes.Right))
anchorMax.x -= diffX;
if (m_currentResizeType.HasFlag(ResizeTypes.Top))
if (currentResizeType.HasFlag(ResizeTypes.Top))
anchorMax.y -= diffY;
else if (m_currentResizeType.HasFlag(ResizeTypes.Bottom))
else if (currentResizeType.HasFlag(ResizeTypes.Bottom))
anchorMin.y -= diffY;
var prevMin = Panel.anchorMin;
@ -475,13 +469,13 @@ namespace UnityExplorer.UI.Panels
try
{
var text = UIFactory.CreateLabel(UIManager.UIRoot, "ResizeCursor", "↔", TextAnchor.MiddleCenter, Color.white, true, 35);
s_resizeCursorObj = text.gameObject;
resizeCursorObj = text.gameObject;
RectTransform rect = s_resizeCursorObj.GetComponent<RectTransform>();
RectTransform rect = resizeCursorObj.GetComponent<RectTransform>();
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 64);
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 64);
s_resizeCursorObj.SetActive(false);
resizeCursorObj.SetActive(false);
}
catch (Exception e)
{

View File

@ -5,12 +5,13 @@ using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UniverseLib.Input;
using UnityExplorer.UI.Widgets;
using UniverseLib.UI.Models;
using UniverseLib.UI;
using UniverseLib;
using System.Collections;
namespace UnityExplorer.UI.Panels
{
@ -23,8 +24,8 @@ namespace UnityExplorer.UI.Panels
public static event Action OnPanelsReordered;
public static event Action OnClickedOutsidePanels;
internal static readonly List<UIPanel> instances = new List<UIPanel>();
internal static readonly Dictionary<int, UIPanel> transformToPanelDict = new Dictionary<int, UIPanel>();
internal static readonly List<UIPanel> instances = new();
internal static readonly Dictionary<int, UIPanel> transformToPanelDict = new();
public static void UpdateFocus()
{
@ -32,10 +33,11 @@ namespace UnityExplorer.UI.Panels
return;
// if the user is clicking
if (InputManager.GetMouseButtonDown(0) || InputManager.GetMouseButtonDown(1))
if (DisplayManager.MouseInTargetDisplay
&& (InputManager.GetMouseButtonDown(0) || InputManager.GetMouseButtonDown(1)))
{
int count = UIManager.PanelHolder.transform.childCount;
var mousePos = InputManager.MousePosition;
var mousePos = DisplayManager.MousePosition;
bool clickedInAny = false;
for (int i = count - 1; i >= 0; i--)
@ -92,19 +94,16 @@ namespace UnityExplorer.UI.Panels
protected GameObject uiRoot;
public RectTransform Rect;
public GameObject content;
public GameObject titleBar;
public abstract void ConstructPanelContent();
public virtual void OnFinishResize(RectTransform panel)
{
SaveToConfigManager();
SaveInternalData();
}
public virtual void OnFinishDrag(RectTransform panel)
{
SaveToConfigManager();
SaveInternalData();
}
public override void SetActive(bool active)
@ -115,7 +114,7 @@ namespace UnityExplorer.UI.Panels
base.SetActive(active);
if (!ApplyingSaveData)
SaveToConfigManager();
SaveInternalData();
if (NavButtonWanted)
{
@ -148,13 +147,15 @@ namespace UnityExplorer.UI.Panels
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
}
public void EnsureValidPosition() => EnsureValidPosition(this.Rect);
public static void EnsureValidPosition(RectTransform panel)
{
var pos = panel.localPosition;
// Prevent panel going oustide screen bounds
var halfW = Screen.width * 0.5f;
var halfH = Screen.height * 0.5f;
var halfW = DisplayManager.Width * 0.5f;
var halfH = DisplayManager.Height * 0.5f;
pos.x = Math.Max(-halfW - panel.rect.width + 50, Math.Min(pos.x, halfW - 50));
pos.y = Math.Max(-halfH + 50, Math.Min(pos.y, halfH));
@ -162,29 +163,30 @@ namespace UnityExplorer.UI.Panels
panel.localPosition = pos;
}
#region Save Data
// Save Data
public abstract void DoSaveToConfigElement();
public bool ApplyingSaveData { get; set; }
public void SaveToConfigManager()
public void SaveInternalData()
{
if (UIManager.Initializing)
return;
DoSaveToConfigElement();
SetSaveDataToConfigValue();
}
public abstract string GetSaveDataFromConfigManager();
public bool ApplyingSaveData { get; set; }
private void SetSaveDataToConfigValue() => ConfigManager.GetPanelSaveData(this.PanelType).Value = this.ToSaveData();
public virtual string ToSaveData()
{
try
{
return $"{ShouldSaveActiveState && Enabled}" +
$"|{Rect.RectAnchorsToString()}" +
$"|{Rect.RectPositionToString()}";
return string.Join("|", new string[]
{
$"{ShouldSaveActiveState && Enabled}",
Rect.RectAnchorsToString(),
Rect.RectPositionToString()
});
}
catch (Exception ex)
{
@ -193,7 +195,13 @@ namespace UnityExplorer.UI.Panels
}
}
public virtual void ApplySaveData(string data)
public virtual void ApplySaveData()
{
string data = ConfigManager.GetPanelSaveData(this.PanelType).Value;
ApplySaveData(data);
}
protected virtual void ApplySaveData(string data)
{
if (string.IsNullOrEmpty(data))
return;
@ -210,17 +218,14 @@ namespace UnityExplorer.UI.Panels
{
ExplorerCore.LogWarning("Invalid or corrupt panel save data! Restoring to default.");
SetTransformDefaults();
UIManager.Initializing = false;
DoSaveToConfigElement();
ConfigManager.InternalHandler.SaveConfig();
UIManager.Initializing = true;
SetSaveDataToConfigValue();
}
}
#endregion
// UI Construction
public abstract void ConstructPanelContent();
public void ConstructUI()
{
//this.Enabled = true;
@ -275,7 +280,7 @@ namespace UnityExplorer.UI.Panels
closeBtn.OnClick += () =>
{
UIManager.SetPanelActive(this.PanelType, false);
SaveToConfigManager();
SaveInternalData();
};
if (!CanDragAndResize)
@ -300,7 +305,7 @@ namespace UnityExplorer.UI.Panels
// apply panel save data or revert to default
try
{
ApplySaveData(GetSaveDataFromConfigManager());
ApplySaveData();
}
catch (Exception ex)
{
@ -308,7 +313,20 @@ namespace UnityExplorer.UI.Panels
SetTransformDefaults();
}
LayoutRebuilder.ForceRebuildLayoutImmediate(this.Rect);
RuntimeProvider.Instance.StartCoroutine(LateSetupCoroutine());
// simple listener for saving enabled state
this.OnToggleEnabled += (bool val) =>
{
SaveInternalData();
};
ApplyingSaveData = false;
}
private IEnumerator LateSetupCoroutine()
{
yield return null;
// ensure initialized position is valid
EnsureValidSize();
@ -316,14 +334,6 @@ namespace UnityExplorer.UI.Panels
// update dragger and save data
Dragger.OnEndResize();
// simple listener for saving enabled state
this.OnToggleEnabled += (bool val) =>
{
SaveToConfigManager();
};
ApplyingSaveData = false;
}
public override void ConstructUI(GameObject parent) => ConstructUI();
@ -380,7 +390,7 @@ namespace UnityExplorer.UI.Panels
return string.Format(CultureInfo.InvariantCulture, "{0},{1}", new object[]
{
rect.localPosition.x, rect.localPosition.y
rect.anchoredPosition.x, rect.anchoredPosition.y
});
}
@ -398,10 +408,10 @@ namespace UnityExplorer.UI.Panels
if (split.Length != 2)
throw new Exception($"stringPosition split is unexpected length: {split.Length}");
Vector3 vector = rect.localPosition;
Vector3 vector = rect.anchoredPosition;
vector.x = float.Parse(split[0], CultureInfo.InvariantCulture);
vector.y = float.Parse(split[1], CultureInfo.InvariantCulture);
rect.localPosition = vector;
rect.anchoredPosition = vector;
}
}

View File

@ -27,17 +27,6 @@ namespace UnityExplorer.UI.Panels
private ButtonListHandler<GameObject, ButtonCell> dataHandler;
private ScrollPool<ButtonCell> buttonScrollPool;
public override void ConstructPanelContent()
{
dataHandler = new ButtonListHandler<GameObject, ButtonCell>(buttonScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked);
buttonScrollPool = UIFactory.CreateScrollPool<ButtonCell>(this.content, "ResultsList", out GameObject scrollObj,
out GameObject scrollContent);
buttonScrollPool.Initialize(dataHandler);
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
}
public void ShowResults()
{
dataHandler.RefreshData();
@ -65,6 +54,17 @@ namespace UnityExplorer.UI.Panels
cell.Button.ButtonText.text = $"<color=cyan>{obj.name}</color> ({obj.transform.GetTransformPath(true)})";
}
public override void ConstructPanelContent()
{
dataHandler = new ButtonListHandler<GameObject, ButtonCell>(buttonScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked);
buttonScrollPool = UIFactory.CreateScrollPool<ButtonCell>(this.content, "ResultsList", out GameObject scrollObj,
out GameObject scrollContent);
buttonScrollPool.Initialize(dataHandler);
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
}
protected internal override void DoSetDefaultPosAndAnchors()
{
this.Rect.anchorMin = new Vector2(0.5f, 0.5f);
@ -72,8 +72,5 @@ namespace UnityExplorer.UI.Panels
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 500f);
this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 500f);
}
public override void DoSaveToConfigElement() { }
public override string GetSaveDataFromConfigManager() => null;
}
}

View File

@ -1,19 +1,10 @@
using HarmonyLib;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Config;
using UnityExplorer.CSConsole;
using UnityExplorer.Inspectors;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib;
using UniverseLib.Input;
@ -35,6 +26,7 @@ namespace UnityExplorer.UI
MouseInspector,
UIInspectorResults,
HookManager,
Clipboard
}
public enum VerticalAnchor
@ -47,15 +39,17 @@ namespace UnityExplorer.UI
public static bool Initializing { get; internal set; } = true;
private static UIBase uiBase;
public static GameObject UIRoot => uiBase?.RootObject;
internal static UIBase UiBase { get; private set; }
public static GameObject UIRoot => UiBase?.RootObject;
public static RectTransform UIRootRect { get; private set; }
public static Canvas UICanvas { get; private set; }
internal static GameObject PanelHolder { get; private set; }
private static readonly Dictionary<Panels, UIPanel> UIPanels = new Dictionary<Panels, UIPanel>();
internal static readonly Dictionary<Panels, UIPanel> UIPanels = new();
public static RectTransform NavBarRect;
public static GameObject NavbarTabButtonHolder;
public static Dropdown MouseInspectDropdown;
private static readonly Vector2 NAVBAR_DIMENSIONS = new(1020f, 35f);
private static ButtonRef closeBtn;
private static ButtonRef pauseBtn;
@ -63,12 +57,15 @@ namespace UnityExplorer.UI
private static bool pauseButtonPausing;
private static float lastTimeScale;
private static int lastScreenWidth;
private static int lastScreenHeight;
public static bool ShowMenu
{
get => uiBase != null && uiBase.Enabled;
get => UiBase != null && UiBase.Enabled;
set
{
if (uiBase == null || !UIRoot || uiBase.Enabled == value)
if (UiBase == null || !UIRoot || UiBase.Enabled == value)
return;
UniversalUI.SetUIActive(ExplorerCore.GUID, value);
@ -79,17 +76,28 @@ namespace UnityExplorer.UI
internal static void InitUI()
{
uiBase = UniversalUI.RegisterUI(ExplorerCore.GUID, Update);
UiBase = UniversalUI.RegisterUI(ExplorerCore.GUID, Update);
UIRootRect = UIRoot.GetComponent<RectTransform>();
UICanvas = UIRoot.GetComponent<Canvas>();
DisplayManager.Init();
var display = DisplayManager.ActiveDisplay;
lastScreenWidth = display.renderingWidth;
lastScreenHeight = display.renderingHeight;
// Create UI.
CreatePanelHolder();
CreateTopNavBar();
// This could be automated with Assembly.GetTypes(),
// but the order is important and I'd have to write something to handle the order.
UIPanels.Add(Panels.AutoCompleter, new AutoCompleteModal());
UIPanels.Add(Panels.ObjectExplorer, new ObjectExplorerPanel());
UIPanels.Add(Panels.Inspector, new InspectorPanel());
UIPanels.Add(Panels.CSConsole, new CSConsolePanel());
UIPanels.Add(Panels.HookManager, new HookManagerPanel());
UIPanels.Add(Panels.Clipboard, new ClipboardPanel());
UIPanels.Add(Panels.ConsoleLog, new LogPanel());
UIPanels.Add(Panels.Options, new OptionsPanel());
UIPanels.Add(Panels.UIInspectorResults, new UiInspectorResultsPanel());
@ -98,29 +106,25 @@ namespace UnityExplorer.UI
foreach (var panel in UIPanels.Values)
panel.ConstructUI();
// Call some initialize methods
Notification.Init();
ConsoleController.Init();
// Add this listener to prevent ScrollPool doing anything while we are resizing panels
ScrollPool<ICell>.writingLockedListeners.Add(() => !PanelDragger.Resizing);
// Set default menu visibility
ShowMenu = !ConfigManager.Hide_On_Startup.Value;
lastScreenWidth = Screen.width;
lastScreenHeight = Screen.height;
// Failsafe fix
// Failsafe fix, in some games all dropdowns displayed values are blank on startup for some reason.
foreach (var dropdown in UIRoot.GetComponentsInChildren<Dropdown>(true))
dropdown.RefreshShownValue();
timeInput.Text = string.Empty;
timeInput.Text = Time.timeScale.ToString();
ScrollPool<ICell>.writingLockedListeners.Add(() => !PanelDragger.Resizing);
Initializing = false;
}
// Main UI Update loop
private static int lastScreenWidth;
private static int lastScreenHeight;
public static void Update()
{
if (!UIRoot)
@ -133,6 +137,9 @@ namespace UnityExplorer.UI
return;
}
// Update Notification modal
Notification.Update();
// Check forceUnlockMouse toggle
if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value))
UniverseLib.Config.ConfigManager.Force_Unlock_Mouse = !UniverseLib.Config.ConfigManager.Force_Unlock_Mouse;
@ -158,7 +165,8 @@ namespace UnityExplorer.UI
}
// check screen dimension change
if (Screen.width != lastScreenWidth || Screen.height != lastScreenHeight)
var display = DisplayManager.ActiveDisplay;
if (display.renderingWidth != lastScreenWidth || display.renderingHeight != lastScreenHeight)
OnScreenDimensionsChanged();
}
@ -206,14 +214,14 @@ namespace UnityExplorer.UI
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(1080f, 35f);
NavBarRect.sizeDelta = NAVBAR_DIMENSIONS;
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(1080f, 35f);
NavBarRect.sizeDelta = NAVBAR_DIMENSIONS;
break;
}
}
@ -222,8 +230,9 @@ namespace UnityExplorer.UI
private static void OnScreenDimensionsChanged()
{
lastScreenWidth = Screen.width;
lastScreenHeight = Screen.height;
var display = DisplayManager.ActiveDisplay;
lastScreenWidth = display.renderingWidth;
lastScreenHeight = display.renderingHeight;
foreach (var panel in UIPanels)
{
@ -243,6 +252,8 @@ namespace UnityExplorer.UI
closeBtn.ButtonText.text = val.ToString();
}
// Time controls
private static void OnTimeInputEndEdit(string val)
{
if (pauseButtonPausing)
@ -328,22 +339,15 @@ namespace UnityExplorer.UI
timeInput = UIFactory.CreateInputField(navbarPanel, "TimeInput", "timeScale");
UIFactory.SetLayoutElement(timeInput.Component.gameObject, minHeight: 25, minWidth: 40);
timeInput.Text = Time.timeScale.ToString("F2");
timeInput.Component.GetOnEndEdit().AddListener(OnTimeInputEndEdit);
timeInput.Text = string.Empty;
timeInput.Text = Time.timeScale.ToString();
pauseBtn = UIFactory.CreateButton(navbarPanel, "PauseButton", "||", new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(pauseBtn.Component.gameObject, minHeight: 25, minWidth: 25);
pauseBtn.OnClick += OnPauseButtonClicked;
// Inspect under mouse dropdown
var mouseDropdown = UIFactory.CreateDropdown(navbarPanel, out MouseInspectDropdown, "Mouse Inspect", 14,
InspectUnderMouse.OnDropdownSelect);
UIFactory.SetLayoutElement(mouseDropdown, minHeight: 25, minWidth: 140);
MouseInspectDropdown.options.Add(new Dropdown.OptionData("Mouse Inspect"));
MouseInspectDropdown.options.Add(new Dropdown.OptionData("World"));
MouseInspectDropdown.options.Add(new Dropdown.OptionData("UI"));
// Hide menu button
closeBtn = UIFactory.CreateButton(navbarPanel, "CloseButton", ConfigManager.Master_Toggle.Value.ToString());

View File

@ -5,7 +5,7 @@ using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UniverseLib.Input;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Runtime;
using UnityExplorer.UI;
using UnityExplorer.UI.Panels;
using UniverseLib.UI.Widgets;
@ -164,11 +164,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
if (!CurrentHandler.InputField.UIRoot.activeInHierarchy)
ReleaseOwnership(CurrentHandler);
else
{
UpdatePosition();
}
}
}
// Setting autocomplete cell buttons
@ -228,9 +226,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
private int lastCaretPosition;
private Vector3 lastInputPosition;
private void UpdatePosition()
internal void UpdatePosition()
{
if (CurrentHandler == null || !CurrentHandler.InputField.Component.isFocused)
if (CurrentHandler == null)
return;
var input = CurrentHandler.InputField;
@ -255,9 +253,10 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
}
else
{
var textGen = input.Component.textComponent.cachedTextGenerator;
var pos = input.UIRoot.transform.TransformPoint(textGen.characters[0].cursorPos);
uiRoot.transform.position = new Vector3(pos.x + 10, pos.y - 20, 0);
uiRoot.transform.position = input.Rect.position + new Vector3(-(input.Rect.rect.width / 2) + 10, -20, 0);
//var textGen = input.Component.textComponent.cachedTextGenerator;
//var pos = input.UIRoot.transform.TransformPoint(textGen.characters[0].cursorPos);
//uiRoot.transform.position = new Vector3(pos.x + 10, pos.y - 20, 0);
}
this.Dragger.OnEndResize();
@ -316,12 +315,5 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
UIRoot.SetActive(false);
}
public override void DoSaveToConfigElement()
{
// not savable
}
public override string GetSaveDataFromConfigManager() => null;
}
}

View File

@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using UnityExplorer.CacheObject.IValues;
using UniverseLib;
using UniverseLib.UI;
namespace UnityExplorer.UI.Widgets.AutoComplete
{
public class EnumCompleter : ISuggestionProvider
{
public bool Enabled
{
get => _enabled;
set
{
_enabled = value;
if (!_enabled)
AutoCompleteModal.Instance.ReleaseOwnership(this);
}
}
private bool _enabled = true;
public event Action<Suggestion> SuggestionClicked;
public Type EnumType { get; set; }
public InputFieldRef InputField { get; }
public bool AnchorToCaretPosition => false;
private readonly List<Suggestion> suggestions = new List<Suggestion>();
private readonly HashSet<string> suggestedValues = new HashSet<string>();
private OrderedDictionary enumValues;
internal string chosenSuggestion;
bool ISuggestionProvider.AllowNavigation => false;
public EnumCompleter(Type enumType, InputFieldRef inputField)
{
EnumType = enumType;
InputField = inputField;
inputField.OnValueChanged += OnInputFieldChanged;
if (EnumType != null)
CacheEnumValues();
}
public void CacheEnumValues()
{
enumValues = InteractiveEnum.GetEnumValues(EnumType);
}
private string GetLastSplitInput(string fullInput)
{
string ret = fullInput;
int lastSplit = fullInput.LastIndexOf(',');
if (lastSplit >= 0)
{
lastSplit++;
if (lastSplit == fullInput.Length)
ret = "";
else
ret = fullInput.Substring(lastSplit);
}
return ret;
}
public void OnSuggestionClicked(Suggestion suggestion)
{
chosenSuggestion = suggestion.UnderlyingValue;
string lastInput = GetLastSplitInput(InputField.Text);
if (lastInput != suggestion.UnderlyingValue)
{
string valueToSet = InputField.Text;
if (valueToSet.Length > 0)
valueToSet = valueToSet.Substring(0, InputField.Text.Length - lastInput.Length);
valueToSet += suggestion.UnderlyingValue;
InputField.Text = valueToSet;
//InputField.Text += suggestion.UnderlyingValue.Substring(lastInput.Length);
}
SuggestionClicked?.Invoke(suggestion);
suggestions.Clear();
AutoCompleteModal.Instance.SetSuggestions(suggestions);
}
public void HelperButtonClicked()
{
GetSuggestions("");
AutoCompleteModal.Instance.TakeOwnership(this);
AutoCompleteModal.Instance.SetSuggestions(suggestions);
}
private void OnInputFieldChanged(string value)
{
if (!Enabled)
return;
if (string.IsNullOrEmpty(value) || GetLastSplitInput(value) == chosenSuggestion)
{
chosenSuggestion = null;
AutoCompleteModal.Instance.ReleaseOwnership(this);
}
else
{
GetSuggestions(value);
AutoCompleteModal.Instance.TakeOwnership(this);
AutoCompleteModal.Instance.SetSuggestions(suggestions);
}
}
private void GetSuggestions(string value)
{
suggestions.Clear();
suggestedValues.Clear();
if (EnumType == null)
{
ExplorerCore.LogWarning("Autocompleter Base enum type is null!");
return;
}
value = GetLastSplitInput(value);
for (int i = 0; i < this.enumValues.Count; i++)
{
var enumValue = (CachedEnumValue)enumValues[i];
if (enumValue.Name.ContainsIgnoreCase(value))
AddSuggestion(enumValue.Name);
}
}
internal static readonly Dictionary<string, string> sharedValueToLabel = new Dictionary<string, string>(4096);
void AddSuggestion(string value)
{
if (suggestedValues.Contains(value))
return;
suggestedValues.Add(value);
if (!sharedValueToLabel.ContainsKey(value))
sharedValueToLabel.Add(value, $"<color={SignatureHighlighter.CONST}>{value}</color>");
suggestions.Add(new Suggestion(sharedValueToLabel[value], value));
}
}
}

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityExplorer.Core;
namespace UnityExplorer.UI.Widgets.AutoComplete
{
@ -12,8 +11,6 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
public readonly string DisplayText;
public readonly string UnderlyingValue;
public string Combined => DisplayText + UnderlyingValue;
public Suggestion(string displayText, string underlyingValue)
{
DisplayText = displayText;

View File

@ -9,12 +9,24 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
{
internal static readonly Dictionary<string, string> sharedTypeToLabel = new Dictionary<string, string>(4096);
public bool Enabled
{
get => _enabled;
set
{
_enabled = value;
if (!_enabled)
AutoCompleteModal.Instance.ReleaseOwnership(this);
}
}
private bool _enabled = true;
public event Action<Suggestion> SuggestionClicked;
public Type BaseType { get; set; }
public Type[] GenericConstraints { get; set; }
private bool allowAbstract;
private bool allowEnum;
private readonly bool allowAbstract;
private readonly bool allowEnum;
public InputFieldRef InputField { get; }
public bool AnchorToCaretPosition => false;
@ -61,6 +73,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
private void OnInputFieldChanged(string value)
{
if (!Enabled)
return;
if (string.IsNullOrEmpty(value) || value == chosenSuggestion)
{
chosenSuggestion = null;

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib.UI.Models;
namespace UnityExplorer.UI.Widgets
{
public abstract class BaseArgumentHandler : IPooledObject
{
protected EvaluateWidget evaluator;
internal Text argNameLabel;
internal InputFieldRef inputField;
internal TypeCompleter typeCompleter;
// IPooledObject
public float DefaultHeight => 25f;
public GameObject UIRoot { get; set; }
public abstract void CreateSpecialContent();
public GameObject CreateContent(GameObject parent)
{
UIRoot = UIFactory.CreateUIObject("ArgRow", parent);
UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 50, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(UIRoot, false, false, true, true, 5);
UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
argNameLabel = UIFactory.CreateLabel(UIRoot, "ArgLabel", "not set", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(argNameLabel.gameObject, minWidth: 40, flexibleWidth: 90, minHeight: 25, flexibleHeight: 50);
argNameLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
inputField = UIFactory.CreateInputField(UIRoot, "InputField", "...");
UIFactory.SetLayoutElement(inputField.UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000);
inputField.Component.lineType = InputField.LineType.MultiLineNewline;
inputField.UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
typeCompleter = new TypeCompleter(typeof(object), this.inputField);
typeCompleter.Enabled = false;
CreateSpecialContent();
return UIRoot;
}
}
}

View File

@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UniverseLib.UI.Models;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib.UI;
using UniverseLib;
using UnityExplorer.CacheObject;
namespace UnityExplorer.UI.Widgets
{
public class EvaluateWidget : IPooledObject
{
public CacheMember Owner { get; set; }
public GameObject UIRoot { get; set; }
public float DefaultHeight => -1f;
private ParameterInfo[] parameters;
internal GameObject parametersHolder;
private ParameterHandler[] paramHandlers;
private Type[] genericArguments;
internal GameObject genericArgumentsHolder;
private GenericArgumentHandler[] genericHandlers;
public void OnBorrowedFromPool(CacheMember owner)
{
this.Owner = owner;
parameters = owner.Arguments;
paramHandlers = new ParameterHandler[parameters.Length];
genericArguments = owner.GenericArguments;
genericHandlers = new GenericArgumentHandler[genericArguments.Length];
SetArgRows();
this.UIRoot.SetActive(true);
}
public void OnReturnToPool()
{
foreach (var widget in paramHandlers)
{
widget.OnReturned();
Pool<ParameterHandler>.Return(widget);
}
paramHandlers = null;
foreach (var widget in genericHandlers)
{
widget.OnReturned();
Pool<GenericArgumentHandler>.Return(widget);
}
genericHandlers = null;
this.Owner = null;
}
public Type[] TryParseGenericArguments()
{
Type[] outArgs = new Type[genericArguments.Length];
for (int i = 0; i < genericArguments.Length; i++)
outArgs[i] = genericHandlers[i].Evaluate();
return outArgs;
}
public object[] TryParseArguments()
{
object[] outArgs = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
outArgs[i] = paramHandlers[i].Evaluate();
return outArgs;
}
private void SetArgRows()
{
if (genericArguments.Any())
{
genericArgumentsHolder.SetActive(true);
SetGenericRows();
}
else
genericArgumentsHolder.SetActive(false);
if (parameters.Any())
{
parametersHolder.SetActive(true);
SetNormalArgRows();
}
else
parametersHolder.SetActive(false);
}
private void SetGenericRows()
{
for (int i = 0; i < genericArguments.Length; i++)
{
var type = genericArguments[i];
var holder = genericHandlers[i] = Pool<GenericArgumentHandler>.Borrow();
holder.UIRoot.transform.SetParent(this.genericArgumentsHolder.transform, false);
holder.OnBorrowed(this, type);
}
}
private void SetNormalArgRows()
{
for (int i = 0; i < parameters.Length; i++)
{
var param = parameters[i];
var holder = paramHandlers[i] = Pool<ParameterHandler>.Borrow();
holder.UIRoot.transform.SetParent(this.parametersHolder.transform, false);
holder.OnBorrowed(this, param);
}
}
public GameObject CreateContent(GameObject parent)
{
UIRoot = UIFactory.CreateVerticalGroup(parent, "EvaluateWidget", false, false, true, true, 3, new Vector4(2, 2, 2, 2),
new Color(0.15f, 0.15f, 0.15f));
UIFactory.SetLayoutElement(UIRoot, minWidth: 50, flexibleWidth: 9999, minHeight: 50, flexibleHeight: 800);
//UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// generic args
this.genericArgumentsHolder = UIFactory.CreateUIObject("GenericHolder", UIRoot);
UIFactory.SetLayoutElement(genericArgumentsHolder, flexibleWidth: 1000);
var genericsTitle = UIFactory.CreateLabel(genericArgumentsHolder, "GenericsTitle", "Generic Arguments", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(genericsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(genericArgumentsHolder, false, false, true, true, 3);
UIFactory.SetLayoutElement(genericArgumentsHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
//genericArgHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// args
this.parametersHolder = UIFactory.CreateUIObject("ArgHolder", UIRoot);
UIFactory.SetLayoutElement(parametersHolder, flexibleWidth: 1000);
var argsTitle = UIFactory.CreateLabel(parametersHolder, "ArgsTitle", "Arguments", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(argsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(parametersHolder, false, false, true, true, 3);
UIFactory.SetLayoutElement(parametersHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
//argHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// evaluate button
var evalButton = UIFactory.CreateButton(UIRoot, "EvaluateButton", "Evaluate", new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(evalButton.Component.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0);
evalButton.OnClick += () =>
{
Owner.EvaluateAndSetCell();
};
return UIRoot;
}
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UniverseLib;
namespace UnityExplorer.UI.Widgets
{
public class GenericArgumentHandler : BaseArgumentHandler
{
private Type genericType;
public void OnBorrowed(EvaluateWidget evaluator, Type genericConstraint)
{
this.evaluator = evaluator;
this.genericType = genericConstraint;
typeCompleter.Enabled = true;
typeCompleter.BaseType = genericType;
typeCompleter.CacheTypes();
var constraints = genericType.GetGenericParameterConstraints();
typeCompleter.GenericConstraints = constraints;
var sb = new StringBuilder($"<color={SignatureHighlighter.CONST}>{genericType.Name}</color>");
for (int j = 0; j < constraints.Length; j++)
{
if (j == 0) sb.Append(' ').Append('(');
else sb.Append(',').Append(' ');
sb.Append(SignatureHighlighter.Parse(constraints[j], false));
if (j + 1 == constraints.Length)
sb.Append(')');
}
argNameLabel.text = sb.ToString();
}
public void OnReturned()
{
this.evaluator = null;
this.genericType = null;
this.typeCompleter.Enabled = false;
this.inputField.Text = "";
}
public Type Evaluate()
{
return ReflectionUtility.GetTypeByName(this.inputField.Text)
?? throw new Exception($"Could not find any type by name '{this.inputField.Text}'!");
}
public override void CreateSpecialContent()
{
}
}
}

View File

@ -0,0 +1,177 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.CacheObject.IValues;
using UnityExplorer.UI.Panels;
using UnityExplorer.UI.Widgets.AutoComplete;
using UniverseLib;
using UniverseLib.UI;
namespace UnityExplorer.UI.Widgets
{
public class ParameterHandler : BaseArgumentHandler
{
private ParameterInfo paramInfo;
private Type paramType;
internal EnumCompleter enumCompleter;
private ButtonRef enumHelperButton;
private bool usingBasicLabel;
private object basicValue;
private GameObject basicLabelHolder;
private Text basicLabel;
private ButtonRef pasteButton;
public void OnBorrowed(EvaluateWidget evaluator, ParameterInfo paramInfo)
{
this.evaluator = evaluator;
this.paramInfo = paramInfo;
this.paramType = paramInfo.ParameterType;
if (paramType.IsByRef)
paramType = paramType.GetElementType();
this.argNameLabel.text =
$"{SignatureHighlighter.Parse(paramType, false)} <color={SignatureHighlighter.LOCAL_ARG}>{paramInfo.Name}</color>";
if (ParseUtility.CanParse(paramType) || typeof(Type).IsAssignableFrom(paramType))
{
usingBasicLabel = false;
this.inputField.Component.gameObject.SetActive(true);
this.basicLabelHolder.SetActive(false);
this.typeCompleter.Enabled = typeof(Type).IsAssignableFrom(paramType);
this.enumCompleter.Enabled = paramType.IsEnum;
this.enumHelperButton.Component.gameObject.SetActive(paramType.IsEnum);
if (!typeCompleter.Enabled)
{
if (paramType == typeof(string))
inputField.PlaceholderText.text = "...";
else
inputField.PlaceholderText.text = $"eg. {ParseUtility.GetExampleInput(paramType)}";
}
else
{
inputField.PlaceholderText.text = "Enter a Type name...";
this.typeCompleter.BaseType = typeof(object);
this.typeCompleter.CacheTypes();
}
if (enumCompleter.Enabled)
{
enumCompleter.EnumType = paramType;
enumCompleter.CacheEnumValues();
}
}
else
{
// non-parsable, and not a Type
usingBasicLabel = true;
this.inputField.Component.gameObject.SetActive(false);
this.basicLabelHolder.SetActive(true);
this.typeCompleter.Enabled = false;
this.enumCompleter.Enabled = false;
this.enumHelperButton.Component.gameObject.SetActive(false);
SetDisplayedValueFromPaste();
}
}
public void OnReturned()
{
this.evaluator = null;
this.paramInfo = null;
this.enumCompleter.Enabled = false;
this.typeCompleter.Enabled = false;
this.inputField.Text = "";
this.usingBasicLabel = false;
this.basicValue = null;
}
public object Evaluate()
{
if (usingBasicLabel)
return basicValue;
var input = this.inputField.Text;
if (typeof(Type).IsAssignableFrom(paramType))
return ReflectionUtility.GetTypeByName(input);
if (paramType == typeof(string))
return input;
if (string.IsNullOrEmpty(input))
{
if (paramInfo.IsOptional)
return paramInfo.DefaultValue;
else
return null;
}
if (!ParseUtility.TryParse(input, paramType, out object parsed, out Exception ex))
{
ExplorerCore.LogWarning($"Cannot parse argument '{paramInfo.Name}' ({paramInfo.ParameterType.Name})" +
$"{(ex == null ? "" : $", {ex.GetType().Name}: {ex.Message}")}");
return null;
}
else
return parsed;
}
private void OnPasteClicked()
{
if (ClipboardPanel.TryPaste(this.paramType, out object paste))
{
basicValue = paste;
SetDisplayedValueFromPaste();
}
}
private void SetDisplayedValueFromPaste()
{
if (usingBasicLabel)
basicLabel.text = ToStringUtility.ToStringWithType(basicValue, paramType, false);
else
{
if (typeof(Type).IsAssignableFrom(paramType))
inputField.Text = (basicValue as Type).FullDescription();
else
inputField.Text = ParseUtility.ToStringForInput(basicValue, paramType);
}
}
public override void CreateSpecialContent()
{
enumCompleter = new(paramType, this.inputField)
{
Enabled = false
};
enumHelperButton = UIFactory.CreateButton(UIRoot, "EnumHelper", "▼");
UIFactory.SetLayoutElement(enumHelperButton.Component.gameObject, minWidth: 25, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
enumHelperButton.OnClick += enumCompleter.HelperButtonClicked;
basicLabelHolder = UIFactory.CreateHorizontalGroup(UIRoot, "BasicLabelHolder", true, true, true, true, bgColor: new(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(basicLabelHolder, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000);
basicLabel = UIFactory.CreateLabel(basicLabelHolder, "BasicLabel", "null", TextAnchor.MiddleLeft);
basicLabel.gameObject.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
pasteButton = UIFactory.CreateButton(UIRoot, "PasteButton", "Paste", new Color(0.13f, 0.13f, 0.13f, 1f));
UIFactory.SetLayoutElement(pasteButton.Component.gameObject, minHeight: 25, minWidth: 28, flexibleWidth: 0);
pasteButton.ButtonText.color = Color.green;
pasteButton.ButtonText.fontSize = 10;
pasteButton.OnClick += OnPasteClicked;
}
}
}

View File

@ -6,6 +6,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B21DBDE3-5D6F-4726-93AB-CC3CC68BAE7D}</ProjectGuid>
<OutputType>Library</OutputType>
<LangVersion>9.0</LangVersion>
<AppDesignerFolder>Properties</AppDesignerFolder>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
@ -105,8 +106,11 @@
<HintPath>..\lib\mcs-unity\mcs\bin\Release\mcs.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="INIFileParser, Version=2.5.2.0, Culture=neutral, PublicKeyToken=79af7b307b65cf3c, processorArchitecture=MSIL">
<HintPath>packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll</HintPath>
</ItemGroup>
<!-- Non-MelonLoader (it includes Tomlet) -->
<ItemGroup Condition="'$(IsMelonLoader)'=='false'">
<Reference Include="Tomlet, Version=3.1.3.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\Samboy063.Tomlet.3.1.3\lib\net35\Tomlet.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
@ -162,9 +166,6 @@
</ItemGroup>
<!-- Mono refs -->
<ItemGroup Condition="'$(IsCpp)'=='false'">
<Reference Include="UniverseLib.Mono">
<HintPath>packages\UniverseLib.1.0.1\lib\net35\UniverseLib.Mono.dll</HintPath>
</Reference>
<Reference Include="UnityEngine">
<HintPath>..\lib\mono\UnityEngine.dll</HintPath>
<Private>False</Private>
@ -173,11 +174,14 @@
<HintPath>..\lib\mono\UnityEngine.UI.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UniverseLib.Mono">
<HintPath>packages\UniverseLib.1.1.2\lib\net35\UniverseLib.Mono.dll</HintPath>
</Reference>
</ItemGroup>
<!-- Il2Cpp refs -->
<ItemGroup Condition="'$(IsCpp)'=='true'">
<Reference Include="UniverseLib.IL2CPP">
<HintPath>packages\UniverseLib.1.0.1\lib\net472\UniverseLib.IL2CPP.dll</HintPath>
<HintPath>packages\UniverseLib.1.1.2\lib\net472\UniverseLib.IL2CPP.dll</HintPath>
</Reference>
<Reference Include="UnhollowerBaseLib">
<HintPath>..\lib\Il2CppAssemblyUnhollower\UnhollowerBaseLib\bin\Release\net4.7.2\UnhollowerBaseLib.dll</HintPath>
@ -224,7 +228,7 @@
<Compile Include="Hooks\HookCell.cs" />
<Compile Include="Hooks\HookInstance.cs" />
<Compile Include="Hooks\HookManager.cs" />
<Compile Include="Core\Config\InternalConfigHandler.cs" />
<Compile Include="Config\InternalConfigHandler.cs" />
<Compile Include="CacheObject\CacheConfigEntry.cs" />
<Compile Include="CacheObject\Views\CacheConfigCell.cs" />
<Compile Include="CSConsole\CSAutoCompleter.cs" />
@ -237,7 +241,7 @@
<Compile Include="CSConsole\Lexers\SymbolLexer.cs" />
<Compile Include="CSConsole\ScriptEvaluator.cs" />
<Compile Include="CSConsole\ScriptInteraction.cs" />
<Compile Include="Core\ExplorerBehaviour.cs" />
<Compile Include="ExplorerBehaviour.cs" />
<Compile Include="Hooks\AddHookCell.cs" />
<Compile Include="Inspectors\GameObjectWidgets\ComponentCell.cs" />
<Compile Include="Inspectors\GameObjectWidgets\ComponentList.cs" />
@ -255,7 +259,11 @@
<Compile Include="CacheObject\Views\CacheListEntryCell.cs" />
<Compile Include="CacheObject\Views\CacheMemberCell.cs" />
<Compile Include="CacheObject\Views\CacheObjectCell.cs" />
<Compile Include="CacheObject\Views\EvaluateWidget.cs" />
<Compile Include="UI\DisplayManager.cs" />
<Compile Include="UI\Notification.cs" />
<Compile Include="UI\Panels\ClipboardPanel.cs" />
<Compile Include="UI\Widgets\AutoComplete\EnumCompleter.cs" />
<Compile Include="UI\Widgets\EvaluateWidget\EvaluateWidget.cs" />
<Compile Include="Inspectors\GameObjectInspector.cs" />
<Compile Include="CacheObject\ICacheObjectController.cs" />
<Compile Include="Inspectors\InspectorManager.cs" />
@ -273,22 +281,22 @@
<Compile Include="Inspectors\ReflectionInspector.cs" />
<Compile Include="CacheObject\IValues\InteractiveValueStruct.cs" />
<Compile Include="UI\Panels\HookManagerPanel.cs" />
<Compile Include="UI\Panels\UiInspectorResultsPanel.cs" />
<Compile Include="UI\Panels\UIInspectorResultsPanel.cs" />
<Compile Include="UI\Panels\LogPanel.cs" />
<Compile Include="UI\Panels\CSConsolePanel.cs" />
<Compile Include="UI\Panels\OptionsPanel.cs" />
<Compile Include="UI\Widgets\AutoComplete\ISuggestionProvider.cs" />
<Compile Include="UI\Widgets\AutoComplete\Suggestion.cs" />
<Compile Include="Core\Config\ConfigElement.cs" />
<Compile Include="Core\Config\ConfigHandler.cs" />
<Compile Include="Core\Config\ConfigManager.cs" />
<Compile Include="Core\Config\IConfigElement.cs" />
<Compile Include="Core\Runtime\Il2CppProvider.cs" />
<Compile Include="Core\Runtime\MonoProvider.cs" />
<Compile Include="Core\Runtime\RuntimeHelper.cs" />
<Compile Include="Config\ConfigElement.cs" />
<Compile Include="Config\ConfigHandler.cs" />
<Compile Include="Config\ConfigManager.cs" />
<Compile Include="Config\IConfigElement.cs" />
<Compile Include="Runtime\Il2CppProvider.cs" />
<Compile Include="Runtime\MonoProvider.cs" />
<Compile Include="Runtime\RuntimeHelper.cs" />
<Compile Include="ObjectExplorer\SceneHandler.cs" />
<Compile Include="ObjectExplorer\SearchProvider.cs" />
<Compile Include="Core\Tests\TestClass.cs" />
<Compile Include="Tests\TestClass.cs" />
<Compile Include="ExplorerCore.cs" />
<Compile Include="Loader\BepInEx\BepInExConfigHandler.cs" />
<Compile Include="Loader\BepInEx\ExplorerBepInPlugin.cs" />
@ -307,6 +315,9 @@
<Compile Include="UI\Widgets\AutoComplete\TypeCompleter.cs" />
<Compile Include="ObjectExplorer\ObjectSearch.cs" />
<Compile Include="ObjectExplorer\SceneExplorer.cs" />
<Compile Include="UI\Widgets\EvaluateWidget\BaseArgumentHandler.cs" />
<Compile Include="UI\Widgets\EvaluateWidget\GenericArgumentHandler.cs" />
<Compile Include="UI\Widgets\EvaluateWidget\ParameterHandler.cs" />
<Compile Include="UI\Widgets\TransformTree\CachedTransform.cs" />
<Compile Include="UI\Widgets\TransformTree\TransformCell.cs" />
<Compile Include="UI\Widgets\TransformTree\TransformTree.cs" />

View File

@ -2,7 +2,7 @@
<packages>
<package id="HarmonyX" version="2.5.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="Mono.Cecil" version="0.10.4" targetFramework="net35" />
<package id="UniverseLib" version="1.0.1" targetFramework="net472" />
<package id="Samboy063.Tomlet" version="3.1.3" targetFramework="net472" />
<package id="UniverseLib" version="1.1.2" targetFramework="net35" />
</packages>