Merge pull request #68 from sinai-dev/4.0.0-alpha

4.0 hotfixes
This commit is contained in:
Sinai 2021-05-18 21:20:09 +10:00 committed by GitHub
commit 6970dcbbc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 279 additions and 134 deletions

View File

@ -20,7 +20,6 @@
| Standalone | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Mono.zip) | | Standalone | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Il2Cpp.zip) | ✅ [link](https://github.com/sinai-dev/UnityExplorer/releases/latest/download/UnityExplorer.Standalone.Mono.zip) |
### Known issues ### Known issues
* UI layouts broken/unusable after changing resolutions: delete the file `data.ini` in the UnityExplorer folder (same place as where you put the DLL). Better fix being worked on.
* Any `MissingMethodException` or `NotSupportedException`: please report the issue and provide a copy of your mod loader log and/or Unity log. * Any `MissingMethodException` or `NotSupportedException`: please report the issue and provide a copy of your mod loader log and/or Unity log.
* The C# console may unexpectedly produce a GC Mark Overflow crash when calling certain outside methods. Not clear yet what is causing this, but it's being looked into. * The C# console may unexpectedly produce a GC Mark Overflow crash when calling certain outside methods. Not clear yet what is causing this, but it's being looked into.
* In IL2CPP, some IEnumerable and IDictionary types may fail enumeration. Waiting for the Unhollower rewrite to address this any further. * In IL2CPP, some IEnumerable and IDictionary types may fail enumeration. Waiting for the Unhollower rewrite to address this any further.
@ -95,8 +94,7 @@ Depending on the release you are using, the config file will be found at:
## Building ## Building
Building the project should be straight-forward, the references are all inside the `lib\` folder. 0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
1. Open the `src\UnityExplorer.sln` project in Visual Studio. 1. Open the `src\UnityExplorer.sln` project in Visual Studio.
2. Select `Solution 'UnityExplorer' (1 of 1 project)` in the Solution Explorer panel, and set the <b>Active config</b> property to the version you want to build, then build it. Alternatively, use "Batch Build" and select all releases. 2. Select `Solution 'UnityExplorer' (1 of 1 project)` in the Solution Explorer panel, and set the <b>Active config</b> property to the version you want to build, then build it. Alternatively, use "Batch Build" and select all releases.
3. The DLLs are built to the `Release\` folder in the root of the repository. 3. The DLLs are built to the `Release\` folder in the root of the repository.

View File

@ -36,6 +36,27 @@ namespace UnityExplorer
// ------- Misc extensions -------- // ------- Misc extensions --------
/// <summary>
/// Recursively check the type and its base types to find any generic arguments.
/// </summary>
public static bool TryGetGenericArguments(this Type type, out Type[] args)
{
if (type.IsGenericType)
{
args = type.GetGenericArguments();
return true;
}
else if (type.BaseType != null)
{
return TryGetGenericArguments(type.BaseType, out args);
}
else
{
args = null;
return false;
}
}
/// <summary> /// <summary>
/// Safely try to get all Types inside an Assembly. /// Safely try to get all Types inside an Assembly.
/// </summary> /// </summary>

View File

@ -14,8 +14,40 @@ using UnhollowerBaseLib;
namespace UnityExplorer.Tests namespace UnityExplorer.Tests
{ {
public class TestIndexer : IList<int>
{
private readonly List<int> list = new List<int>() { 1,2,3,4,5 };
public int Count => list.Count;
public bool IsReadOnly => false;
int IList<int>.this[int index]
{
get => list[index];
set => list[index] = value;
}
public int IndexOf(int item) => list.IndexOf(item);
public bool Contains(int item) => list.Contains(item);
public void Add(int item) => list.Add(item);
public void Insert(int index, int item) => list.Insert(index, item);
public bool Remove(int item) => list.Remove(item);
public void RemoveAt(int index) => list.RemoveAt(index);
public void Clear() => list.Clear();
public void CopyTo(int[] array, int arrayIndex) => list.CopyTo(array, arrayIndex);
public IEnumerator<int> GetEnumerator() => list.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => list.GetEnumerator();
}
public static class TestClass public static class TestClass
{ {
public static readonly TestIndexer AAAAATest = new TestIndexer();
public static void ATestMethod(string s, float f, Vector3 vector, DateTime date, Quaternion quater, bool b, CameraClearFlags enumvalue) public static void ATestMethod(string s, float f, Vector3 vector, DateTime date, Quaternion quater, bool b, CameraClearFlags enumvalue)
{ {
ExplorerCore.Log($"{s}, {f}, {vector.ToString()}, {date}, {quater.eulerAngles.ToString()}, {b}, {enumvalue}"); ExplorerCore.Log($"{s}, {f}, {vector.ToString()}, {date}, {quater.eulerAngles.ToString()}, {b}, {enumvalue}");

View File

@ -19,7 +19,7 @@ namespace UnityExplorer
public static class ExplorerCore public static class ExplorerCore
{ {
public const string NAME = "UnityExplorer"; public const string NAME = "UnityExplorer";
public const string VERSION = "4.0.0"; public const string VERSION = "4.0.1";
public const string AUTHOR = "Sinai"; public const string AUTHOR = "Sinai";
public const string GUID = "com.sinai.unityexplorer"; public const string GUID = "com.sinai.unityexplorer";

View File

@ -75,10 +75,11 @@ namespace UnityExplorer.UI.IValues
else else
{ {
var type = value.GetActualType(); var type = value.GetActualType();
if (type.IsGenericType && type.GetGenericArguments().Length == 2)
if (type.TryGetGenericArguments(out var args) && args.Length == 2)
{ {
KeyType = type.GetGenericArguments()[0]; KeyType = args[0];
ValueType = type.GetGenericArguments()[1]; ValueType = args[1];
} }
else else
{ {

View File

@ -2,6 +2,7 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.CacheObject; using UnityExplorer.UI.CacheObject;
@ -19,13 +20,15 @@ namespace UnityExplorer.UI.IValues
object ICacheObjectController.Target => this.CurrentOwner.Value; object ICacheObjectController.Target => this.CurrentOwner.Value;
public Type TargetType { get; private set; } public Type TargetType { get; private set; }
public override bool CanWrite => base.CanWrite && RefIList != null && !RefIList.IsReadOnly; public override bool CanWrite => base.CanWrite && ((RefIList != null && !RefIList.IsReadOnly) || IsWritableGenericIList);
public Type EntryType; public Type EntryType;
public IList RefIList; public IList RefIList;
public int ItemCount => values.Count; private bool IsWritableGenericIList;
private readonly List<object> values = new List<object>(); private PropertyInfo genericIndexer;
public int ItemCount => cachedEntries.Count;
private readonly List<CacheListEntry> cachedEntries = new List<CacheListEntry>(); private readonly List<CacheListEntry> cachedEntries = new List<CacheListEntry>();
public ScrollPool<CacheListEntryCell> ListScrollPool { get; private set; } public ScrollPool<CacheListEntryCell> ListScrollPool { get; private set; }
@ -49,7 +52,6 @@ namespace UnityExplorer.UI.IValues
private void ClearAndRelease() private void ClearAndRelease()
{ {
RefIList = null; RefIList = null;
values.Clear();
foreach (var entry in cachedEntries) foreach (var entry in cachedEntries)
{ {
@ -66,14 +68,14 @@ namespace UnityExplorer.UI.IValues
if (value == null) if (value == null)
{ {
// should never be null // should never be null
if (values.Any()) if (cachedEntries.Any())
ClearAndRelease(); ClearAndRelease();
} }
else else
{ {
var type = value.GetActualType(); var type = value.GetActualType();
if (type.IsGenericType) if (type.TryGetGenericArguments(out var args))
EntryType = type.GetGenericArguments()[0]; EntryType = args[0];
else if (type.HasElementType) else if (type.HasElementType)
EntryType = type.GetElementType(); EntryType = type.GetElementType();
else else
@ -92,7 +94,12 @@ namespace UnityExplorer.UI.IValues
{ {
RefIList = value as IList; RefIList = value as IList;
values.Clear(); // Check if the type implements IList<T> but not IList (ie. Il2CppArrayBase)
if (RefIList == null)
CheckGenericIList(value);
else
IsWritableGenericIList = false;
int idx = 0; int idx = 0;
if (ReflectionUtility.TryGetEnumerator(value, out IEnumerator enumerator)) if (ReflectionUtility.TryGetEnumerator(value, out IEnumerator enumerator))
@ -103,8 +110,6 @@ namespace UnityExplorer.UI.IValues
{ {
var entry = enumerator.Current; var entry = enumerator.Current;
values.Add(entry);
// If list count increased, create new cache entries // If list count increased, create new cache entries
CacheListEntry cache; CacheListEntry cache;
if (idx >= cachedEntries.Count) if (idx >= cachedEntries.Count)
@ -122,9 +127,9 @@ namespace UnityExplorer.UI.IValues
} }
// Remove excess cached entries if list count decreased // Remove excess cached entries if list count decreased
if (cachedEntries.Count > values.Count) if (cachedEntries.Count > idx)
{ {
for (int i = cachedEntries.Count - 1; i >= values.Count; i--) for (int i = cachedEntries.Count - 1; i >= idx; i--)
{ {
var cache = cachedEntries[i]; var cache = cachedEntries[i];
if (cache.CellView != null) if (cache.CellView != null)
@ -141,14 +146,61 @@ namespace UnityExplorer.UI.IValues
} }
} }
private void CheckGenericIList(object value)
{
try
{
var type = value.GetType();
if (type.GetInterfaces().Any(it => it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IList<>)))
IsWritableGenericIList = !(bool)type.GetProperty("IsReadOnly").GetValue(value, null);
else
IsWritableGenericIList = false;
if (IsWritableGenericIList)
{
// Find the "this[int index]" property.
// It might be a private implementation.
foreach (var prop in type.GetProperties(ReflectionUtility.FLAGS))
{
if ((prop.Name == "Item"
|| (prop.Name.StartsWith("System.Collections.Generic.IList<") && prop.Name.EndsWith(">.Item")))
&& prop.GetIndexParameters() is ParameterInfo[] parameters
&& parameters.Length == 1
&& parameters[0].ParameterType == typeof(int))
{
genericIndexer = prop;
break;
}
}
if (genericIndexer == null)
{
ExplorerCore.LogWarning($"Failed to find indexer property for IList<T> type '{type.FullName}'!");
IsWritableGenericIList = false;
}
}
}
catch (Exception ex)
{
ExplorerCore.LogWarning($"Exception processing IEnumerable for IList<T> check: {ex.ReflectionExToString()}");
IsWritableGenericIList = false;
}
}
// Setting the value of an index to the list // Setting the value of an index to the list
public void TrySetValueToIndex(object value, int index) public void TrySetValueToIndex(object value, int index)
{ {
try try
{ {
//value = value.TryCast(this.EntryType); if (!IsWritableGenericIList)
RefIList[index] = value; {
RefIList[index] = value;
}
else
{
genericIndexer.SetValue(CurrentOwner.Value, value, new object[] { index });
}
var entry = cachedEntries[index]; var entry = cachedEntries[index];
entry.SetValueFromSource(value); entry.SetValueFromSource(value);

View File

@ -226,7 +226,7 @@ namespace UnityExplorer.UI.Inspectors
var scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out var scrollbar, var scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out var scrollbar,
new Color(0.065f, 0.065f, 0.065f)); new Color(0.065f, 0.065f, 0.065f));
UIFactory.SetLayoutElement(scrollObj, minHeight: 300, flexibleWidth: 9999, flexibleHeight: 1); UIFactory.SetLayoutElement(scrollObj, minHeight: 250, preferredHeight: 300, flexibleHeight: 0, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2); UIFactory.SetLayoutGroup<VerticalLayoutGroup>(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2);
@ -244,10 +244,7 @@ namespace UnityExplorer.UI.Inspectors
{ {
var listHolder = UIFactory.CreateUIObject("ListHolders", UIRoot); var listHolder = UIFactory.CreateUIObject("ListHolders", UIRoot);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(listHolder, false, true, true, true, 8, 2, 2, 2, 2); UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(listHolder, false, true, true, true, 8, 2, 2, 2, 2);
UIFactory.SetLayoutElement(listHolder, minHeight: 350, flexibleWidth: 9999, flexibleHeight: 9999); UIFactory.SetLayoutElement(listHolder, minHeight: 150, flexibleWidth: 9999, flexibleHeight: 9999);
//var listRect = listHolder.GetComponent<RectTransform>();
//listRect.anchorMin = new Vector2(0, 1);
//listRect.anchorMax = new Vector2(1, 1);
// Left group (Children) // Left group (Children)

View File

@ -155,8 +155,8 @@ namespace UnityExplorer.UI.Inspectors
mousePos.x = 350; mousePos.x = 350;
if (mousePos.x > Screen.width - 350) if (mousePos.x > Screen.width - 350)
mousePos.x = Screen.width - 350; mousePos.x = Screen.width - 350;
if (mousePos.y < mainPanelRect.rect.height) if (mousePos.y < Rect.rect.height)
mousePos.y += mainPanelRect.rect.height + 10; mousePos.y += Rect.rect.height + 10;
else else
mousePos.y -= 10; mousePos.y -= 10;
@ -341,10 +341,10 @@ namespace UnityExplorer.UI.Inspectors
protected internal override void DoSetDefaultPosAndAnchors() protected internal override void DoSetDefaultPosAndAnchors()
{ {
mainPanelRect.anchorMin = Vector2.zero; Rect.anchorMin = Vector2.zero;
mainPanelRect.anchorMax = Vector2.zero; Rect.anchorMax = Vector2.zero;
mainPanelRect.pivot = new Vector2(0.5f, 1); Rect.pivot = new Vector2(0.5f, 1);
mainPanelRect.sizeDelta = new Vector2(700, 150); Rect.sizeDelta = new Vector2(700, 150);
} }
public override void ConstructPanelContent() public override void ConstructPanelContent()

View File

@ -62,10 +62,10 @@ namespace UnityExplorer.UI.Panels
protected internal override void DoSetDefaultPosAndAnchors() protected internal override void DoSetDefaultPosAndAnchors()
{ {
mainPanelRect.localPosition = Vector2.zero; Rect.localPosition = Vector2.zero;
mainPanelRect.pivot = new Vector2(0f, 1f); Rect.pivot = new Vector2(0f, 1f);
mainPanelRect.anchorMin = new Vector2(0.4f, 0.175f); Rect.anchorMin = new Vector2(0.4f, 0.175f);
mainPanelRect.anchorMax = new Vector2(0.85f, 0.925f); Rect.anchorMax = new Vector2(0.85f, 0.925f);
} }
public override void ConstructPanelContent() public override void ConstructPanelContent()

View File

@ -26,8 +26,8 @@ namespace UnityExplorer.UI.Panels
public GameObject ContentHolder; public GameObject ContentHolder;
public RectTransform ContentRect; public RectTransform ContentRect;
public static float CurrentPanelWidth => Instance.mainPanelRect.rect.width; public static float CurrentPanelWidth => Instance.Rect.rect.width;
public static float CurrentPanelHeight => Instance.mainPanelRect.rect.height; public static float CurrentPanelHeight => Instance.Rect.rect.height;
public override void Update() public override void Update()
{ {
@ -38,7 +38,7 @@ namespace UnityExplorer.UI.Panels
{ {
base.OnFinishResize(panel); base.OnFinishResize(panel);
InspectorManager.PanelWidth = this.mainPanelRect.rect.width; InspectorManager.PanelWidth = this.Rect.rect.width;
InspectorManager.OnPanelResized(panel.rect.width); InspectorManager.OnPanelResized(panel.rect.width);
} }
@ -51,10 +51,10 @@ namespace UnityExplorer.UI.Panels
protected internal override void DoSetDefaultPosAndAnchors() protected internal override void DoSetDefaultPosAndAnchors()
{ {
mainPanelRect.localPosition = Vector2.zero; Rect.localPosition = Vector2.zero;
mainPanelRect.pivot = new Vector2(0f, 1f); Rect.pivot = new Vector2(0f, 1f);
mainPanelRect.anchorMin = new Vector2(0.35f, 0.175f); Rect.anchorMin = new Vector2(0.35f, 0.175f);
mainPanelRect.anchorMax = new Vector2(0.8f, 0.925f); Rect.anchorMax = new Vector2(0.8f, 0.925f);
} }
public override void ConstructPanelContent() public override void ConstructPanelContent()

View File

@ -51,7 +51,7 @@ namespace UnityExplorer.UI.Panels
if (active && !DoneScrollPoolInit) if (active && !DoneScrollPoolInit)
{ {
LayoutRebuilder.ForceRebuildLayoutImmediate(this.mainPanelRect); LayoutRebuilder.ForceRebuildLayoutImmediate(this.Rect);
logScrollPool.Initialize(this); logScrollPool.Initialize(this);
DoneScrollPoolInit = true; DoneScrollPoolInit = true;
} }
@ -158,10 +158,10 @@ namespace UnityExplorer.UI.Panels
protected internal override void DoSetDefaultPosAndAnchors() protected internal override void DoSetDefaultPosAndAnchors()
{ {
mainPanelRect.localPosition = Vector2.zero; Rect.localPosition = Vector2.zero;
mainPanelRect.pivot = new Vector2(0f, 1f); Rect.pivot = new Vector2(0f, 1f);
mainPanelRect.anchorMin = new Vector2(0.5f, 0.03f); Rect.anchorMin = new Vector2(0.5f, 0.03f);
mainPanelRect.anchorMax = new Vector2(0.9f, 0.2f); Rect.anchorMax = new Vector2(0.9f, 0.2f);
} }
// UI Construction // UI Construction

View File

@ -99,10 +99,10 @@ namespace UnityExplorer.UI.Panels
protected internal override void DoSetDefaultPosAndAnchors() protected internal override void DoSetDefaultPosAndAnchors()
{ {
mainPanelRect.localPosition = Vector2.zero; Rect.localPosition = Vector2.zero;
mainPanelRect.pivot = new Vector2(0f, 1f); Rect.pivot = new Vector2(0f, 1f);
mainPanelRect.anchorMin = new Vector2(0.125f, 0.175f); Rect.anchorMin = new Vector2(0.125f, 0.175f);
mainPanelRect.anchorMax = new Vector2(0.325f, 0.925f); Rect.anchorMax = new Vector2(0.325f, 0.925f);
//mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 350); //mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 350);
} }

View File

@ -69,11 +69,11 @@ namespace UnityExplorer.UI.Panels
protected internal override void DoSetDefaultPosAndAnchors() protected internal override void DoSetDefaultPosAndAnchors()
{ {
mainPanelRect.localPosition = Vector2.zero; Rect.localPosition = Vector2.zero;
mainPanelRect.pivot = new Vector2(0f, 1f); Rect.pivot = new Vector2(0f, 1f);
mainPanelRect.anchorMin = new Vector2(0.5f, 0.1f); Rect.anchorMin = new Vector2(0.5f, 0.1f);
mainPanelRect.anchorMax = new Vector2(0.5f, 0.85f); Rect.anchorMax = new Vector2(0.5f, 0.85f);
mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 600f); Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 600f);
} }
// UI Construction // UI Construction

View File

@ -250,15 +250,9 @@ namespace UnityExplorer.UI.Panels
Vector2 diff = (Vector2)mousePos - m_lastDragPosition; Vector2 diff = (Vector2)mousePos - m_lastDragPosition;
m_lastDragPosition = mousePos; m_lastDragPosition = mousePos;
var pos = Panel.localPosition + (Vector3)diff; Panel.localPosition = Panel.localPosition + (Vector3)diff;
// Prevent panel going oustide screen bounds UIPanel.EnsureValidPosition(Panel);
var halfW = Screen.width * 0.5f;
var halfH = Screen.height * 0.5f;
pos.x = Math.Max(-halfW, Math.Min(pos.x, halfW - Panel.rect.width));
pos.y = Math.Max(-halfH + Panel.rect.height, Math.Min(pos.y, halfH));
Panel.localPosition = pos;
} }
public void OnEndDrag() public void OnEndDrag()
@ -425,6 +419,9 @@ namespace UnityExplorer.UI.Panels
if ((Vector2)mousePos == m_lastResizePos) if ((Vector2)mousePos == m_lastResizePos)
return; return;
if (mousePos.x < 0 || mousePos.y < 0 || mousePos.x > Screen.width || mousePos.y > Screen.height)
return;
m_lastResizePos = mousePos; m_lastResizePos = mousePos;
float diffX = (float)((decimal)diff.x / Screen.width); float diffX = (float)((decimal)diff.x / Screen.width);

View File

@ -44,8 +44,8 @@ namespace UnityExplorer.UI.Panels
continue; continue;
// check if our mouse is clicking inside the panel // check if our mouse is clicking inside the panel
var pos = panel.mainPanelRect.InverseTransformPoint(mousePos); var pos = panel.Rect.InverseTransformPoint(mousePos);
if (!panel.Enabled || !panel.mainPanelRect.rect.Contains(pos)) if (!panel.Enabled || !panel.Rect.rect.Contains(pos))
continue; continue;
// if this is not the top panel, reorder and invoke the onchanged event // if this is not the top panel, reorder and invoke the onchanged event
@ -88,9 +88,11 @@ namespace UnityExplorer.UI.Panels
public override GameObject UIRoot => uiRoot; public override GameObject UIRoot => uiRoot;
protected GameObject uiRoot; protected GameObject uiRoot;
protected RectTransform mainPanelRect; public RectTransform Rect;
public GameObject content; public GameObject content;
public GameObject titleBar;
public abstract void ConstructPanelContent(); public abstract void ConstructPanelContent();
public virtual void OnFinishResize(RectTransform panel) public virtual void OnFinishResize(RectTransform panel)
@ -136,14 +138,85 @@ namespace UnityExplorer.UI.Panels
public void SetTransformDefaults() public void SetTransformDefaults()
{ {
DoSetDefaultPosAndAnchors(); DoSetDefaultPosAndAnchors();
if (mainPanelRect.rect.width < MinWidth)
mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth);
if (mainPanelRect.rect.height < MinHeight)
mainPanelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
} }
public GameObject titleBar; public void EnsureValidSize()
{
if (Rect.rect.width < MinWidth)
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth);
if (Rect.rect.height < MinHeight)
Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight);
}
public 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;
pos.x = Math.Max(-halfW, Math.Min(pos.x, halfW - panel.rect.width));
pos.y = Math.Max(-halfH + panel.rect.height, Math.Min(pos.y, halfH));
panel.localPosition = pos;
}
#region Save Data
public abstract void DoSaveToConfigElement();
public void SaveToConfigManager()
{
if (UIManager.Initializing)
return;
DoSaveToConfigElement();
}
public abstract string GetSaveDataFromConfigManager();
public bool ApplyingSaveData { get; set; }
public virtual string ToSaveData()
{
try
{
return $"{ShouldSaveActiveState && Enabled}" +
$"|{Rect.RectAnchorsToString()}" +
$"|{Rect.RectPositionToString()}";
}
catch (Exception ex)
{
ExplorerCore.LogWarning($"Exception generating Panel save data: {ex}");
return "";
}
}
public virtual void ApplySaveData(string data)
{
if (string.IsNullOrEmpty(data))
return;
var split = data.Split('|');
try
{
Rect.SetAnchorsFromString(split[1]);
Rect.SetPositionFromString(split[2]);
UIManager.SetPanelActive(this.PanelType, bool.Parse(split[0]));
}
catch
{
ExplorerCore.LogWarning("Invalid or corrupt panel save data! Restoring to default.");
SetTransformDefaults();
}
}
#endregion
// UI Construction
public void ConstructUI() public void ConstructUI()
{ {
@ -168,7 +241,7 @@ namespace UnityExplorer.UI.Panels
// create core canvas // create core canvas
uiRoot = UIFactory.CreatePanel(Name, out GameObject panelContent); uiRoot = UIFactory.CreatePanel(Name, out GameObject panelContent);
mainPanelRect = this.uiRoot.GetComponent<RectTransform>(); Rect = this.uiRoot.GetComponent<RectTransform>();
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.uiRoot, false, false, true, true, 0, 2, 2, 2, 2, TextAnchor.UpperLeft); UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.uiRoot, false, false, true, true, 0, 2, 2, 2, 2, TextAnchor.UpperLeft);
int id = this.uiRoot.transform.GetInstanceID(); int id = this.uiRoot.transform.GetInstanceID();
@ -177,9 +250,6 @@ namespace UnityExplorer.UI.Panels
content = panelContent; content = panelContent;
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.content, false, false, true, true, 2, 2, 2, 2, 2, TextAnchor.UpperLeft); UIFactory.SetLayoutGroup<VerticalLayoutGroup>(this.content, false, false, true, true, 2, 2, 2, 2, 2, TextAnchor.UpperLeft);
// always apply default pos and anchors (save data may only be partial)
SetTransformDefaults();
// Title bar // Title bar
titleBar = UIFactory.CreateHorizontalGroup(content, "TitleBar", false, true, true, true, 2, titleBar = UIFactory.CreateHorizontalGroup(content, "TitleBar", false, true, true, true, 2,
new Vector4(2, 2, 2, 2), new Color(0.06f, 0.06f, 0.06f)); new Vector4(2, 2, 2, 2), new Color(0.06f, 0.06f, 0.06f));
@ -210,7 +280,7 @@ namespace UnityExplorer.UI.Panels
// Panel dragger // Panel dragger
Dragger = new PanelDragger(titleBar.GetComponent<RectTransform>(), mainPanelRect, this); Dragger = new PanelDragger(titleBar.GetComponent<RectTransform>(), Rect, this);
Dragger.OnFinishResize += OnFinishResize; Dragger.OnFinishResize += OnFinishResize;
Dragger.OnFinishDrag += OnFinishDrag; Dragger.OnFinishDrag += OnFinishDrag;
@ -223,6 +293,7 @@ namespace UnityExplorer.UI.Panels
UIManager.SetPanelActive(this.PanelType, ShowByDefault); UIManager.SetPanelActive(this.PanelType, ShowByDefault);
ApplyingSaveData = true; ApplyingSaveData = true;
SetTransformDefaults();
// apply panel save data or revert to default // apply panel save data or revert to default
try try
{ {
@ -234,6 +305,13 @@ namespace UnityExplorer.UI.Panels
SetTransformDefaults(); SetTransformDefaults();
} }
LayoutRebuilder.ForceRebuildLayoutImmediate(this.Rect);
// ensure initialized position is valid
EnsureValidSize();
EnsureValidPosition(this.Rect);
// update dragger and save data
Dragger.OnEndResize(); Dragger.OnEndResize();
// simple listener for saving enabled state // simple listener for saving enabled state
@ -241,61 +319,11 @@ namespace UnityExplorer.UI.Panels
{ {
SaveToConfigManager(); SaveToConfigManager();
}; };
ApplyingSaveData = false; ApplyingSaveData = false;
} }
public override void ConstructUI(GameObject parent) => ConstructUI(); public override void ConstructUI(GameObject parent) => ConstructUI();
// SAVE DATA
public abstract void DoSaveToConfigElement();
public void SaveToConfigManager()
{
if (UIManager.Initializing)
return;
DoSaveToConfigElement();
}
public abstract string GetSaveDataFromConfigManager();
public bool ApplyingSaveData { get; set; }
public virtual string ToSaveData()
{
try
{
return $"{ShouldSaveActiveState && Enabled}" +
$"|{mainPanelRect.RectAnchorsToString()}" +
$"|{mainPanelRect.RectPositionToString()}";
}
catch (Exception ex)
{
ExplorerCore.LogWarning($"Exception generating Panel save data: {ex}");
return "";
}
}
public virtual void ApplySaveData(string data)
{
if (string.IsNullOrEmpty(data))
return;
var split = data.Split('|');
try
{
mainPanelRect.SetAnchorsFromString(split[1]);
mainPanelRect.SetPositionFromString(split[2]);
UIManager.SetPanelActive(this.PanelType, bool.Parse(split[0]));
}
catch
{
ExplorerCore.LogWarning("Invalid or corrupt panel save data! Restoring to default.");
SetTransformDefaults();
}
}
} }
#region WINDOW ANCHORS / POSITION HELPERS #region WINDOW ANCHORS / POSITION HELPERS

View File

@ -123,6 +123,9 @@ namespace UnityExplorer.UI
// Main UI Update loop // Main UI Update loop
private static int lastScreenWidth;
private static int lastScreenHeight;
public static void Update() public static void Update()
{ {
if (!CanvasRoot || Initializing) if (!CanvasRoot || Initializing)
@ -150,6 +153,19 @@ namespace UnityExplorer.UI
PanelDragger.UpdateInstances(); PanelDragger.UpdateInstances();
InputFieldRef.UpdateInstances(); InputFieldRef.UpdateInstances();
UIBehaviourModel.UpdateInstances(); UIBehaviourModel.UpdateInstances();
if (Screen.width != lastScreenWidth || Screen.height != lastScreenHeight)
{
lastScreenWidth = Screen.width;
lastScreenHeight = Screen.height;
foreach (var panel in UIPanels)
{
panel.Value.EnsureValidSize();
UIPanel.EnsureValidPosition(panel.Value.Rect);
panel.Value.Dragger.OnEndResize();
}
}
} }
// Initialization and UI Construction // Initialization and UI Construction
@ -184,6 +200,9 @@ namespace UnityExplorer.UI
ShowMenu = !ConfigManager.Hide_On_Startup.Value; ShowMenu = !ConfigManager.Hide_On_Startup.Value;
lastScreenWidth = Screen.width;
lastScreenHeight = Screen.height;
Initializing = false; Initializing = false;
} }

View File

@ -292,9 +292,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
protected internal override void DoSetDefaultPosAndAnchors() protected internal override void DoSetDefaultPosAndAnchors()
{ {
mainPanelRect.pivot = new Vector2(0f, 1f); Rect.pivot = new Vector2(0f, 1f);
mainPanelRect.anchorMin = new Vector2(0.42f, 0.4f); Rect.anchorMin = new Vector2(0.42f, 0.4f);
mainPanelRect.anchorMax = new Vector2(0.68f, 0.6f); Rect.anchorMax = new Vector2(0.68f, 0.6f);
} }
public override void ConstructPanelContent() public override void ConstructPanelContent()