Skip to content
This repository was archived by the owner on May 9, 2023. It is now read-only.

Commit 6970dcb

Browse files
authored
Merge pull request #68 from sinai-dev/4.0.0-alpha
4.0 hotfixes
2 parents e4615af + ac9c2d5 commit 6970dcb

17 files changed

+278
-133
lines changed

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
| 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) |
2121

2222
### Known issues
23-
* 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.
2423
* Any `MissingMethodException` or `NotSupportedException`: please report the issue and provide a copy of your mod loader log and/or Unity log.
2524
* 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.
2625
* 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:
9594

9695
## Building
9796

98-
Building the project should be straight-forward, the references are all inside the `lib\` folder.
99-
97+
0. Clone the repository and run `git submodule update --init --recursive` to get the submodules.
10098
1. Open the `src\UnityExplorer.sln` project in Visual Studio.
10199
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.
102100
3. The DLLs are built to the `Release\` folder in the root of the repository.

src/Core/Reflection/Extensions.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,27 @@ public static HashSet<Type> GetImplementationsOf(this Type baseType, bool allowA
3636

3737
// ------- Misc extensions --------
3838

39+
/// <summary>
40+
/// Recursively check the type and its base types to find any generic arguments.
41+
/// </summary>
42+
public static bool TryGetGenericArguments(this Type type, out Type[] args)
43+
{
44+
if (type.IsGenericType)
45+
{
46+
args = type.GetGenericArguments();
47+
return true;
48+
}
49+
else if (type.BaseType != null)
50+
{
51+
return TryGetGenericArguments(type.BaseType, out args);
52+
}
53+
else
54+
{
55+
args = null;
56+
return false;
57+
}
58+
}
59+
3960
/// <summary>
4061
/// Safely try to get all Types inside an Assembly.
4162
/// </summary>

src/Core/Tests/TestClass.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,40 @@
1414

1515
namespace UnityExplorer.Tests
1616
{
17+
public class TestIndexer : IList<int>
18+
{
19+
private readonly List<int> list = new List<int>() { 1,2,3,4,5 };
20+
21+
public int Count => list.Count;
22+
public bool IsReadOnly => false;
23+
24+
int IList<int>.this[int index]
25+
{
26+
get => list[index];
27+
set => list[index] = value;
28+
}
29+
30+
public int IndexOf(int item) => list.IndexOf(item);
31+
public bool Contains(int item) => list.Contains(item);
32+
33+
public void Add(int item) => list.Add(item);
34+
public void Insert(int index, int item) => list.Insert(index, item);
35+
36+
public bool Remove(int item) => list.Remove(item);
37+
public void RemoveAt(int index) => list.RemoveAt(index);
38+
39+
public void Clear() => list.Clear();
40+
41+
public void CopyTo(int[] array, int arrayIndex) => list.CopyTo(array, arrayIndex);
42+
43+
public IEnumerator<int> GetEnumerator() => list.GetEnumerator();
44+
IEnumerator IEnumerable.GetEnumerator() => list.GetEnumerator();
45+
}
46+
1747
public static class TestClass
1848
{
49+
public static readonly TestIndexer AAAAATest = new TestIndexer();
50+
1951
public static void ATestMethod(string s, float f, Vector3 vector, DateTime date, Quaternion quater, bool b, CameraClearFlags enumvalue)
2052
{
2153
ExplorerCore.Log($"{s}, {f}, {vector.ToString()}, {date}, {quater.eulerAngles.ToString()}, {b}, {enumvalue}");

src/ExplorerCore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace UnityExplorer
1919
public static class ExplorerCore
2020
{
2121
public const string NAME = "UnityExplorer";
22-
public const string VERSION = "4.0.0";
22+
public const string VERSION = "4.0.1";
2323
public const string AUTHOR = "Sinai";
2424
public const string GUID = "com.sinai.unityexplorer";
2525

src/UI/IValues/InteractiveDictionary.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,11 @@ public override void SetValue(object value)
7575
else
7676
{
7777
var type = value.GetActualType();
78-
if (type.IsGenericType && type.GetGenericArguments().Length == 2)
79-
{
80-
KeyType = type.GetGenericArguments()[0];
81-
ValueType = type.GetGenericArguments()[1];
78+
79+
if (type.TryGetGenericArguments(out var args) && args.Length == 2)
80+
{
81+
KeyType = args[0];
82+
ValueType = args[1];
8283
}
8384
else
8485
{

src/UI/IValues/InteractiveList.cs

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections;
33
using System.Collections.Generic;
44
using System.Linq;
5+
using System.Reflection;
56
using UnityEngine;
67
using UnityEngine.UI;
78
using UnityExplorer.UI.CacheObject;
@@ -19,13 +20,15 @@ public class InteractiveList : InteractiveValue, ICellPoolDataSource<CacheListEn
1920
object ICacheObjectController.Target => this.CurrentOwner.Value;
2021
public Type TargetType { get; private set; }
2122

22-
public override bool CanWrite => base.CanWrite && RefIList != null && !RefIList.IsReadOnly;
23+
public override bool CanWrite => base.CanWrite && ((RefIList != null && !RefIList.IsReadOnly) || IsWritableGenericIList);
2324

2425
public Type EntryType;
2526
public IList RefIList;
2627

27-
public int ItemCount => values.Count;
28-
private readonly List<object> values = new List<object>();
28+
private bool IsWritableGenericIList;
29+
private PropertyInfo genericIndexer;
30+
31+
public int ItemCount => cachedEntries.Count;
2932
private readonly List<CacheListEntry> cachedEntries = new List<CacheListEntry>();
3033

3134
public ScrollPool<CacheListEntryCell> ListScrollPool { get; private set; }
@@ -49,7 +52,6 @@ public override void ReleaseFromOwner()
4952
private void ClearAndRelease()
5053
{
5154
RefIList = null;
52-
values.Clear();
5355

5456
foreach (var entry in cachedEntries)
5557
{
@@ -66,14 +68,14 @@ public override void SetValue(object value)
6668
if (value == null)
6769
{
6870
// should never be null
69-
if (values.Any())
71+
if (cachedEntries.Any())
7072
ClearAndRelease();
7173
}
7274
else
7375
{
7476
var type = value.GetActualType();
75-
if (type.IsGenericType)
76-
EntryType = type.GetGenericArguments()[0];
77+
if (type.TryGetGenericArguments(out var args))
78+
EntryType = args[0];
7779
else if (type.HasElementType)
7880
EntryType = type.GetElementType();
7981
else
@@ -92,7 +94,12 @@ private void CacheEntries(object value)
9294
{
9395
RefIList = value as IList;
9496

95-
values.Clear();
97+
// Check if the type implements IList<T> but not IList (ie. Il2CppArrayBase)
98+
if (RefIList == null)
99+
CheckGenericIList(value);
100+
else
101+
IsWritableGenericIList = false;
102+
96103
int idx = 0;
97104

98105
if (ReflectionUtility.TryGetEnumerator(value, out IEnumerator enumerator))
@@ -103,8 +110,6 @@ private void CacheEntries(object value)
103110
{
104111
var entry = enumerator.Current;
105112

106-
values.Add(entry);
107-
108113
// If list count increased, create new cache entries
109114
CacheListEntry cache;
110115
if (idx >= cachedEntries.Count)
@@ -122,9 +127,9 @@ private void CacheEntries(object value)
122127
}
123128

124129
// Remove excess cached entries if list count decreased
125-
if (cachedEntries.Count > values.Count)
130+
if (cachedEntries.Count > idx)
126131
{
127-
for (int i = cachedEntries.Count - 1; i >= values.Count; i--)
132+
for (int i = cachedEntries.Count - 1; i >= idx; i--)
128133
{
129134
var cache = cachedEntries[i];
130135
if (cache.CellView != null)
@@ -141,14 +146,61 @@ private void CacheEntries(object value)
141146
}
142147
}
143148

149+
private void CheckGenericIList(object value)
150+
{
151+
try
152+
{
153+
var type = value.GetType();
154+
if (type.GetInterfaces().Any(it => it.IsGenericType && it.GetGenericTypeDefinition() == typeof(IList<>)))
155+
IsWritableGenericIList = !(bool)type.GetProperty("IsReadOnly").GetValue(value, null);
156+
else
157+
IsWritableGenericIList = false;
158+
159+
if (IsWritableGenericIList)
160+
{
161+
// Find the "this[int index]" property.
162+
// It might be a private implementation.
163+
foreach (var prop in type.GetProperties(ReflectionUtility.FLAGS))
164+
{
165+
if ((prop.Name == "Item"
166+
|| (prop.Name.StartsWith("System.Collections.Generic.IList<") && prop.Name.EndsWith(">.Item")))
167+
&& prop.GetIndexParameters() is ParameterInfo[] parameters
168+
&& parameters.Length == 1
169+
&& parameters[0].ParameterType == typeof(int))
170+
{
171+
genericIndexer = prop;
172+
break;
173+
}
174+
}
175+
176+
if (genericIndexer == null)
177+
{
178+
ExplorerCore.LogWarning($"Failed to find indexer property for IList<T> type '{type.FullName}'!");
179+
IsWritableGenericIList = false;
180+
}
181+
}
182+
}
183+
catch (Exception ex)
184+
{
185+
ExplorerCore.LogWarning($"Exception processing IEnumerable for IList<T> check: {ex.ReflectionExToString()}");
186+
IsWritableGenericIList = false;
187+
}
188+
}
189+
144190
// Setting the value of an index to the list
145191

146192
public void TrySetValueToIndex(object value, int index)
147193
{
148194
try
149195
{
150-
//value = value.TryCast(this.EntryType);
151-
RefIList[index] = value;
196+
if (!IsWritableGenericIList)
197+
{
198+
RefIList[index] = value;
199+
}
200+
else
201+
{
202+
genericIndexer.SetValue(CurrentOwner.Value, value, new object[] { index });
203+
}
152204

153205
var entry = cachedEntries[index];
154206
entry.SetValueFromSource(value);

src/UI/Inspectors/GameObjectInspector.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public override GameObject CreateContent(GameObject parent)
226226

227227
var scrollObj = UIFactory.CreateScrollView(UIRoot, "GameObjectInspector", out Content, out var scrollbar,
228228
new Color(0.065f, 0.065f, 0.065f));
229-
UIFactory.SetLayoutElement(scrollObj, minHeight: 300, flexibleWidth: 9999, flexibleHeight: 1);
229+
UIFactory.SetLayoutElement(scrollObj, minHeight: 250, preferredHeight: 300, flexibleHeight: 0, flexibleWidth: 9999);
230230

231231
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2);
232232

@@ -244,10 +244,7 @@ private void ConstructLists()
244244
{
245245
var listHolder = UIFactory.CreateUIObject("ListHolders", UIRoot);
246246
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(listHolder, false, true, true, true, 8, 2, 2, 2, 2);
247-
UIFactory.SetLayoutElement(listHolder, minHeight: 350, flexibleWidth: 9999, flexibleHeight: 9999);
248-
//var listRect = listHolder.GetComponent<RectTransform>();
249-
//listRect.anchorMin = new Vector2(0, 1);
250-
//listRect.anchorMax = new Vector2(1, 1);
247+
UIFactory.SetLayoutElement(listHolder, minHeight: 150, flexibleWidth: 9999, flexibleHeight: 9999);
251248

252249
// Left group (Children)
253250

src/UI/Inspectors/InspectUnderMouse.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ internal void UpdatePosition(Vector2 mousePos)
155155
mousePos.x = 350;
156156
if (mousePos.x > Screen.width - 350)
157157
mousePos.x = Screen.width - 350;
158-
if (mousePos.y < mainPanelRect.rect.height)
159-
mousePos.y += mainPanelRect.rect.height + 10;
158+
if (mousePos.y < Rect.rect.height)
159+
mousePos.y += Rect.rect.height + 10;
160160
else
161161
mousePos.y -= 10;
162162

@@ -341,10 +341,10 @@ private static void StopUIInspect()
341341

342342
protected internal override void DoSetDefaultPosAndAnchors()
343343
{
344-
mainPanelRect.anchorMin = Vector2.zero;
345-
mainPanelRect.anchorMax = Vector2.zero;
346-
mainPanelRect.pivot = new Vector2(0.5f, 1);
347-
mainPanelRect.sizeDelta = new Vector2(700, 150);
344+
Rect.anchorMin = Vector2.zero;
345+
Rect.anchorMax = Vector2.zero;
346+
Rect.pivot = new Vector2(0.5f, 1);
347+
Rect.sizeDelta = new Vector2(700, 150);
348348
}
349349

350350
public override void ConstructPanelContent()

src/UI/Panels/CSConsolePanel.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ public override void DoSaveToConfigElement()
6262

6363
protected internal override void DoSetDefaultPosAndAnchors()
6464
{
65-
mainPanelRect.localPosition = Vector2.zero;
66-
mainPanelRect.pivot = new Vector2(0f, 1f);
67-
mainPanelRect.anchorMin = new Vector2(0.4f, 0.175f);
68-
mainPanelRect.anchorMax = new Vector2(0.85f, 0.925f);
65+
Rect.localPosition = Vector2.zero;
66+
Rect.pivot = new Vector2(0f, 1f);
67+
Rect.anchorMin = new Vector2(0.4f, 0.175f);
68+
Rect.anchorMax = new Vector2(0.85f, 0.925f);
6969
}
7070

7171
public override void ConstructPanelContent()

src/UI/Panels/InspectorPanel.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ public class InspectorPanel : UIPanel
2626
public GameObject ContentHolder;
2727
public RectTransform ContentRect;
2828

29-
public static float CurrentPanelWidth => Instance.mainPanelRect.rect.width;
30-
public static float CurrentPanelHeight => Instance.mainPanelRect.rect.height;
29+
public static float CurrentPanelWidth => Instance.Rect.rect.width;
30+
public static float CurrentPanelHeight => Instance.Rect.rect.height;
3131

3232
public override void Update()
3333
{
@@ -38,7 +38,7 @@ public override void OnFinishResize(RectTransform panel)
3838
{
3939
base.OnFinishResize(panel);
4040

41-
InspectorManager.PanelWidth = this.mainPanelRect.rect.width;
41+
InspectorManager.PanelWidth = this.Rect.rect.width;
4242
InspectorManager.OnPanelResized(panel.rect.width);
4343
}
4444

@@ -51,10 +51,10 @@ public override void DoSaveToConfigElement()
5151

5252
protected internal override void DoSetDefaultPosAndAnchors()
5353
{
54-
mainPanelRect.localPosition = Vector2.zero;
55-
mainPanelRect.pivot = new Vector2(0f, 1f);
56-
mainPanelRect.anchorMin = new Vector2(0.35f, 0.175f);
57-
mainPanelRect.anchorMax = new Vector2(0.8f, 0.925f);
54+
Rect.localPosition = Vector2.zero;
55+
Rect.pivot = new Vector2(0f, 1f);
56+
Rect.anchorMin = new Vector2(0.35f, 0.175f);
57+
Rect.anchorMax = new Vector2(0.8f, 0.925f);
5858
}
5959

6060
public override void ConstructPanelContent()

0 commit comments

Comments
 (0)