Add support for Hashset, add try/catch for loading settings

This commit is contained in:
sinaioutlander 2020-09-11 00:17:13 +10:00
parent 51ed936e30
commit 835a81765e
10 changed files with 109 additions and 45 deletions

View File

@ -172,7 +172,7 @@ namespace Explorer
{
holder = new CacheDictionary();
}
else if (ReflectionHelpers.IsEnumerable(valueType) || ReflectionHelpers.IsCppList(valueType))
else if (ReflectionHelpers.IsEnumerable(valueType) || ReflectionHelpers.IsCppEnumerable(valueType))
{
holder = new CacheList();
}

View File

@ -228,7 +228,7 @@ namespace Explorer
var negativeWhitespace = window.width - (whitespace + 100f);
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
string btnLabel = $"<color=#2df7b2>[{count}] Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
string btnLabel = $"[{count}] <color=#2df7b2>Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.Width(negativeWhitespace) }))
{
WindowManager.InspectObject(Value, out bool _);

View File

@ -40,7 +40,7 @@ namespace Explorer
private Type m_genericTypeDef;
// Cached ToArray method for Lists
public MethodInfo GenericToArrayMethod
public MethodInfo CppListToArrayMethod
{
get => GetGenericToArrayMethod();
}
@ -60,7 +60,7 @@ namespace Explorer
{
if (m_enumerable == null && Value != null)
{
m_enumerable = Value as IEnumerable ?? GetEnumerableFromIl2CppList();
m_enumerable = Value as IEnumerable ?? EnumerateWithReflection();
}
return m_enumerable;
}
@ -100,21 +100,45 @@ namespace Explorer
return m_itemProperty;
}
private IEnumerable GetEnumerableFromIl2CppList()
private IEnumerable EnumerateWithReflection()
{
if (Value == null) return null;
if (GenericTypeDef == typeof(Il2CppSystem.Collections.Generic.List<>))
{
return (IEnumerable)GenericToArrayMethod?.Invoke(Value, new object[0]);
return (IEnumerable)CppListToArrayMethod?.Invoke(Value, new object[0]);
}
else if (GenericTypeDef == typeof(Il2CppSystem.Collections.Generic.HashSet<>))
{
return CppHashSetToMono();
}
else
{
return ConvertIListToMono();
return CppIListToMono();
}
}
private IList ConvertIListToMono()
private IEnumerable CppHashSetToMono()
{
var set = new HashSet<object>();
// invoke GetEnumerator
var enumerator = Value.GetType().GetMethod("GetEnumerator").Invoke(Value, null);
// get the type of it
var enumeratorType = enumerator.GetType();
// reflect MoveNext and Current
var moveNext = enumeratorType.GetMethod("MoveNext");
var current = enumeratorType.GetProperty("Current");
// iterate
while ((bool)moveNext.Invoke(enumerator, null))
{
set.Add(current.GetValue(enumerator));
}
return set;
}
private IList CppIListToMono()
{
try
{

View File

@ -49,10 +49,10 @@ namespace Explorer
}
}
var c = (Color)Value;
GUI.color = c;
GUILayout.Label($"<color=#2df7b2>Color:</color> {c.ToString()}", null);
GUI.color = Color.white;
//var c = (Color)Value;
//GUI.color = c;
GUILayout.Label($"<color=#2df7b2>Color:</color> {((Color)Value).ToString()}", null);
//GUI.color = Color.white;
if (CanWrite && IsExpanded)
{

View File

@ -28,25 +28,31 @@ namespace Explorer
Directory.CreateDirectory(EXPLORER_FOLDER);
}
if (File.Exists(SETTINGS_PATH))
{
LoadSettings(false);
}
else
{
Instance = new ModConfig();
SaveSettings(false);
}
if (LoadSettings()) return;
Instance = new ModConfig();
SaveSettings();
}
public static void LoadSettings(bool checkExist = true)
// returns true if settings successfully loaded
public static bool LoadSettings(bool checkExist = true)
{
if (checkExist && !File.Exists(SETTINGS_PATH))
return;
return false;
var file = File.OpenRead(SETTINGS_PATH);
Instance = (ModConfig)Serializer.Deserialize(file);
file.Close();
try
{
using (var file = File.OpenRead(SETTINGS_PATH))
{
Instance = (ModConfig)Serializer.Deserialize(file);
}
}
catch
{
return false;
}
return Instance != null;
}
public static void SaveSettings(bool checkExist = true)
@ -54,9 +60,10 @@ namespace Explorer
if (checkExist && File.Exists(SETTINGS_PATH))
File.Delete(SETTINGS_PATH);
FileStream file = File.Create(SETTINGS_PATH);
Serializer.Serialize(file, Instance);
file.Close();
using (var file = File.Create(SETTINGS_PATH))
{
Serializer.Serialize(file, Instance);
}
}
}
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@ -29,6 +29,10 @@
<HintPath>..\..\..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Il2Cppmscorlib.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Il2CppSystem.Core">
<HintPath>..\..\..\Steam\steamapps\common\Hellpoint\MelonLoader\Managed\Il2CppSystem.Core.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="mcs">
<HintPath>..\lib\mcs.dll</HintPath>
<Private>True</Private>
@ -118,4 +122,4 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
</Project>

