33using System . Collections . Generic ;
44using System . Linq ;
55using System . Reflection ;
6+ using MelonLoader ;
67using UnityEngine ;
78
89namespace Explorer
@@ -16,74 +17,216 @@ public partial class CacheList : CacheObjectBase
1617 public float WhiteSpace = 215f ;
1718 public float ButtonWidthOffset = 290f ;
1819
20+ private CacheObjectBase [ ] m_cachedEntries ;
21+
22+ // Type of Entries in the Array
1923 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 )
2263 {
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 )
2475 {
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 ( ) ;
4177 }
42- return m_entryType ;
4378 }
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 )
4587 {
46- m_entryType = value ;
47- }
88+ m_genericToArray = GenericTypeDef
89+ . MakeGenericType ( new Type [ ] { this . EntryType } )
90+ . GetMethod ( "ToArray" ) ;
91+ }
92+ return m_genericToArray ;
4893 }
49- private Type m_entryType ;
5094
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 ( )
52105 {
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
54113 {
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 ++ )
56126 {
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 ; }
58133 }
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 ;
60141 }
61142 }
62143
63- private IEnumerable m_enumerable ;
64- private CacheObjectBase [ ] m_cachedEntries ;
65-
66- public MethodInfo GenericToArrayMethod
144+ private Type GetEntryType ( )
67145 {
68- get
146+ if ( m_entryType == null )
69147 {
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+ }
71160
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+ }
76174 }
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 ;
77183 }
78- private MethodInfo m_genericToArray ;
79184
80- private IEnumerable CastValueFromList ( )
185+ public override void UpdateValue ( )
81186 {
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 ( ) ;
83218 }
84219
220+ // ============= GUI Draw =============
221+
85222 public override void DrawValue ( Rect window , float width )
86223 {
224+ if ( m_cachedEntries == null )
225+ {
226+ GUILayout . Label ( "m_cachedEntries is null!" , null ) ;
227+ return ;
228+ }
229+
87230 int count = m_cachedEntries . Length ;
88231
89232 if ( ! IsExpanded )
@@ -182,27 +325,5 @@ public override void DrawValue(Rect window, float width)
182325 GUI . skin . label . alignment = TextAnchor . UpperLeft ;
183326 }
184327 }
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- }
207328 }
208329}
0 commit comments