/// <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);
                }
            }
        }
Exemple #9
0
        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();
        }
Exemple #11
0
        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);
        }
Exemple #12
0
        /// <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);
 }
Exemple #19
0
        /// <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);
        }
Exemple #20
0
 public object CreateInstance()
 {
     return(InspectedType.Get(byProperty.StorageType).CreateInstance());
 }
Exemple #21
0
        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);
            }
        }
Exemple #22
0
 protected override object CreateInstance()
 {
     return(InspectedType.Get(typeof(TEdited)).CreateInstance());
 }
Exemple #23
0
        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);
            }
        }
Exemple #26
0
        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);
        }