View File

@ -37,13 +37,14 @@ namespace Explorer
return typeof(IEnumerable).IsAssignableFrom(t);
}
// Only Il2Cpp List needs this check. C# List is IEnumerable.
public static bool IsCppList(Type t)
// Checks for Il2Cpp List or HashSet.
public static bool IsCppEnumerable(Type t)
{
if (t.IsGenericType && t.GetGenericTypeDefinition() is Type g)
{
return typeof(Il2CppSystem.Collections.Generic.List<>).IsAssignableFrom(g)
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g);
|| typeof(Il2CppSystem.Collections.Generic.IList<>).IsAssignableFrom(g)
|| typeof(Il2CppSystem.Collections.Generic.HashSet<>).IsAssignableFrom(g);
}
else
{
@ -89,18 +90,20 @@ namespace Explorer
{
if (obj == null) return null;
// Need to use GetIl2CppType for Il2CppSystem Objects
if (obj is Il2CppSystem.Object ilObject)
{
var ilTypeName = ilObject.GetIl2CppType().AssemblyQualifiedName;
if (Type.GetType(ilTypeName) is Type t && !t.FullName.Contains("System.RuntimeType"))
// Prevent weird behaviour when inspecting an Il2CppSystem.Type object.
if (ilObject is ILType)
{
return t;
return typeof(ILType);
}
return ilObject.GetType();
// Get the System.Type using the qualified name, or fallback to GetType.
return Type.GetType(ilObject.GetIl2CppType().AssemblyQualifiedName) ?? obj.GetType();
}
// It's a normal object, this is fine
return obj.GetType();
}
@ -109,12 +112,11 @@ namespace Explorer
var list = new List<Type>();
var type = GetActualType(obj);
list.Add(type);
while (type.BaseType != null)
while (type != null)
{
type = type.BaseType;
list.Add(type);
type = type.BaseType;
}
return list.ToArray();

View File

@ -428,7 +428,7 @@ namespace Explorer
{
var t = ReflectionHelpers.GetActualType(obj);
if (!FilterName(t.FullName) || ReflectionHelpers.IsEnumerable(t) || ReflectionHelpers.IsCppList(t))
if (!FilterName(t.FullName) || ReflectionHelpers.IsEnumerable(t) || ReflectionHelpers.IsCppEnumerable(t))
{
continue;
}

View File

@ -14,6 +14,25 @@ namespace Explorer.Tests
public static TestClass Instance => m_instance ?? (m_instance = new TestClass());
private static TestClass m_instance;
public TestClass()
{
ILHashSetTest = new Il2CppSystem.Collections.Generic.HashSet<string>();
ILHashSetTest.Add("1");
ILHashSetTest.Add("2");
ILHashSetTest.Add("3");
}
// test HashSets
public static HashSet<string> HashSetTest = new HashSet<string>
{
"One",
"Two",
"Three"
};
public static Il2CppSystem.Collections.Generic.HashSet<string> ILHashSetTest;
// Test indexed parameter
public string this[int arg0, string arg1]

View File

@ -32,10 +32,14 @@ namespace Explorer
private UnityEngine.Object m_uObj;
private Component m_component;
private static readonly HashSet<string> _memberBlacklist = new HashSet<string>
private static readonly HashSet<string> _typeAndMemberBlacklist = new HashSet<string>
{
// Causes a crash
"Type.DeclaringMethod",
};
private static readonly HashSet<string> _methodStartsWithBlacklist = new HashSet<string>
{
// Pointless (handled by Properties)
"get_",
"set_"
@ -157,7 +161,11 @@ namespace Explorer
continue;
// check blacklisted members
if (_memberBlacklist.Any(it => member.Name.StartsWith(it)))
var name = member.DeclaringType.Name + "." + member.Name;
if (_typeAndMemberBlacklist.Any(it => it == name))
continue;
if (_methodStartsWithBlacklist.Any(it => member.Name.StartsWith(it)))
continue;
// compare signature to already cached members