-
Notifications
You must be signed in to change notification settings - Fork 110
Inspector - Improved handling of IL2CPP members #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
788bcf3
Refactor inspector member collecting code
ManlyMarco 6231a11
wip
ManlyMarco d31b32e
It's working!
ManlyMarco 3cff891
REfactoring
ManlyMarco 68abb5d
Lighter
ManlyMarco 2a8a7e5
Update RuntimeUnityEditor.Core/Windows/Inspector/Inspector.cs
ManlyMarco File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
225 changes: 225 additions & 0 deletions
225
RuntimeUnityEditor.Core/Windows/Inspector/IL2CPP/MemberCollector.IL2CPP.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| #if IL2CPP | ||
| using HarmonyLib; | ||
| using RuntimeUnityEditor.Core.Inspector.Entries; | ||
| using RuntimeUnityEditor.Core.Utils; | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using System.Reflection; | ||
|
|
||
| namespace RuntimeUnityEditor.Core.Inspector.IL2CPP; | ||
|
|
||
| public class IL2CPPCacheEntryHelper | ||
| { | ||
| private static readonly Dictionary<Type, Dictionary<MemberInfo, FieldInfo>> _ptrLookup = new(); | ||
|
|
||
| public static Dictionary<MemberInfo, FieldInfo> GetPtrLookupTable(Type type) | ||
| { | ||
| // todo some way to clean up old entries? | ||
| if (_ptrLookup.TryGetValue(type, out var value)) | ||
| return value; | ||
|
|
||
| value = new Dictionary<MemberInfo, FieldInfo>(); | ||
|
|
||
| var staticFields = type.GetFields(BindingFlags.Static | BindingFlags.NonPublic).Where(x => x.IsInitOnly).ToList(); | ||
|
|
||
| var fieldPtrs = staticFields.Where(x => x.Name.StartsWith("NativeFieldInfoPtr_")) | ||
| .Select(x => new { trimmed = x.Name.Substring("NativeFieldInfoPtr_".Length), ptrF = x }); | ||
|
|
||
| var usedFields = new HashSet<MethodInfo>(); | ||
|
|
||
| foreach (var fieldPtr in fieldPtrs) | ||
| { | ||
| var targetFieldName = fieldPtr.trimmed; | ||
| // Fields are props in il2cpp interop | ||
| var targetField = type.GetProperty(targetFieldName, AccessTools.all); | ||
| if (targetField != null) | ||
| { | ||
| value[targetField] = fieldPtr.ptrF; | ||
|
|
||
| var getMethod = targetField.GetGetMethod(); | ||
| if (getMethod != null) usedFields.Add(getMethod); | ||
| var setMethod = targetField.GetSetMethod(); | ||
| if (setMethod != null) usedFields.Add(setMethod); | ||
| } | ||
| } | ||
|
|
||
| foreach (var propertyInfo in type.GetAllProperties(true)) | ||
| { | ||
| // It's a field | ||
| if (value.ContainsKey(propertyInfo)) | ||
| continue; | ||
|
|
||
| var getMethod = propertyInfo.GetGetMethod(true); | ||
| if (getMethod != null && getMethod.GetMethodBody() != null) | ||
| { | ||
| var ptr = Il2CppInterop.Common.Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(getMethod); | ||
| if (ptr != null) | ||
| value[getMethod] = ptr; | ||
| } | ||
|
|
||
| var setMethod = propertyInfo.GetSetMethod(); | ||
| if (setMethod != null && setMethod.GetMethodBody() != null) | ||
| { | ||
| var ptr = Il2CppInterop.Common.Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(setMethod); | ||
| if (ptr != null) | ||
| value[setMethod] = ptr; | ||
| } | ||
| } | ||
|
|
||
| foreach (var methodInfo in type.GetAllMethods(true)) | ||
| { | ||
| if (value.ContainsKey(methodInfo) || usedFields.Contains(methodInfo)) | ||
| continue; | ||
|
|
||
| if (methodInfo.GetMethodBody() != null) | ||
| { | ||
| var ptr = Il2CppInterop.Common.Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(methodInfo); | ||
| if (ptr != null) | ||
| value[methodInfo] = ptr; | ||
| } | ||
| } | ||
|
|
||
| _ptrLookup[type] = value; | ||
| return value; | ||
| } | ||
|
|
||
| public static bool TryGetIl2CppCacheEntry(object instance, Type type, EventInfo p, Dictionary<MemberInfo, FieldInfo> lookup, out ICacheEntry result) | ||
| { | ||
| FieldInfo ptrAdd = null; | ||
| FieldInfo ptrRaise = null; | ||
| FieldInfo ptrRemove = null; | ||
| var addMethod = p.GetAddMethod(true); | ||
| if (addMethod != null) lookup.TryGetValue(addMethod, out ptrAdd); | ||
| var raiseMethod = p.GetRaiseMethod(true); | ||
| if (raiseMethod != null) lookup.TryGetValue(raiseMethod, out ptrRaise); | ||
| var removeMethod = p.GetRemoveMethod(true); | ||
| if (removeMethod != null) lookup.TryGetValue(removeMethod, out ptrRemove); | ||
| if (ptrAdd != null || ptrRaise != null || ptrRemove != null) | ||
| { | ||
| result = new IL2CPPEventCacheEntry(instance, p, type, ptrAdd, ptrRaise, ptrRemove); | ||
| return true; | ||
| } | ||
|
|
||
| result = null; | ||
| return false; | ||
| } | ||
|
|
||
| public static bool TryGetIl2CppCacheEntry(object instance, Type type, PropertyInfo p, Dictionary<MemberInfo, FieldInfo> lookup, out ICacheEntry result) | ||
| { | ||
| if (lookup.TryGetValue(p, out var ptr)) | ||
| { | ||
| result = new IL2CPPFieldCacheEntry(instance, p, type, ptr); | ||
| return true; | ||
| } | ||
|
|
||
| FieldInfo ptrGet = null; | ||
| FieldInfo ptrSet = null; | ||
| var getMethod = p.GetGetMethod(true); | ||
| if (getMethod != null) lookup.TryGetValue(getMethod, out ptrGet); | ||
| var setMethod = p.GetSetMethod(true); | ||
| if (setMethod != null) lookup.TryGetValue(setMethod, out ptrSet); | ||
| if (ptrGet != null || ptrSet != null) | ||
| { | ||
| result = new IL2CPPPropertyCacheEntry(instance, p, type, ptrGet, ptrSet); | ||
| return true; | ||
| } | ||
|
|
||
| result = null; | ||
| return false; | ||
| } | ||
|
|
||
| public static object SafeGetPtr(Type owner, FieldInfo ptrField) | ||
| { | ||
| if (ptrField == null) return "null"; | ||
| if (owner.ContainsGenericParameters) | ||
| return "???"; | ||
| try | ||
| { | ||
| return ptrField.GetValue(null); | ||
| } | ||
| catch | ||
| { | ||
| return "error"; | ||
| } | ||
| } | ||
|
|
||
| internal static bool IsIl2CppCacheEntry(ICacheEntry entry) | ||
| { | ||
| return entry is IL2CPPFieldCacheEntry || entry is IL2CPPPropertyCacheEntry || entry is IL2CPPMethodCacheEntry || entry is IL2CPPEventCacheEntry; | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public class IL2CPPFieldCacheEntry : PropertyCacheEntry | ||
| { | ||
| public FieldInfo PtrField { get; } | ||
|
|
||
| /// <inheritdoc /> | ||
| public IL2CPPFieldCacheEntry(object ins, PropertyInfo p, Type owner, FieldInfo ptrField) : base(ins, p, owner) | ||
| { | ||
| PtrField = ptrField; | ||
| _nameContent.tooltip = $"IL2CPP Field (ptr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrField)})\n\n{_nameContent.tooltip}"; | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public IL2CPPFieldCacheEntry(object ins, PropertyInfo p, Type owner, FieldInfo ptrField, ICacheEntry parent) : base(ins, p, owner, parent) | ||
| { | ||
| PtrField = ptrField; | ||
| _nameContent.tooltip = $"IL2CPP Field (ptr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrField)})\n\n{_nameContent.tooltip}"; | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public class IL2CPPPropertyCacheEntry : PropertyCacheEntry | ||
| { | ||
| public FieldInfo PtrFieldGet { get; } | ||
| public FieldInfo PtrFieldSet { get; } | ||
|
|
||
| /// <inheritdoc /> | ||
| public IL2CPPPropertyCacheEntry(object ins, PropertyInfo p, Type owner, FieldInfo ptrFieldGet, FieldInfo ptrFieldSet) : base(ins, p, owner) | ||
| { | ||
| PtrFieldGet = ptrFieldGet; | ||
| PtrFieldSet = ptrFieldSet; | ||
| _nameContent.tooltip = $"IL2CPP Property (getPtr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrFieldGet)}, setPtr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrFieldSet)})\n\n{_nameContent.tooltip}"; | ||
| } | ||
| /// <inheritdoc /> | ||
| public IL2CPPPropertyCacheEntry(object ins, PropertyInfo p, Type owner, FieldInfo ptrFieldGet, FieldInfo ptrFieldSet, ICacheEntry parent) : base(ins, p, owner, parent) | ||
| { | ||
| PtrFieldGet = ptrFieldGet; | ||
| PtrFieldSet = ptrFieldSet; | ||
| _nameContent.tooltip = $"IL2CPP Property (getPtr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrFieldGet)}, setPtr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrFieldSet)})\n\n{_nameContent.tooltip}"; | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public class IL2CPPMethodCacheEntry : MethodCacheEntry | ||
| { | ||
| public FieldInfo PtrField { get; } | ||
|
|
||
| /// <inheritdoc /> | ||
| public IL2CPPMethodCacheEntry(object instance, MethodInfo methodInfo, Type owner, FieldInfo ptrField) : base(instance, methodInfo, owner) | ||
| { | ||
| PtrField = ptrField; | ||
| _nameContent.tooltip = $"IL2CPP Method (ptr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrField)})\n\n{_nameContent.tooltip}"; | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| /// TODO: This does nothing so far because events are not implemented in il2cpp interop (they show up as separate add/remove/raise methods). Maybe combine them back into events? | ||
| public class IL2CPPEventCacheEntry : EventCacheEntry | ||
| { | ||
| public FieldInfo PtrFieldAdd { get; } | ||
| public FieldInfo PtrFieldRaise { get; } | ||
| public FieldInfo PtrFieldRemove { get; } | ||
| /// <inheritdoc /> | ||
| public IL2CPPEventCacheEntry(object ins, EventInfo e, Type owner, FieldInfo ptrFieldAdd, FieldInfo ptrFieldRaise, FieldInfo ptrFieldRemove) : base(ins, e, owner) | ||
| { | ||
| PtrFieldAdd = ptrFieldAdd; | ||
| PtrFieldRaise = ptrFieldRaise; | ||
| PtrFieldRemove = ptrFieldRemove; | ||
| _nameContent.tooltip = $"IL2CPP Event (addPtr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrFieldAdd)}, raisePtr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrFieldRaise)}, removePtr={IL2CPPCacheEntryHelper.SafeGetPtr(owner, ptrFieldRemove)})\n\n{_nameContent.tooltip}"; | ||
| } | ||
| } | ||
|
|
||
ManlyMarco marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| #endif | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.