public static UndoActionObject FromJson(string json) { // // Here be dragons. Thou art forewarned // var serialized = FlaxEngine.Json.JsonSerializer.Deserialize <SerializedUndoActionObject>(json); UndoActionObject undoActionObject = (UndoActionObject)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(UndoActionObject)); TargetInstanceField.SetValue(undoActionObject, serialized.TargetInstance); DataField.SetValue(undoActionObject, serialized.Data); var memberInfoPaths = new MemberInfoPath[serialized.MemberStacks.Length]; for (int i = 0; i < memberInfoPaths.Length; i++) { // Prepare the stack entries var entries = new MemberInfoPath.Entry[serialized.MemberStacks[i].Length]; for (int j = 0; j < entries.Length; j++) { var serializedEntry = serialized.MemberStacks[i][j]; Type type = Type.GetType(serializedEntry.AssemblyQualifiedName); MemberInfo memberInfo; if (serializedEntry.MemberInfoType == typeof(MethodInfo)) { memberInfo = type.GetMethod(serializedEntry.Path); } else if (serializedEntry.MemberInfoType == typeof(FieldInfo)) { memberInfo = type.GetField(serializedEntry.Path); } else if (serializedEntry.MemberInfoType == typeof(PropertyInfo)) { memberInfo = type.GetProperty(serializedEntry.Path); } else { throw new Exception("Unexpected MemberInfoType: " + serializedEntry.MemberInfoType); } entries[j] = new MemberInfoPath.Entry(new ScriptMemberInfo(memberInfo), serializedEntry.Index); } // MemberInfoPath is a struct, we have to jump through some hoops to set a private field object boxedMemberInfoPath = memberInfoPaths[i]; StackField.SetValue(boxedMemberInfoPath, entries); memberInfoPaths[i] = (MemberInfoPath)boxedMemberInfoPath; } MembersField.SetValue(undoActionObject, memberInfoPaths); return(undoActionObject); }
// ---------[ UTILITY ]--------- /// <summary>Generates the MemberInfoPath data for the given MemberInfo.</summary> private static List <MemberInfoPath> GenerateMemberInfoPathList(FieldInfo[] fieldInfoArray, PropertyInfo[] propertyInfoArray, string[] membersToIgnore, bool displayEnumerables, bool displayNested, string pathPrefix) { List <MemberInfoPath> retVal = new List <MemberInfoPath>(); List <MemberInfoPath> nested = new List <MemberInfoPath>(); // process root members foreach (FieldInfo field in fieldInfoArray) { // obsolete check if (Attribute.IsDefined(field, typeof(ObsoleteAttribute))) { continue; } // enumerable check if (!displayEnumerables && MemberReferenceDropdownDrawer.IsTypeEnumerable(field.FieldType)) { continue; } // mask check string fullName = pathPrefix + field.Name; bool skipMember = false; for (int i = 0; i < membersToIgnore.Length && !skipMember; ++i) { skipMember = (membersToIgnore[i] == fullName); } if (skipMember) { continue; } // add to list MemberInfoPath mip = new MemberInfoPath() { pathPrefix = pathPrefix, memberType = field.FieldType, info = field, }; retVal.Add(mip); // add nested? if (displayNested && field.FieldType.IsClass && field.FieldType != typeof(string)) { nested.Add(mip); } } // process root members foreach (PropertyInfo property in propertyInfoArray) { // obsolete check if (Attribute.IsDefined(property, typeof(ObsoleteAttribute))) { continue; } // enumerable check if (!displayEnumerables && MemberReferenceDropdownDrawer.IsTypeEnumerable(property.PropertyType)) { continue; } // mask check string fullName = pathPrefix + property.Name; bool skipMember = false; for (int i = 0; i < membersToIgnore.Length && !skipMember; ++i) { skipMember = (membersToIgnore[i] == fullName); } if (skipMember) { continue; } // add to list MemberInfoPath mip = new MemberInfoPath() { pathPrefix = pathPrefix, memberType = property.PropertyType, info = property, }; retVal.Add(mip); // add nested? if (displayNested && property.PropertyType.IsClass && property.PropertyType != typeof(string)) { nested.Add(mip); } } // process nested foreach (MemberInfoPath nestedInfo in nested) { string prefix = pathPrefix + nestedInfo.info.Name + "."; FieldInfo[] nestedFields = nestedInfo.memberType.GetFields(BindingFlags.Instance | BindingFlags.Public); PropertyInfo[] nestedProperties = nestedInfo.memberType.GetProperties(BindingFlags.Instance | BindingFlags.Public); retVal.AddRange(GenerateMemberInfoPathList(nestedFields, nestedProperties, membersToIgnore, displayEnumerables, displayNested, prefix)); } return(retVal); }