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

Commit 835a817

Browse files
committed
Add support for Hashset, add try/catch for loading settings
1 parent 51ed936 commit 835a817

File tree

10 files changed

+109
-45
lines changed

10 files changed

+109
-45
lines changed

src/CachedObjects/CacheObjectBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ private static CacheObjectBase GetCacheObjectImpl(object obj, MemberInfo memberI
172172
{
173173
holder = new CacheDictionary();
174174
}
175-
else if (ReflectionHelpers.IsEnumerable(valueType) || ReflectionHelpers.IsCppList(valueType))
175+
else if (ReflectionHelpers.IsEnumerable(valueType) || ReflectionHelpers.IsCppEnumerable(valueType))
176176
{
177177
holder = new CacheList();
178178
}

src/CachedObjects/Object/CacheDictionary.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ public override void DrawValue(Rect window, float width)
228228
var negativeWhitespace = window.width - (whitespace + 100f);
229229

230230
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
231-
string btnLabel = $"<color=#2df7b2>[{count}] Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
231+
string btnLabel = $"[{count}] <color=#2df7b2>Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
232232
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.Width(negativeWhitespace) }))
233233
{
234234
WindowManager.InspectObject(Value, out bool _);

src/CachedObjects/Object/CacheList.cs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public Type GenericTypeDef
4040
private Type m_genericTypeDef;
4141

4242
// Cached ToArray method for Lists
43-
public MethodInfo GenericToArrayMethod
43+
public MethodInfo CppListToArrayMethod
4444
{
4545
get => GetGenericToArrayMethod();
4646
}
@@ -60,7 +60,7 @@ private IEnumerable GetEnumerable()
6060
{
6161
if (m_enumerable == null && Value != null)
6262
{
63-
m_enumerable = Value as IEnumerable ?? GetEnumerableFromIl2CppList();
63+
m_enumerable = Value as IEnumerable ?? EnumerateWithReflection();
6464
}
6565
return m_enumerable;
6666
}
@@ -100,21 +100,45 @@ private PropertyInfo GetItemProperty()
100100
return m_itemProperty;
101101
}
102102

103-
private IEnumerable GetEnumerableFromIl2CppList()
103+
private IEnumerable EnumerateWithReflection()
104104
{
105105
if (Value == null) return null;
106106

107107
if (GenericTypeDef == typeof(Il2CppSystem.Collections.Generic.List<>))
108108
{
109-
return (IEnumerable)GenericToArrayMethod?.Invoke(Value, new object[0]);
109+
return (IEnumerable)CppListToArrayMethod?.Invoke(Value, new object[0]);
110+
}
111+
else if (GenericTypeDef == typeof(Il2CppSystem.Collections.Generic.HashSet<>))
112+
{
113+
return CppHashSetToMono();
110114
}
111115
else
112116
{
113-
return ConvertIListToMono();
117+
return CppIListToMono();
118+
}
119+
}
120+
121+
private IEnumerable CppHashSetToMono()
122+
{
123+
var set = new HashSet<object>();
124+
125+
// invoke GetEnumerator
126+
var enumerator = Value.GetType().GetMethod("GetEnumerator").Invoke(Value, null);
127+
// get the type of it
128+
var enumeratorType = enumerator.GetType();
129+
// reflect MoveNext and Current
130+
var moveNext = enumeratorType.GetMethod("MoveNext");
131+
var current = enumeratorType.GetProperty("Current");
132+
// iterate
133+
while ((bool)moveNext.Invoke(enumerator, null))
134+
{
135+
set.Add(current.GetValue(enumerator));
114136
}
137+
138+
return set;
115139
}
116140

117-
private IList ConvertIListToMono()
141+
private IList CppIListToMono()
118142
{
119143
try
120144
{

src/CachedObjects/Struct/CacheColor.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ public override void DrawValue(Rect window, float width)
4949
}
5050
}
5151

