2
2
using System . Collections ;
3
3
using System . Collections . Generic ;
4
4
using System . Linq ;
5
+ using System . Reflection ;
5
6
using UnityEngine ;
6
7
using UnityEngine . UI ;
7
8
using UnityExplorer . UI . CacheObject ;
@@ -19,11 +20,14 @@ public class InteractiveList : InteractiveValue, ICellPoolDataSource<CacheListEn
19
20
object ICacheObjectController . Target => this . CurrentOwner . Value ;
20
21
public Type TargetType { get ; private set ; }
21
22
22
- public override bool CanWrite => base . CanWrite && RefIList != null && ! RefIList . IsReadOnly ;
23
+ public override bool CanWrite => base . CanWrite && ( ( RefIList != null && ! RefIList . IsReadOnly ) || IsWritableGenericIList ) ;
23
24
24
25
public Type EntryType ;
25
26
public IList RefIList ;
26
27
28
+ private bool IsWritableGenericIList ;
29
+ private PropertyInfo genericIndexer ;
30
+
27
31
public int ItemCount => values . Count ;
28
32
private readonly List < object > values = new List < object > ( ) ;
29
33
private readonly List < CacheListEntry > cachedEntries = new List < CacheListEntry > ( ) ;
@@ -92,6 +96,12 @@ private void CacheEntries(object value)
92
96
{
93
97
RefIList = value as IList ;
94
98
99
+ // Check if the type implements IList<T> but not IList (ie. Il2CppArrayBase)
100
+ if ( RefIList == null )
101
+ CheckGenericIList ( value ) ;
102
+ else
103
+ IsWritableGenericIList = false ;
104
+
95
105
values . Clear ( ) ;
96
106
int idx = 0 ;
97
107
@@ -141,14 +151,61 @@ private void CacheEntries(object value)
141
151
}
142
152
}
143
153
154
+ private void CheckGenericIList ( object value )
155
+ {
156
+ try
157
+ {
158
+ var type = value . GetType ( ) ;
159
+ if ( type . GetInterfaces ( ) . Any ( it => it . IsGenericType && it . GetGenericTypeDefinition ( ) == typeof ( IList < > ) ) )
160
+ IsWritableGenericIList = ! ( bool ) type . GetProperty ( "IsReadOnly" ) . GetValue ( value , null ) ;
161
+ else
162
+ IsWritableGenericIList = false ;
163
+
164
+ if ( IsWritableGenericIList )
165
+ {
166
+ // Find the "this[int index]" property.
167
+ // It might be a private implementation.
168
+ foreach ( var prop in type . GetProperties ( ReflectionUtility . FLAGS ) )
169
+ {
170
+ if ( ( prop . Name == "Item"
171
+ || ( prop . Name . StartsWith ( "System.Collections.Generic.IList<" ) && prop . Name . EndsWith ( ">.Item" ) ) )
172
+ && prop . GetIndexParameters ( ) is ParameterInfo [ ] parameters
173
+ && parameters . Length == 1
174
+ && parameters [ 0 ] . ParameterType == typeof ( int ) )
175
+ {
176
+ genericIndexer = prop ;
177
+ break ;
178
+ }
179
+ }
180
+
181
+ if ( genericIndexer == null )
182
+ {
183
+ ExplorerCore . LogWarning ( $ "Failed to find indexer property for IList<T> type '{ type . FullName } '!") ;
184
+ IsWritableGenericIList = false ;
185
+ }
186
+ }
187
+ }
188
+ catch ( Exception ex )
189
+ {
190
+ ExplorerCore . LogWarning ( $ "Exception processing IEnumerable for IList<T> check: { ex . ReflectionExToString ( ) } ") ;
191
+ IsWritableGenericIList = false ;
192
+ }
193
+ }
194
+
144
195
// Setting the value of an index to the list
145
196
146
197
public void TrySetValueToIndex ( object value , int index )
147
198
{
148
199
try
149
200
{
150
- //value = value.TryCast(this.EntryType);
151
- RefIList [ index ] = value ;
201
+ if ( ! IsWritableGenericIList )
202
+ {
203
+ RefIList [ index ] = value ;
204
+ }
205
+ else
206
+ {
207
+ genericIndexer . SetValue ( CurrentOwner . Value , value , new object [ ] { index } ) ;
208
+ }
152
209
153
210
var entry = cachedEntries [ index ] ;
154
211
entry . SetValueFromSource ( value ) ;
0 commit comments