/// <summary> /// Changes the instance of the given object, if necessary. /// </summary> public object UpdateObjectInstance(object current, int currentIndex, int updatedIndex) { // the index has not changed - there will be no change in object // instance if (currentIndex == updatedIndex) { return(current); } // index 0 is always null if (updatedIndex == 0) { return(null); } // create an instance of the object Type currentType = null; if (current != null) { currentType = current.GetType(); } Type newType = GetTypeForIndex(updatedIndex, currentType); if (newType == null) { return(null); } return(InspectedType.Get(newType).CreateInstance()); }
static TypeSelectionPopupWindow() { _allTypesWithStatics = new List <Type>(); var blackList = fiSettings.TypeSelectionBlacklist; foreach (Assembly assembly in fiRuntimeReflectionUtility.GetUserDefinedEditorAssemblies()) { foreach (Type type in assembly.GetTypesWithoutException()) { var inspected = InspectedType.Get(type); if (inspected.IsCollection == false) { var shouldAdd = blackList == null || !blackList.Any(t => type.FullName.ToUpper().Contains(t.ToUpper())); if (shouldAdd) { _allTypesWithStatics.Add(type); _typeNames.Add(type, type.CSharpName()); } } } } _allTypesWithStatics = (from type in _allTypesWithStatics orderby type.CSharpName() orderby type.Namespace select type).ToList(); }
public fiDeserializedObject(fiSerializedObject serializedState) { Type targetType = serializedState.Target.Target.GetType(); var serializationOperator = new fiSerializationOperator() { SerializedObjects = serializedState.ObjectReferences }; // Fetch the serializer that the target uses Type serializerType = BehaviorTypeToSerializerTypeMap.GetSerializerType(targetType); var serializer = (BaseSerializer)fiSingletons.Get(serializerType); var inspectedType = InspectedType.Get(targetType); Members = new List <fiDeserializedMember>(); foreach (fiSerializedMember member in serializedState.Members) { InspectedProperty property = inspectedType.GetPropertyByName(member.Name); if (property != null) { object deserialized = serializer.Deserialize( fsPortableReflection.AsMemberInfo(property.StorageType), member.Value, serializationOperator); Members.Add(new fiDeserializedMember() { InspectedProperty = property, Value = deserialized, ShouldRestore = member.ShouldRestore }); } } }
/// <summary> /// Returns the methods that should be shown in the dropdown, and returns /// the active method in that list. /// </summary> private void GetMethodOptions(TSerializationDelegate action, out int selectedIndex, out string[] displayedOptions) { selectedIndex = -1; var options = new List <string>(); var containerType = InspectedType.Get(action.MethodContainer.GetType()); var currentMethodName = action.MethodName; var methods = containerType.GetMethods(InspectedMemberFilters.All); for (int i = 0; i < methods.Count; ++i) { var method = methods[i]; if (method.Method.IsGenericMethodDefinition || IsValidMethod(method.Method) == false) { continue; } if (currentMethodName == method.Method.Name) { selectedIndex = options.Count; } options.Add(method.Method.Name); } displayedOptions = options.ToArray(); }
private static void EnsureNotNull(ref TCollection elements) { if (elements == null) { elements = (TCollection)InspectedType.Get(typeof(TActual)).CreateInstance(); GUI.changed = true; } }
public void VerifyPropertySerializationAndDisplay() { // SerializeAutoProperties = true using (new fiTemporaryValue <bool>(fiSettings.SerializeAutoProperties, newValue: true, setter: val => { fiSettings.SerializeAutoProperties = val; InspectedType.ResetCacheForTesting(); })) { var displayedProperties = InspectedType.Get(typeof(ModelType)).GetProperties( InspectedMemberFilters.InspectableMembers).Select(t => t.Name).ToArray(); var serializedProperties = InspectedType.Get(typeof(ModelType)).GetProperties( InspectedMemberFilters.FullInspectorSerializedProperties).Select(t => t.Name).ToArray(); CollectionAssert.AreEqual(new[] { "AutoPropertyPublicGetPublicSet", "AutoPropertyPublicGetPrivateSet", "ForceShow_ManualPropertyPublicGetPublicSet", "ForceShow_ManualPropertyPublicGetPrivateSet", "ForceShow_ManualPropertyPublicGet", "ForceSerialized_AutoPropertyPublicGetPublicSet", "ForceSerialized_AutoPropertyPublicGetPrivateSet", "ForceSerialized_ManualPropertyPublicGetPrivateSet" }, displayedProperties); CollectionAssert.AreEqual(new[] { "AutoPropertyPublicGetPublicSet", "AutoPropertyPublicGetPrivateSet", "ForceHide_AutoPropertyPublicGetPublicSet", "ForceHide_AutoPropertyPublicGetPrivateSet", "ForceSerialized_AutoPropertyPublicGetPublicSet", "ForceSerialized_AutoPropertyPublicGetPrivateSet", "ForceSerialized_ManualPropertyPublicGetPrivateSet" }, serializedProperties); } // SerializeAutoProperties = false using (new fiTemporaryValue <bool>(fiSettings.SerializeAutoProperties, newValue: false, setter: val => { fiSettings.SerializeAutoProperties = val; InspectedType.ResetCacheForTesting(); })) { var displayedProperties = InspectedType.Get(typeof(ModelType)).GetProperties( InspectedMemberFilters.InspectableMembers).Select(t => t.Name).ToArray(); var serializedProperties = InspectedType.Get(typeof(ModelType)).GetProperties( InspectedMemberFilters.FullInspectorSerializedProperties).Select(t => t.Name).ToArray(); CollectionAssert.AreEqual(new[] { "ForceShow_ManualPropertyPublicGetPublicSet", "ForceShow_ManualPropertyPublicGetPrivateSet", "ForceShow_ManualPropertyPublicGet", "ForceSerialized_AutoPropertyPublicGetPublicSet", "ForceSerialized_AutoPropertyPublicGetPrivateSet", "ForceSerialized_ManualPropertyPublicGetPrivateSet" }, displayedProperties); CollectionAssert.AreEqual(new[] { "ForceSerialized_AutoPropertyPublicGetPublicSet", "ForceSerialized_AutoPropertyPublicGetPrivateSet", "ForceSerialized_ManualPropertyPublicGetPrivateSet" }, serializedProperties); } }
/// <summary> /// Creates a serialized object from the given component. /// </summary> private static fiSerializedObject Serialize(Component target) { // Fetch the serializer that the target uses Type serializerType = BehaviorTypeToSerializerTypeMap.GetSerializerType(target.GetType()); if (serializerType == typeof(NullSerializer)) { Debug.LogError("Backups are not supported for NullSerializer types"); return(null); } var serializer = (BaseSerializer)fiSingletons.Get(serializerType); // Save the current state if (target is ISerializedObject) { ((ISerializedObject)target).SaveState(); } // Create our backup storage fiSerializedObject state = new fiSerializedObject() { Target = new fiUnityObjectReference(target), SavedAt = DateTime.Now.ToString() }; var serializationOperator = new fiSerializationOperator() { SerializedObjects = state.ObjectReferences }; // note: we use InspectedProperties, *not* SerializedProperties, because we want to // backup every field var properties = InspectedType.Get(target.GetType()).GetProperties(InspectedMemberFilters.InspectableMembers); foreach (InspectedProperty property in properties) { if (ShouldIgnoreForPersist(property)) { continue; } Type storageType = property.StorageType; object currentValue = property.Read(target); string serialized = serializer.Serialize(storageType, currentValue, serializationOperator); state.Members.Add(new fiSerializedMember() { Name = property.Name, Value = serialized }); } return(state); }
/// <summary> /// Instantiates all of the references in the given object. /// </summary> /// <param name="obj">The object to instantiate references in.</param> /// <param name="metadata">The (cached) metadata for the object.</param> private static void InstantiateReferences(object obj, InspectedType metadata) { if (metadata == null) { metadata = InspectedType.Get(obj.GetType()); } // we don't want to do anything with collections if (metadata.IsCollection) { return; } var inspectedProperties = metadata.GetProperties(InspectedMemberFilters.InspectableMembers); for (int i = 0; i < inspectedProperties.Count; ++i) { var property = inspectedProperties[i]; // this type is a reference, so we might need to instantiate it if (property.StorageType.Resolve().IsClass) { // cannot allocate an instance for abstract types if (property.StorageType.Resolve().IsAbstract) { continue; } // check to see if the property already has a value; if it // does, then skip it object current = property.Read(obj); if (current != null) { continue; } // the property is null; we need to instantiate a new value // for it var propertyMetadata = InspectedType.Get(property.StorageType); // the value cannot be created using the default constructor // (ie, it has only one constructor that takes parameters); // we cannot initialize an instance that is guaranteed to be // in a valid state if (propertyMetadata.HasDefaultConstructor == false) { continue; } object instance = propertyMetadata.CreateInstance(); property.Write(obj, instance); // recursively create instances InstantiateReferences(instance, propertyMetadata); } } }
public static IPropertyEditor TryCreate(Type dataType, ICustomAttributeProvider attributes) { // The reflected property editor is applicable to *every* type except collections, where // it is expected that the ICollectionPropertyEditor will take over (or something more // specific than that, such as the IListPropertyEditor). var metadata = InspectedType.Get(dataType); if (metadata.IsCollection) { return(null); } return(new ReflectedPropertyEditor(metadata)); }
private static void EnsureInitialState(tkDatabaseContext context, fiGraphMetadata metadata) { if (context.editedList == null) { context.editedList = (IList)InspectedType.Get(typeof(TDerived)).CreateInstance(); } TryEnsureValidIndex(context); // Set the global metadata to the graph metadata, as the graph metadata is persistent // but users still may want to access the global metadata. fiGlobalMetadata.Set(context.editedList, metadata.GetMetadata <InspectorDatabaseEditorMetadata>()); // Disable the dropdown metadata.GetPersistentMetadata <fiDropdownMetadata>().ForceDisable(); }
public bool Read(object obj, out object result) { if (byType != null) { result = obj; return(true); } // The property was potentially found on a different type. We need to // update it to associate with this type. It's very possible the // property will not even apply to context, in which case Write // becomes a no-op. InspectedProperty propertyToUse = byProperty; if (byProperty.MemberInfo.DeclaringType != obj.GetType()) { var childProp = InspectedType.Get(obj.GetType()).GetPropertyByName(byProperty.Name); if (childProp != null) { propertyToUse = childProp; } else { result = null; return(false); } } var read = propertyToUse.Read(obj); if (byListIndex >= 0) { result = ((IList)read)[byListIndex]; return(true); } if (byDictKey != null) { result = ((IDictionary)read)[byDictKey]; return(true); } result = read; return(true); }
/// <summary> /// Changes the instance of the given object, if necessary. /// </summary> public object UpdateObjectInstance(object current, int currentIndex, int updatedIndex) { // the index has not changed - there will be no change in object instance if (currentIndex == updatedIndex) { return(current); } // index 0 is always null if (updatedIndex == 0) { return(null); } // create an instance of the object Type type = _options[updatedIndex - 1].RawType; return(InspectedType.Get(type).CreateInstance()); }
static TypeSelectionPopupWindow() { _allTypesWithStatics = new List <Type>(); foreach (Assembly assembly in fiRuntimeReflectionUtility.GetUserDefinedEditorAssemblies()) { foreach (Type type in assembly.GetTypesWithoutException()) { var inspected = InspectedType.Get(type); if (inspected.IsCollection == false) { _allTypesWithStatics.Add(type); } } } _allTypesWithStatics = (from type in _allTypesWithStatics orderby type.CSharpName() orderby type.Namespace select type).ToList(); }
/// <summary> /// Restores a backup that was previously created. /// </summary> public static void RestoreBackup(fiSerializedObject serializedState) { Type targetType = serializedState.Target.Target.GetType(); var inspectedType = InspectedType.Get(targetType); var serializationOperator = new fiSerializationOperator() { SerializedObjects = serializedState.ObjectReferences }; // Fetch the serializer that the target uses Type serializerType = BehaviorTypeToSerializerTypeMap.GetSerializerType(targetType); var serializer = (BaseSerializer)fiSingletons.Get(serializerType); foreach (fiSerializedMember member in serializedState.Members) { // user requested a skip for restoring this property if (member.ShouldRestore.Enabled == false) { continue; } InspectedProperty property = inspectedType.GetPropertyByName(member.Name); if (property != null) { Type storageType = property.StorageType; object restoredValue = serializer.Deserialize(storageType, member.Value, serializationOperator); property.Write(serializedState.Target.Target, restoredValue); } } if (serializedState.Target.Target is ISerializedObject) { var serializedObj = ((ISerializedObject)serializedState.Target.Target); serializedObj.SaveState(); serializedObj.RestoreState(); } }
private static bool TryToCopyValues(ISerializedObject newInstance) { if (string.IsNullOrEmpty(newInstance.SharedStateGuid)) { return(false); } ISerializedObject originalInstance = null; lock (_skipSerializationQueue) { if (!_skipSerializationQueue.TryGetValue(newInstance.SharedStateGuid, out originalInstance)) { return(false); } _skipSerializationQueue.Remove(newInstance.SharedStateGuid); } // After a prefab is instantiated Unity will call a full // serialize/deserialize cycle on the object. We don't need to copy // values if the object references are the same. if (ReferenceEquals(newInstance, originalInstance)) { return(true); } var inspectedType = InspectedType.Get(originalInstance.GetType()); for (int i = 0; i < originalInstance.SerializedStateKeys.Count; ++i) { InspectedProperty property = inspectedType.GetPropertyByName(originalInstance.SerializedStateKeys[i]) ?? inspectedType.GetPropertyByFormerlySerializedName(originalInstance.SerializedStateKeys[i]); property.Write(newInstance, property.Read(originalInstance)); } return(true); }
/// <summary> /// Serializes the current state of the given object. /// </summary> /// <typeparam name="TSerializer">The type of serializer to use for the serialization /// process.</typeparam> /// <param name="obj">The object that should be serialized.</param> /// <returns>True if serialization was entirely successful, false if something bad happened along the way.</returns> public static bool SaveState <TSerializer>(ISerializedObject obj) where TSerializer : BaseSerializer { bool success = true; var callbacks = obj as ISerializationCallbacks; if (callbacks != null) { callbacks.OnBeforeSerialize(); } // fetch the selected serializer var serializer = fiSingletons.Get <TSerializer>(); // setup the serialization operator var serializationOperator = fiSingletons.Get <ListSerializationOperator>(); serializationOperator.SerializedObjects = new List <UnityObject>(); // get the properties that we will be serializing var serializedKeys = new List <string>(); var serializedValues = new List <string>(); // PERF: Calling InspectedType().GetProperties() is extremely expensive. If we're not in the editor, then we can avoid making // that call because the only time we serialize an object is if it has existing FS data. If it has FS data, then that data // stores the set of properties which are serialized, so we can just hijack that information when doing the serialization to // determine which properties to serialize. if (fiUtility.IsEditor || obj.SerializedStateKeys == null || obj.SerializedStateKeys.Count == 0) { var properties = InspectedType.Get(obj.GetType()).GetProperties(InspectedMemberFilters.FullInspectorSerializedProperties); for (int i = 0; i < properties.Count; ++i) { InspectedProperty property = properties[i]; string serializedValue; if (SaveStateForProperty(obj, property, serializer, serializationOperator, out serializedValue, ref success)) { serializedKeys.Add(property.Name); serializedValues.Add(serializedValue); } } } else { var inspectedType = InspectedType.Get(obj.GetType()); for (int i = 0; i < obj.SerializedStateKeys.Count; ++i) { InspectedProperty property = inspectedType.GetPropertyByName(obj.SerializedStateKeys[i]) ?? inspectedType.GetPropertyByFormerlySerializedName(obj.SerializedStateKeys[i]); if (property == null) { continue; } string serializedValue; if (SaveStateForProperty(obj, property, serializer, serializationOperator, out serializedValue, ref success)) { serializedKeys.Add(property.Name); serializedValues.Add(serializedValue); } } } // Write the updated data out to the object. // Note that we only write data out to the object if our serialized state has // changed. Unity will blindly rewrite the data on disk which will cause some // source control systems to check-out the files. If we are just updating // the content to the same content, we do not want to cause an accidental // checkout. if (AreListsDifferent(obj.SerializedStateKeys, serializedKeys)) { obj.SerializedStateKeys = serializedKeys; } if (AreListsDifferent(obj.SerializedStateValues, serializedValues)) { obj.SerializedStateValues = serializedValues; } if (AreListsDifferent(obj.SerializedObjectReferences, serializationOperator.SerializedObjects)) { obj.SerializedObjectReferences = serializationOperator.SerializedObjects; } // Calling SetDirty seems cause prefab instances to have prefab differences after a script // reload, so we only call SetDirty on ScriptableObjects (it's only really necessary for those as well) if (obj is ScriptableObject) { fiLateBindings.EditorUtility.SetDirty((ScriptableObject)obj); } if (callbacks != null) { callbacks.OnAfterSerialize(); } return(success); }
/// <summary> /// Deserializes an object that has been serialized. /// </summary> /// <typeparam name="TSerializer"> /// The type of serializer that was used to serialize the object. /// </typeparam> /// <param name="obj"> /// The object that will be restored from its serialized state. /// </param> /// <returns> /// True if restoration was completely successful, false if something bad /// happened at some point (the object may be in a partially deserialized /// state). /// </returns> public static bool RestoreState <TSerializer>(ISerializedObject obj) where TSerializer : BaseSerializer { fiLog.Log(typeof(fiISerializedObjectUtility), "Deserializing object of type {0}", obj.GetType()); var callbacks = obj as ISerializationCallbacks; try { if (callbacks != null) { callbacks.OnBeforeDeserialize(); } // Use fast-path that does not do object serialization if the // user requested it. if (!string.IsNullOrEmpty(obj.SharedStateGuid)) { if (obj.IsRestored) { return(true); } if (TryToCopyValues(obj)) { fiLog.Log(typeof(fiISerializedObjectUtility), "-- note: Used fast path when deserializing object of type {0}", obj.GetType()); obj.IsRestored = true; if (callbacks != null) { callbacks.OnAfterDeserialize(); } return(true); } else { Debug.LogError("Shared state deserialization failed for object of type " + obj.GetType().CSharpName(), obj as UnityObject); } } // ensure references are initialized if (obj.SerializedStateKeys == null) { obj.SerializedStateKeys = new List <string>(); } if (obj.SerializedStateValues == null) { obj.SerializedStateValues = new List <string>(); } if (obj.SerializedObjectReferences == null) { obj.SerializedObjectReferences = new List <UnityObject>(); } // try to verify that no data corruption occurred if (obj.SerializedStateKeys.Count != obj.SerializedStateValues.Count) { if (fiSettings.EmitWarnings) { Debug.LogWarning("Serialized key count does not equal value count; possible " + "data corruption / bad manual edit?", obj as UnityObject); } } // there is nothing to deserialize if (obj.SerializedStateKeys.Count == 0) { if (fiSettings.AutomaticReferenceInstantation) { InstantiateReferences(obj, null); } obj.IsRestored = true; return(true); } // fetch the selected serializer var serializer = fiSingletons.Get <TSerializer>(); // setup the serialization operator setup the serialization // operator var serializationOperator = fiSingletons.Get <ListSerializationOperator>(); serializationOperator.SerializedObjects = obj.SerializedObjectReferences; // get the properties that we will be serializing var inspectedType = InspectedType.Get(obj.GetType()); bool success = true; for (int i = 0; i < obj.SerializedStateKeys.Count; ++i) { var name = obj.SerializedStateKeys[i]; var state = obj.SerializedStateValues[i]; var property = inspectedType.GetPropertyByName(name) ?? inspectedType.GetPropertyByFormerlySerializedName(name); if (property == null) { if (fiSettings.EmitWarnings) { Debug.LogWarning("Unable to find serialized property with name=" + name + " on type " + obj.GetType(), obj as UnityObject); } continue; } object restoredValue = null; if (string.IsNullOrEmpty(state) == false) { try { restoredValue = serializer.Deserialize(property.MemberInfo, state, serializationOperator); } catch (Exception e) { success = false; Debug.LogError("Exception caught when deserializing property <" + name + "> with type <" + obj.GetType() + ">\n" + e, obj as UnityObject); } } // sigh... CompareBaseObjectsExternal exception is thrown when we write a null // UnityObject reference in a non-primary thread using reflection // // This is commented out because we're not currently doing multithreaded // deserialization, but this was a tricky issue to find so it will remain // documented here. // // Please note that this breaks Reset() when there is a generic UnityObject // type on the BaseBehavior, ie, // class MyBehavior : BaseBehavior { public SharedInstance<int> myInt; } // //if (ReferenceEquals(restoredValue, null) && // typeof(UnityObject).IsAssignableFrom(property.StorageType)) { // continue; //} try { property.Write(obj, restoredValue); } catch (Exception e) { success = false; if (fiSettings.EmitWarnings) { Debug.LogWarning( "Caught exception when updating property value; see next message for the exception", obj as UnityObject); Debug.LogError(e); } } } obj.IsRestored = true; return(success); } finally { if (callbacks != null) { callbacks.OnAfterDeserialize(); } } }
public NullablePropertyEditor(Type elementType) { _elementType = InspectedType.Get(elementType); }
/// <summary> /// Serializes the current state of the given object. /// </summary> /// <typeparam name="TSerializer">The type of serializer to use for the serialization /// process.</typeparam> /// <param name="obj">The object that should be serialized.</param> /// <returns>True if serialization was entirely successful, false if something bad happened along the way.</returns> public static bool SaveState <TSerializer>(ISerializedObject obj) where TSerializer : BaseSerializer { bool success = true; // short-circuit for null serializer if (typeof(TSerializer) == typeof(NullSerializer)) { return(success); } var callbacks = obj as ISerializationCallbacks; if (callbacks != null) { callbacks.OnBeforeSerialize(); } // fetch the selected serializer var serializer = fiSingletons.Get <TSerializer>(); // setup the serialization operator var serializationOperator = fiSingletons.Get <ListSerializationOperator>(); serializationOperator.SerializedObjects = new List <UnityObject>(); // get the properties that we will be serializing var properties = InspectedType.Get(obj.GetType()).GetProperties(InspectedMemberFilters.FullInspectorSerializedProperties); var serializedKeys = new List <string>(); var serializedValues = new List <string>(); for (int i = 0; i < properties.Count; ++i) { InspectedProperty property = properties[i]; object currentValue = property.Read(obj); try { if (currentValue == null) { serializedKeys.Add(property.Name); serializedValues.Add(null); } else { var serializedState = serializer.Serialize(property.MemberInfo, currentValue, serializationOperator); serializedKeys.Add(property.Name); serializedValues.Add(serializedState); } } catch (Exception e) { success = false; Debug.LogError("Exception caught when serializing property <" + property.Name + "> in <" + obj + "> with value " + currentValue + "\n" + e); } } // Write the updated data out to the object. // Note that we only write data out to the object if our serialized state has // changed. Unity will blindly rewrite the data on disk which will cause some // source control systems to check-out the files. If we are just updating // the content to the same content, we do not want to cause an accidental // checkout. if (AreListsDifferent(obj.SerializedStateKeys, serializedKeys)) { obj.SerializedStateKeys = serializedKeys; } if (AreListsDifferent(obj.SerializedStateValues, serializedValues)) { obj.SerializedStateValues = serializedValues; } if (AreListsDifferent(obj.SerializedObjectReferences, serializationOperator.SerializedObjects)) { obj.SerializedObjectReferences = serializationOperator.SerializedObjects; } // Calling SetDirty seems cause prefab instances to have prefab differences after a script // reload, so we only call SetDirty on ScriptableObjects (it's only really necessary for those as well) if (obj is ScriptableObject) { fiLateBindings.EditorUtility.SetDirty((ScriptableObject)obj); } if (callbacks != null) { callbacks.OnAfterSerialize(); } fiEditorSerializationManager.MarkSerialized(obj); return(success); }
public object CreateInstance() { return(InspectedType.Get(byProperty.StorageType).CreateInstance()); }
public void Write(object context, object value) { if (byType != null) { if (value != s_RemoveObject) { value = InspectedType.Get((Type)value).CreateInstance(); } byType[byType.Length - 1].Write(context, value); return; } // The property was potentially found on a different type. We need to // update it to associate with this type. It's very possible the // property will not even apply to context, in which case Write // becomes a no-op. InspectedProperty propertyToUse = byProperty; if (byProperty.MemberInfo.DeclaringType != context.GetType()) { var childProp = InspectedType.Get(context.GetType()).GetPropertyByName(byProperty.Name); if (childProp != null) { propertyToUse = childProp; } else { return; } } if (byListIndex >= 0) { var read = propertyToUse.Read(context); var list = (IList)read; var elementType = InspectedType.Get(propertyToUse.StorageType).ElementType; if (value == s_RemoveObject) { fiListUtility.RemoveAt(ref list, elementType, byListIndex); } else { while (byListIndex >= list.Count) { fiListUtility.Add(ref list, elementType); } list[byListIndex] = value; } // Changing list will not update the actual array reference, so // we have to write back to the stored object. if (list is Array) { propertyToUse.Write(context, list); } return; } if (byDictKey != null) { var read = propertyToUse.Read(context); var dict = (IDictionary)read; // TODO: Have a separate Write/Remove command, since you might // want to set a dict field to null. if (value == s_RemoveObject) { dict.Remove(byDictKey); } else { dict[byDictKey] = value; } return; } if (value != s_RemoveObject) { propertyToUse.Write(context, value); } else { propertyToUse.Write(context, null); } }
protected override object CreateInstance() { return(InspectedType.Get(typeof(TEdited)).CreateInstance()); }
public static RuntimeTypeModel CreateModel() { var model = TypeModel.Create(); // We want protobuf-net to serialize default values. Sometimes, protobuf-net will skip // serialization when it really shouldn't. // // An example is a nullable struct; the nullable struct can contain a value, but if // that value is the default one then protobuf-net will skip serialization, resulting // in a null nullable type after deserialization. model.UseImplicitZeroDefaults = false; // custom model workers foreach (IProtoModelWorker worker in fiRuntimeReflectionUtility.GetAssemblyInstances <IProtoModelWorker>()) { worker.Work(model); } // regular old [ProtoContract] types foreach (Type contract in GetContracts(model)) { if (contract.Resolve().IsVisible == false) { Throw("A ProtoContract type needs to have public visibility for contract={0}", contract); } model.Add(RunSanityCheck(contract), true); } // Fields and properties on UnityObject derived types, such as BaseBehavior, are not // annotated with serialization annotations. This means that for protobuf-net, if a // BaseBehavior contains a Dictionary{string,string} field, then that specific generic // instantiation may not be discovered, as the field does not serve as an anchor. // // In this loop, we go through all UnityObject derived types and ensure that every // serialized property is in the RuntimeTypeModel. foreach (var behaviorType in fiRuntimeReflectionUtility.GetUnityObjectTypes()) { // We only want UnityObject types are serializable by ProtoBufNet // TODO: support custom base classes if (typeof(BaseBehavior <ProtoBufNetSerializer>).Resolve().IsAssignableFrom(behaviorType.Resolve()) == false) { continue; } var serializedProperties = InspectedType.Get(behaviorType).GetProperties(InspectedMemberFilters.FullInspectorSerializedProperties); foreach (InspectedProperty property in serializedProperties) { // If the property is generic and the model currently doesn't contain it, make // sure we add it to the model. if (property.StorageType.Resolve().IsGenericType&& ContainsType(model, property.StorageType) == false) { model.Add(property.StorageType, true); } } } return(model); }
/// <summary> /// Serializes the current state of the given object. /// </summary> /// <typeparam name="TSerializer"> /// The type of serializer to use for the serialization process. /// </typeparam> /// <param name="obj">The object that should be serialized.</param> /// <returns> /// True if serialization was entirely successful, false if something bad /// happened along the way. /// </returns> public static bool SaveState <TSerializer>(ISerializedObject obj) where TSerializer : BaseSerializer { fiLog.Log(typeof(fiISerializedObjectUtility), "Serializing object of type {0}", obj.GetType()); bool success = true; var callbacks = obj as ISerializationCallbacks; if (callbacks != null) { callbacks.OnBeforeSerialize(); } // Skip serialization entirely if requested. if (!string.IsNullOrEmpty(obj.SharedStateGuid)) { SkipCloningValues(obj); if (callbacks != null) { callbacks.OnAfterSerialize(); } return(true); } // fetch the selected serializer var serializer = fiSingletons.Get <TSerializer>(); // setup the serialization operator var serializationOperator = fiSingletons.Get <ListSerializationOperator>(); serializationOperator.SerializedObjects = new List <UnityObject>(); // get the properties that we will be serializing var serializedKeys = new List <string>(); var serializedValues = new List <string>(); // PERF: Calling InspectedType().GetProperties() is extremely // expensive. If we're not in the editor, then we can avoid // making that call because the only time we serialize an // object is if it has existing FS data. If it has FS data, // then that data stores the set of properties which are // serialized, so we can just hijack that information when // doing the serialization to determine which properties to // serialize. if (fiUtility.IsEditor || obj.SerializedStateKeys == null || obj.SerializedStateKeys.Count == 0) { var properties = InspectedType.Get(obj.GetType()).GetProperties(InspectedMemberFilters.FullInspectorSerializedProperties); for (int i = 0; i < properties.Count; ++i) { InspectedProperty property = properties[i]; string serializedValue; if (SaveStateForProperty(obj, property, serializer, serializationOperator, out serializedValue, ref success)) { serializedKeys.Add(property.Name); serializedValues.Add(serializedValue); } } } else { var inspectedType = InspectedType.Get(obj.GetType()); for (int i = 0; i < obj.SerializedStateKeys.Count; ++i) { InspectedProperty property = inspectedType.GetPropertyByName(obj.SerializedStateKeys[i]) ?? inspectedType.GetPropertyByFormerlySerializedName(obj.SerializedStateKeys[i]); if (property == null) { continue; } string serializedValue; if (SaveStateForProperty(obj, property, serializer, serializationOperator, out serializedValue, ref success)) { serializedKeys.Add(property.Name); serializedValues.Add(serializedValue); } } } // Write the updated data out to the object. // Note that we only write data out to the object if our serialized // state has changed. Unity will blindly rewrite the data on disk // which will cause some source control systems to check-out the // files. If we are just updating the content to the same content, we // do not want to cause an accidental checkout. bool changed = false; if (AreListsDifferent(obj.SerializedStateKeys, serializedKeys)) { obj.SerializedStateKeys = serializedKeys; changed = true; } if (AreListsDifferent(obj.SerializedStateValues, serializedValues)) { obj.SerializedStateValues = serializedValues; changed = true; } if (AreListsDifferent(obj.SerializedObjectReferences, serializationOperator.SerializedObjects)) { obj.SerializedObjectReferences = serializationOperator.SerializedObjects; changed = true; } if (changed && fiUtility.IsEditor) { fiLateBindings.EditorApplication.InvokeOnEditorThread(() => { var unityObj = (UnityObject)obj; if (unityObj != null) { fiLateBindings.EditorUtility.SetDirty(unityObj); } }); } if (callbacks != null) { callbacks.OnAfterSerialize(); } return(success); }
public void OnGUI() { try { EditorGUIUtility.hierarchyMode = true; Type updatedType = _inspectedType; GUILayout.Label("Static Inspector", EditorStyles.boldLabel); { var label = new GUIContent("Inspected Type"); var typeEditor = PropertyEditor.Get(typeof(Type), null); updatedType = typeEditor.FirstEditor.EditWithGUILayout(label, _inspectedType, Metadata.Enter("TypeSelector")); } fiEditorGUILayout.Splitter(2); if (_inspectedType != null) { _inspectorScrollPosition = EditorGUILayout.BeginScrollView(_inspectorScrollPosition); var inspectedType = InspectedType.Get(_inspectedType); foreach (InspectedProperty staticProperty in inspectedType.GetProperties(InspectedMemberFilters.StaticInspectableMembers)) { var editorChain = PropertyEditor.Get(staticProperty.StorageType, staticProperty.MemberInfo); IPropertyEditor editor = editorChain.FirstEditor; GUIContent label = new GUIContent(staticProperty.Name); object currentValue = staticProperty.Read(null); EditorGUILayout.BeginHorizontal(); EditorGUILayout.GetControlRect(GUILayout.Width(8)); EditorGUILayout.BeginVertical(); GUI.enabled = staticProperty.CanWrite; object updatedValue = editor.EditWithGUILayout(label, currentValue, Metadata.Enter(staticProperty.Name)); if (staticProperty.CanWrite) { staticProperty.Write(null, updatedValue); } EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndScrollView(); } // For some reason, the type selection popup window cannot force the rest of the // Unity GUI to redraw. We do it here instead -- this removes any delay after // selecting the type in the popup window and the type actually being displayed. if (fiEditorUtility.ShouldInspectorRedraw.Enabled) { Repaint(); } if (_inspectedType != updatedType) { _inspectedType = updatedType; Repaint(); } EditorGUIUtility.hierarchyMode = false; } catch (ExitGUIException) { } catch (Exception e) { Debug.LogError(e); } }
public static Dictionary <ObjectDataPath[], object> Create(List <ObjectDataPath> toUs, object obj, HashSet <object> seenObjects) { /* * Debug.Log(string.Join(", ", toUs.Select(t => { * if (t.byProperty == null) return ""; * return t.byProperty.Name; * }).ToArray())); * Debug.Log("seenObjects.Count = " + seenObjects.Count); * Debug.Log("seenObjects.Contains " + obj + " = " + seenObjects.Contains(obj)); */ Dictionary <ObjectDataPath[], object> thisLevel = AllocateDict(); if (seenObjects.Add(obj) == false) { return(thisLevel); } // Write the type. thisLevel.Add(CreateNavigation(toUs, new ObjectDataPath(toUs.ToArray())), obj.GetType()); List <InspectedProperty> properties = InspectedType.Get(obj.GetType()).GetProperties(InspectedMemberFilters.InspectableMembers); for (int i = 0; i < properties.Count; ++i) { InspectedProperty property = properties[i]; object valueForProperty = property.Read(obj); if (IsPrimitiveValue(valueForProperty)) { thisLevel.Add(CreateNavigation(toUs, new ObjectDataPath(property)), valueForProperty); continue; } if (InspectedType.Get(property.StorageType).IsCollection) { if (valueForProperty is IList) { var listForProperty = (IList)valueForProperty; for (int j = 0; j < listForProperty.Count; ++j) { object listElement = listForProperty[j]; if (IsPrimitiveValue(listElement)) { thisLevel.Add(CreateNavigation(toUs, new ObjectDataPath(property, j)), listElement); continue; } var listChildValues = CreateWithPath(toUs, new ObjectDataPath(property, j), listElement, seenObjects); foreach (var entry in listChildValues) { thisLevel.Add(entry.Key, entry.Value); } } } else if (valueForProperty is IDictionary) { var dictForProperty = (IDictionary)valueForProperty; IDictionaryEnumerator enumerator = dictForProperty.GetEnumerator(); while (enumerator.MoveNext()) { object key = enumerator.Key; object value = enumerator.Value; if (value == null || value.GetType().IsPrimitive || value is string) { thisLevel.Add(CreateNavigation(toUs, new ObjectDataPath(property, key)), value); } else { toUs.Add(new ObjectDataPath(property, key)); var dictChildValues = Create(toUs, value, seenObjects); toUs.RemoveAt(toUs.Count - 1); foreach (var entry in dictChildValues) { thisLevel.Add(entry.Key, entry.Value); } } } } else { Debug.LogError("Please file a bug (with an example) requesting multiedit support for " + valueForProperty.GetType().CSharpName()); } continue; } // Navigate children. var childValues = CreateWithPath(toUs, new ObjectDataPath(property), valueForProperty, seenObjects); foreach (var entry in childValues) { thisLevel.Add(entry.Key, entry.Value); } } return(thisLevel); }