3
3
using System . Collections . Generic ;
4
4
using System . Linq ;
5
5
using System . Reflection ;
6
+ using MelonLoader ;
6
7
using UnityEngine ;
7
8
8
9
namespace Explorer
@@ -16,74 +17,216 @@ public partial class CacheList : CacheObjectBase
16
17
public float WhiteSpace = 215f ;
17
18
public float ButtonWidthOffset = 290f ;
18
19
20
+ private CacheObjectBase [ ] m_cachedEntries ;
21
+
22
+ // Type of Entries in the Array
19
23
public Type EntryType
20
- {
21
- get
24
+ {
25
+ get => GetEntryType ( ) ;
26
+ set => m_entryType = value ;
27
+ }
28
+ private Type m_entryType ;
29
+
30
+ // Cached IEnumerable object
31
+ public IEnumerable Enumerable
32
+ {
33
+ get => GetEnumerable ( ) ;
34
+ }
35
+ private IEnumerable m_enumerable ;
36
+
37
+ // Generic Type Definition for Lists
38
+ public Type GenericTypeDef
39
+ {
40
+ get => GetGenericTypeDef ( ) ;
41
+ }
42
+ private Type m_genericTypeDef ;
43
+
44
+ // Cached ToArray method for Lists
45
+ public MethodInfo GenericToArrayMethod
46
+ {
47
+ get => GetGenericToArrayMethod ( ) ;
48
+ }
49
+ private MethodInfo m_genericToArray ;
50
+
51
+ // Cached Item Property for ILists
52
+ public PropertyInfo ItemProperty
53
+ {
54
+ get => GetItemProperty ( ) ;
55
+ }
56
+ private PropertyInfo m_itemProperty ;
57
+
58
+ // ========== Methods ==========
59
+
60
+ private IEnumerable GetEnumerable ( )
61
+ {
62
+ if ( m_enumerable == null && Value != null )
22
63
{
23
- if ( m_entryType == null )
64
+ m_enumerable = Value as IEnumerable ?? CastValueFromList ( ) ;
65
+ }
66
+ return m_enumerable ;
67
+ }
68
+
69
+ private Type GetGenericTypeDef ( )
70
+ {
71
+ if ( m_genericTypeDef == null && Value != null )
72
+ {
73
+ var type = Value . GetType ( ) ;
74
+ if ( type . IsGenericType )
24
75
{
25
- if ( this . MemberInfo != null )
26
- {
27
- switch ( this . MemberInfo . MemberType )
28
- {
29
- case MemberTypes . Field :
30
- m_entryType = ( MemberInfo as FieldInfo ) . FieldType . GetGenericArguments ( ) [ 0 ] ;
31
- break ;
32
- case MemberTypes . Property :
33
- m_entryType = ( MemberInfo as PropertyInfo ) . PropertyType . GetGenericArguments ( ) [ 0 ] ;
34
- break ;
35
- }
36
- }
37
- else if ( Value != null )
38
- {
39
- m_entryType = Value . GetType ( ) . GetGenericArguments ( ) [ 0 ] ;
40
- }
76
+ m_genericTypeDef = type . GetGenericTypeDefinition ( ) ;
41
77
}
42
- return m_entryType ;
43
78
}
44
- set
79
+ return m_genericTypeDef ;
80
+ }
81
+
82
+ private MethodInfo GetGenericToArrayMethod ( )
83
+ {
84
+ if ( GenericTypeDef == null ) return null ;
85
+
86
+ if ( m_genericToArray == null )
45
87
{
46
- m_entryType = value ;
47
- }
88
+ m_genericToArray = GenericTypeDef
89
+ . MakeGenericType ( new Type [ ] { this . EntryType } )
90
+ . GetMethod ( "ToArray" ) ;
91
+ }
92
+ return m_genericToArray ;
48
93
}
49
- private Type m_entryType ;
50
94
51
- public IEnumerable Enumerable
95
+ private PropertyInfo GetItemProperty ( )
96
+ {
97
+ if ( m_itemProperty == null )
98
+ {
99
+ m_itemProperty = Value ? . GetType ( ) . GetProperty ( "Item" ) ;
100
+ }
101
+ return m_itemProperty ;
102
+ }
103
+
104
+ private IEnumerable CastValueFromList ( )
52
105
{
53
- get
106
+ if ( Value == null ) return null ;
107
+
108
+ if ( GenericTypeDef == typeof ( Il2CppSystem . Collections . Generic . List < > ) )
109
+ {
110
+ return ( IEnumerable ) GenericToArrayMethod ? . Invoke ( Value , new object [ 0 ] ) ;
111
+ }
112
+ else
54
113
{
55
- if ( m_enumerable == null && Value != null )
114
+ return CastFromIList ( ) ;
115
+ }
116
+ }
117
+
118
+ private IList CastFromIList ( )
119
+ {
120
+ try
121
+ {
122
+ var genericType = typeof ( List < > ) . MakeGenericType ( new Type [ ] { this . EntryType } ) ;
123
+ var list = ( IList ) Activator . CreateInstance ( genericType ) ;
124
+
125
+ for ( int i = 0 ; ; i ++ )
56
126
{
57
- m_enumerable = Value as IEnumerable ?? CastValueFromList ( ) ;
127
+ try
128
+ {
129
+ var itm = ItemProperty . GetValue ( Value , new object [ ] { i } ) ;
130
+ list . Add ( itm ) ;
131
+ }
132
+ catch { break ; }
58
133
}
59
- return m_enumerable ;
134
+
135
+ return list ;
136
+ }
137
+ catch ( Exception e )
138
+ {
139
+ MelonLogger . Log ( "Exception casting IList to Array: " + e . GetType ( ) + ", " + e . Message ) ;
140
+ return null ;
60
141
}
61
142
}
62
143
63
- private IEnumerable m_enumerable ;
64
- private CacheObjectBase [ ] m_cachedEntries ;
65
-
66
- public MethodInfo GenericToArrayMethod
144
+ private Type GetEntryType ( )
67
145
{
68
- get
146
+ if ( m_entryType == null )
69
147
{
70
- if ( EntryType == null ) return null ;
148
+ if ( this . MemberInfo != null )
149
+ {
150
+ Type memberType = null ;
151
+ switch ( this . MemberInfo . MemberType )
152
+ {
153
+ case MemberTypes . Field :
154
+ memberType = ( MemberInfo as FieldInfo ) . FieldType ;
155
+ break ;
156
+ case MemberTypes . Property :
157
+ memberType = ( MemberInfo as PropertyInfo ) . PropertyType ;
158
+ break ;
159
+ }
71
160
72
- return m_genericToArray ??
73
- ( m_genericToArray = typeof ( Il2CppSystem . Collections . Generic . List < > )
74
- . MakeGenericType ( new Type [ ] { this . EntryType } )
75
- . GetMethod ( "ToArray" ) ) ;
161
+ if ( memberType != null && memberType . IsGenericType )
162
+ {
163
+ m_entryType = memberType . GetGenericArguments ( ) [ 0 ] ;
164
+ }
165
+ }
166
+ else if ( Value != null )
167
+ {
168
+ var type = Value . GetType ( ) ;
169
+ if ( type . IsGenericType )
170
+ {
171
+ m_entryType = type . GetGenericArguments ( ) [ 0 ] ;
172
+ }
173
+ }
76
174
}
175
+
176
+ // IList probably won't be able to get any EntryType.
177
+ if ( m_entryType == null )
178
+ {
179
+ m_entryType = typeof ( object ) ;
180
+ }
181
+
182
+ return m_entryType ;
77
183
}
78
- private MethodInfo m_genericToArray ;
79
184
80
- private IEnumerable CastValueFromList ( )
185
+ public override void UpdateValue ( )
81
186
{
82
- return ( Value == null ) ? null : ( IEnumerable ) GenericToArrayMethod ? . Invoke ( Value , new object [ 0 ] ) ;
187
+ base . UpdateValue ( ) ;
188
+
189
+ if ( Value == null )
190
+ {
191
+ return ;
192
+ }
193
+
194
+ var enumerator = Enumerable ? . GetEnumerator ( ) ;
195
+
196
+ if ( enumerator == null )
197
+ {
198
+ return ;
199
+ }
200
+
201
+ var list = new List < CacheObjectBase > ( ) ;
202
+ while ( enumerator . MoveNext ( ) )
203
+ {
204
+ var obj = enumerator . Current ;
205
+ var type = ReflectionHelpers . GetActualType ( obj ) ;
206
+
207
+ if ( obj is Il2CppSystem . Object iObj )
208
+ {
209
+ obj = iObj . Il2CppCast ( type ) ;
210
+ }
211
+
212
+ var cached = GetCacheObject ( obj , null , null , type ) ;
213
+ cached . UpdateValue ( ) ;
214
+
215
+ list . Add ( cached ) ;
216
+ }
217
+ m_cachedEntries = list . ToArray ( ) ;
83
218
}
84
219
220
+ // ============= GUI Draw =============
221
+
85
222
public override void DrawValue ( Rect window , float width )
86
223
{
224
+ if ( m_cachedEntries == null )
225
+ {
226
+ GUILayout . Label ( "m_cachedEntries is null!" , null ) ;
227
+ return ;
228
+ }
229
+
87
230
int count = m_cachedEntries . Length ;
88
231
89
232
if ( ! IsExpanded )
@@ -182,27 +325,5 @@ public override void DrawValue(Rect window, float width)
182
325
GUI . skin . label . alignment = TextAnchor . UpperLeft ;
183
326
}
184
327
}
185
-
186
- /// <summary>
187
- /// Called only when the user presses the "Update" button, or if AutoUpdate is on.
188
- /// </summary>
189
- public override void UpdateValue ( )
190
- {
191
- base . UpdateValue ( ) ;
192
-
193
- if ( Value == null ) return ;
194
-
195
- var enumerator = Enumerable ? . GetEnumerator ( ) ;
196
-
197
- if ( enumerator == null ) return ;
198
-
199
- var list = new List < CacheObjectBase > ( ) ;
200
- while ( enumerator . MoveNext ( ) )
201
- {
202
- list . Add ( GetCacheObject ( enumerator . Current , null , null , this . EntryType ) ) ;
203
- }
204
-
205
- m_cachedEntries = list . ToArray ( ) ;
206
- }
207
328
}
208
329
}
0 commit comments