52-
var c = (Color)Value;
53-
GUI.color = c;
54-
GUILayout.Label($"<color=#2df7b2>Color:</color> {c.ToString()}", null);
55-
GUI.color = Color.white;
52+
//var c = (Color)Value;
53+
//GUI.color = c;
54+
GUILayout.Label($"<color=#2df7b2>Color:</color> {((Color)Value).ToString()}", null);
55+
//GUI.color = Color.white;
5656

5757
if (CanWrite && IsExpanded)
5858
{

src/Config/ModConfig.cs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,35 +28,42 @@ public static void OnLoad()
2828
Directory.CreateDirectory(EXPLORER_FOLDER);
2929
}
3030

31-
if (File.Exists(SETTINGS_PATH))
32-
{
33-
LoadSettings(false);
34-
}
35-
else
36-
{
37-
Instance = new ModConfig();
38-
SaveSettings(false);
39-
}
31+
if (LoadSettings()) return;
32+
33+
Instance = new ModConfig();
34+
SaveSettings();
4035
}
4136

42-
public static void LoadSettings(bool checkExist = true)
37+
// returns true if settings successfully loaded
38+
public static bool LoadSettings(bool checkExist = true)
4339
{
4440
if (checkExist && !File.Exists(SETTINGS_PATH))
45-
return;
41+
return false;
42+
43+
try
44+
{
45+
using (var file = File.OpenRead(SETTINGS_PATH))
46+
{
47+
Instance = (ModConfig)Serializer.Deserialize(file);
48+
}
49+
}
50+
catch
51+
{
52+
return false;
53+
}
4654

47-
var file = File.OpenRead(SETTINGS_PATH);
48-
Instance = (ModConfig)Serializer.Deserialize(file);
49-
file.Close();
55+
return Instance != null;
5056
}
5157

5258
public static void SaveSettings(bool checkExist = true)
5359
{
5460
if (checkExist && File.Exists(SETTINGS_PATH))
5561
File.Delete(SETTINGS_PATH);
5662

57-
FileStream file = File.Create(SETTINGS_PATH);
58-
Serializer.Serialize(file, Instance);
59-
file.Close();
63+
using (var file = File.Create(SETTINGS_PATH))
64+
{
65+
Serializer.Serialize(file, Instance);
66+
}
6067
}
6168
}
6269
}

src/CppExplorer.csproj

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.0" encoding="utf-8"?>
1+
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
44
<PropertyGroup>
@@ -29,6 +29,10 @@
2929
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Il2Cppmscorlib.dll</HintPath>
3030
<Private>False</Private>
3131
</Reference>
32+
<Reference Include="Il2CppSystem.Core">
33+
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Il2CppSystem.Core.dll</HintPath>
34+
<Private>False</Private>
35+
</Reference>
3236
<Reference Include="mcs">
3337
<HintPath>..\lib\mcs.dll</HintPath>
3438
<Private>True</Private>
@@ -118,4 +122,4 @@
118122
<Compile Include="Properties\AssemblyInfo.cs" />
119123
</ItemGroup>
120124
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
121-
</Project>
125+
</Project>

src/Helpers/ReflectionHelpers.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@ public static bool IsEnumerable(Type t)
3737
return typeof(IEnumerable).IsAssignableFrom(t);
3838
}
3939

