using System; using System.Collections; using System.Linq; using System.Reflection; using UnityEngine; namespace PrefabEvolution { [Serializable] public class ExposedProperty : BaseExposedData { public class PropertyInvocationChain { public class InvokeInfo { public MemberInfo member; public int index = -1; public object tempTarget; public Type valueType; public object GetValue(object target) { tempTarget = target; return GetMemberValue(target, member, index); } public void SetValue(object target, object value) { tempTarget = target; setValue(target, member, value, index); } public void SetValue(object value) { setValue(tempTarget, member, value, index); } } public object root; public string path; public InvokeInfo[] members; public object value { get { object obj = root; GetValidFieldName(ref obj, path); for (int i = 0; i < members.Length; i++) { obj = members[i].GetValue(obj); } return obj; } set { object obj = root; GetValidFieldName(ref obj, path); for (int i = 0; i < members.Length - 1; i++) { obj = members[i].GetValue(obj); } members[members.Length - 1].SetValue(obj, value); for (int num = members.Length - 2; num >= 0; num--) { InvokeInfo invokeInfo = members[num]; InvokeInfo invokeInfo2 = members[num + 1]; if (invokeInfo.member.MemberType == MemberTypes.Property || invokeInfo.valueType.IsValueType || invokeInfo2.valueType.IsValueType) { invokeInfo.SetValue(invokeInfo2.tempTarget); } } } } public bool isValid { get { return members != null; } } public PropertyInvocationChain(object root, string path) { this.root = root; this.path = path; GetInstance(root, path, out members); } internal static object GetInstance(object obj, string path, out InvokeInfo[] members) { path = path.Replace(".Array.data", string.Empty); string[] array = path.Split('.'); string[] array2 = array; object obj2 = obj; members = new InvokeInfo[array2.Length]; try { int num = 0; string[] array3 = array2; foreach (string text in array3) { members[num] = new InvokeInfo(); if (text.Contains("[")) { string[] array4 = text.Split('[', ']'); int index = int.Parse(array4[1]); members[num].index = index; obj2 = getField(obj2, array4[0], out members[num].member, index); } else { obj2 = getField(obj2, text, out members[num].member); } PropertyInfo propertyInfo = members[num].member as PropertyInfo; FieldInfo fieldInfo = members[num].member as FieldInfo; if (fieldInfo != null) { members[num].valueType = fieldInfo.FieldType; } else if (propertyInfo != null) { members[num].valueType = propertyInfo.PropertyType; } num++; } return obj2; } catch (Exception exception) { members = null; Debug.LogException(exception); return null; } } private static object GetMemberValue(object target, MemberInfo member, int index = -1) { object obj = null; FieldInfo fieldInfo = member as FieldInfo; if (fieldInfo != null) { obj = fieldInfo.GetValue(target); } PropertyInfo propertyInfo = member as PropertyInfo; if (propertyInfo != null) { obj = propertyInfo.GetValue(target, null); } return (obj == null) ? null : ((index != -1) ? (obj as IList)[index] : obj); } private static void setValue(object target, MemberInfo member, object value, int index = -1) { if (index != -1) { target = GetMemberValue(target, member); (target as IList)[index] = value; return; } FieldInfo fieldInfo = member as FieldInfo; if (fieldInfo != null) { fieldInfo.SetValue(target, value); } PropertyInfo propertyInfo = member as PropertyInfo; if (propertyInfo != null) { propertyInfo.SetValue(target, value, null); } } public static string GetValidFieldName(ref object obj, string fieldName) { if (obj is Renderer && fieldName == "m_Materials") { return "sharedMaterials"; } if (obj is MeshFilter && fieldName == "m_Mesh") { return "sharedMesh"; } if (obj is GameObject && fieldName == "m_IsActive") { obj = new GameObjectWrapper(obj as GameObject); } return fieldName; } private static object getField(object obj, string field, out MemberInfo member, int index = -1) { member = null; try { BindingFlags bindingAttr = BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; if (obj == null) { return null; } field = GetValidFieldName(ref obj, field); Type type = obj.GetType(); member = type.GetField(field, bindingAttr); if (member == null && field.StartsWith("m_")) { member = type.GetField(field.Remove(0, 2), bindingAttr); } member = type.GetProperty(field, bindingAttr); if (member == null && field.StartsWith("m_")) { member = type.GetProperty(field.Remove(0, 2), bindingAttr); } if (member == null) { member = type.GetMembers(bindingAttr).First((MemberInfo m) => m.Name.ToUpper() == field.ToUpper()); } if (member != null) { return GetMemberValue(obj, member, index); } member = null; return null; } catch (Exception) { member = null; return null; } } } public UnityEngine.Object Target; public string PropertyPath; private PropertyInvocationChain _invocationChain; private PropertyInvocationChain invocationChain { get { if (_invocationChain == null) { _invocationChain = new PropertyInvocationChain(Target, PropertyPath); try { Value = Value; } catch (Exception exception) { Debug.LogException(exception); _invocationChain.members = null; } } return _invocationChain; } } public bool IsValid { get { return invocationChain.isValid; } } public object Value { get { if (!IsValid) { Debug.LogWarning(string.Concat("Trying to get value from invalid prefab property. Target:", Target, " Property path:", PropertyPath)); return null; } return invocationChain.value; } set { if (!IsValid) { Debug.LogWarning(string.Concat("Trying to set value to invalid prefab property. [Target:", Target, ", Property path:", PropertyPath, "]")); } else { invocationChain.value = value; } } } public override BaseExposedData Clone() { ExposedProperty exposedProperty = (ExposedProperty)base.Clone(); exposedProperty.Target = Target; exposedProperty.PropertyPath = PropertyPath; return exposedProperty; } public override void OnAfterDeserialize() { base.OnAfterDeserialize(); _invocationChain = null; } } }