11using System ;
2+ using System . Collections ;
3+ using System . Collections . Generic ;
4+ using System . Linq ;
25using System . Reflection ;
36using UnityEditor ;
47using UnityEngine ;
8+ using Object = UnityEngine . Object ;
59
610namespace BrunoMikoski . ScriptableObjectCollections
711{
@@ -108,5 +112,143 @@ public static void SetValue(this SerializedProperty serializedProperty, object v
108112 break ;
109113 }
110114 }
115+
116+ public static T GetActualObject < T > ( this SerializedProperty property , FieldInfo fieldInfo )
117+ where T : class
118+ {
119+ string label = string . Empty ;
120+ return property . GetActualObjectForSerializedProperty < T > ( fieldInfo , ref label ) ;
121+ }
122+
123+ /// <summary>
124+ /// Used to extract the target object from a serialized property.
125+ /// NOTE: This implementation comes from Unity's own Addressables package.
126+ /// </summary>
127+ /// <typeparam name="T">The type of the object to extract.</typeparam>
128+ /// <param name="property">The property containing the object.</param>
129+ /// <param name="field">The field data.</param>
130+ /// <param name="label">The label name.</param>
131+ /// <returns>Returns the target object type.</returns>
132+ public static T GetActualObjectForSerializedProperty < T > (
133+ this SerializedProperty property , FieldInfo field , ref string label )
134+ {
135+ try
136+ {
137+ if ( property == null || field == null )
138+ return default ;
139+
140+ SerializedObject serializedObject = property . serializedObject ;
141+ if ( serializedObject == null )
142+ return default ;
143+
144+ Object targetObject = serializedObject . targetObject ;
145+
146+ if ( property . depth > 0 )
147+ {
148+ List < string > slicedName = property . propertyPath . Split ( '.' ) . ToList ( ) ;
149+ List < int > arrayCounts = new List < int > ( ) ;
150+ for ( int index = 0 ; index < slicedName . Count ; index ++ )
151+ {
152+ arrayCounts . Add ( - 1 ) ;
153+ string currName = slicedName [ index ] ;
154+ if ( currName . EndsWith ( "]" ) )
155+ {
156+ string [ ] arraySlice = currName . Split ( '[' , ']' ) ;
157+ if ( arraySlice . Length >= 2 )
158+ {
159+ arrayCounts [ index - 2 ] = Convert . ToInt32 ( arraySlice [ 1 ] ) ;
160+ slicedName [ index ] = string . Empty ;
161+ slicedName [ index - 1 ] = string . Empty ;
162+ }
163+ }
164+ }
165+
166+ while ( string . IsNullOrEmpty ( slicedName . Last ( ) ) )
167+ {
168+ int i = slicedName . Count - 1 ;
169+ slicedName . RemoveAt ( i ) ;
170+ arrayCounts . RemoveAt ( i ) ;
171+ }
172+
173+ if ( property . propertyPath . EndsWith ( "]" ) )
174+ {
175+ string [ ] slice = property . propertyPath . Split ( '[' , ']' ) ;
176+ if ( slice . Length >= 2 )
177+ label = "Element " + slice [ slice . Length - 2 ] ;
178+ }
179+
180+ return DescendHierarchy < T > ( targetObject , slicedName , arrayCounts , 0 ) ;
181+ }
182+
183+ object obj = field . GetValue ( targetObject ) ;
184+ return ( T ) obj ;
185+ }
186+ catch
187+ {
188+ return default ;
189+ }
190+ }
191+
192+ static T DescendHierarchy < T > ( object targetObject , List < string > splitName , List < int > splitCounts , int depth )
193+ {
194+ if ( depth >= splitName . Count )
195+ return default ;
196+
197+ string currName = splitName [ depth ] ;
198+
199+ if ( string . IsNullOrEmpty ( currName ) )
200+ return DescendHierarchy < T > ( targetObject , splitName , splitCounts , depth + 1 ) ;
201+
202+ int arrayIndex = splitCounts [ depth ] ;
203+
204+ FieldInfo newField = targetObject . GetType ( ) . GetField (
205+ currName , BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance ) ;
206+
207+ if ( newField == null )
208+ {
209+ Type baseType = targetObject . GetType ( ) . BaseType ;
210+ while ( baseType != null && newField == null )
211+ {
212+ newField = baseType . GetField (
213+ currName ,
214+ BindingFlags . Public | BindingFlags . NonPublic | BindingFlags . Instance ) ;
215+ baseType = baseType . BaseType ;
216+ }
217+ }
218+
219+ object newObj = newField . GetValue ( targetObject ) ;
220+ if ( depth == splitName . Count - 1 )
221+ {
222+ T actualObject = default ( T ) ;
223+ if ( arrayIndex >= 0 )
224+ {
225+ if ( newObj . GetType ( ) . IsArray && ( ( Array ) newObj ) . Length > arrayIndex )
226+ actualObject = ( T ) ( ( Array ) newObj ) . GetValue ( arrayIndex ) ;
227+
228+ if ( newObj is IList newObjList && newObjList . Count > arrayIndex )
229+ {
230+ actualObject = ( T ) newObjList [ arrayIndex ] ;
231+
232+ //if (actualObject == null)
233+ // actualObject = new T();
234+ }
235+ }
236+ else
237+ {
238+ actualObject = ( T ) newObj ;
239+ }
240+
241+ return actualObject ;
242+ }
243+ else if ( arrayIndex >= 0 )
244+ {
245+ if ( newObj is IList list )
246+ newObj = list [ arrayIndex ] ;
247+ else if ( newObj is Array a )
248+ newObj = a . GetValue ( arrayIndex ) ;
249+ }
250+
251+ return DescendHierarchy < T > ( newObj , splitName , splitCounts , depth + 1 ) ;
252+ }
111253 }
112- }
254+ }
0 commit comments