40-
// Only Il2Cpp List needs this check. C# List is IEnumerable.
41-
public static bool IsCppList(Type t)
40+
// Checks for Il2Cpp List or HashSet.
41+
public static bool IsCppEnumerable(Type t)
4242
{
4343
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
4444
{
4545
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
46-
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g);
46+
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
47+
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
4748
}
4849
else
4950
{
@@ -89,18 +90,20 @@ public static Type GetActualType(object obj)
8990
{
9091
if (obj == null) return null;
9192

93+
// Need to use GetIl2CppType for Il2CppSystem Objects
9294
if (obj is Il2CppSystem.Object ilObject)
9395
{
94-
var ilTypeName = ilObject.GetIl2CppType().AssemblyQualifiedName;
95-
96-
if (Type.GetType(ilTypeName) is Type t && !t.FullName.Contains("System.RuntimeType"))
96+
// Prevent weird behaviour when inspecting an Il2CppSystem.Type object.
97+
if (ilObject is ILType)
9798
{
98-
return t;
99+
return typeof(ILType);
99100
}
100101

101-
return ilObject.GetType();
102+
// Get the System.Type using the qualified name, or fallback to GetType.
103+
return Type.GetType(ilObject.GetIl2CppType().AssemblyQualifiedName) ?? obj.GetType();
102104
}
103105

106+
// It's a normal object, this is fine
104107
return obj.GetType();
105108
}
106109

@@ -109,12 +112,11 @@ public static Type[] GetAllBaseTypes(object obj)
109112
var list = new List<Type>();
110113

111114
var type = GetActualType(obj);
112-
list.Add(type);
113115

114-
while (type.BaseType != null)
116+
while (type != null)
115117
{
116-
type = type.BaseType;
117118
list.Add(type);
119+
type = type.BaseType;
118120
}
119121

120122
return list.ToArray();

src/MainMenu/Pages/SearchPage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ public static IEnumerable<object> GetInstanceClassScanner()
428428
{
429429
var t = ReflectionHelpers.GetActualType(obj);
430430

431-
if (!FilterName(t.FullName) || ReflectionHelpers.IsEnumerable(t) || ReflectionHelpers.IsCppList(t))
431+
if (!FilterName(t.FullName) || ReflectionHelpers.IsEnumerable(t) || ReflectionHelpers.IsCppEnumerable(t))
432432
{
433433
continue;
434434
}

src/Tests/TestClass.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,25 @@ public class TestClass
1414
public static TestClass Instance => m_instance ?? (m_instance = new TestClass());
1515
private static TestClass m_instance;
1616

17+
public TestClass()
18+
{
19+
ILHashSetTest = new Il2CppSystem.Collections.Generic.HashSet<string>();
20+
ILHashSetTest.Add("1");
21+
ILHashSetTest.Add("2");
22+
ILHashSetTest.Add("3");
23+
}
24+
25+
// test HashSets
26+
27+
public static HashSet<string> HashSetTest = new HashSet<string>
28+
{
29+
"One",
30+
"Two",
31+
"Three"
32+
};
33+
34+
public static Il2CppSystem.Collections.Generic.HashSet<string> ILHashSetTest;
35+
1736
// Test indexed parameter
1837

1938
public string this[int arg0, string arg1]

src/Windows/ReflectionWindow.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,14 @@ public class ReflectionWindow : UIWindow
3232
private UnityEngine.Object m_uObj;
3333
private Component m_component;
3434

35-
private static readonly HashSet<string> _memberBlacklist = new HashSet<string>
35+
private static readonly HashSet<string> _typeAndMemberBlacklist = new HashSet<string>
3636
{
3737
// Causes a crash
3838
"Type.DeclaringMethod",
39+
};
40+
41+
private static readonly HashSet<string> _methodStartsWithBlacklist = new HashSet<string>
42+
{
3943
// Pointless (handled by Properties)
4044
"get_",
4145
"set_"
@@ -157,7 +161,11 @@ private void CacheMembers(Type[] types)
157161
continue;
158162

159163
// check blacklisted members
160-
if (_memberBlacklist.Any(it => member.Name.StartsWith(it)))
164+
var name = member.DeclaringType.Name + "." + member.Name;
165+
if (_typeAndMemberBlacklist.Any(it => it == name))
166+
continue;
167+
168+
if (_methodStartsWithBlacklist.Any(it => member.Name.StartsWith(it)))
161169
continue;
162170

163171
// compare signature to already cached members

0 commit comments

Comments
 (0)