예제 #1
0
        private void DrawToolbar()
        {
            SirenixEditorGUI.BeginHorizontalToolbar();
            {
                // Label
                if (info.DropZone != null && DragAndDropManager.IsDragInProgress && info.DropZone.IsAccepted == false)
                {
                    GUIHelper.PushGUIEnabled(false);
                }

                if (info.Property.ValueEntry.ListLengthChangedFromPrefab)
                {
                    GUIHelper.PushIsBoldLabel(true);
                }

                if (info.ListConfig.HideFoldoutWhileEmpty && info.IsEmpty || info.CustomListDrawerOptions.Expanded)
                {
                    GUILayout.Label(info.Label, GUILayoutOptions.ExpandWidth(false));
                }
                else
                {
                    info.Toggled.Value = SirenixEditorGUI.Foldout(info.Toggled.Value, info.Label ?? GUIContent.none);
                }

                if (info.Property.ValueEntry.ListLengthChangedFromPrefab)
                {
                    GUIHelper.PopIsBoldLabel();
                }

                if (info.CustomListDrawerOptions.Expanded)
                {
                    info.Toggled.Value = true;
                }

                if (info.DropZone != null && DragAndDropManager.IsDragInProgress && info.DropZone.IsAccepted == false)
                {
                    GUIHelper.PopGUIEnabled();
                }

                GUILayout.FlexibleSpace();

                // Item Count
                if (info.CustomListDrawerOptions.ShowItemCountHasValue ? info.CustomListDrawerOptions.ShowItemCount : info.ListConfig.ShowItemCount)
                {
                    if (info.Property.ValueEntry.ValueState == PropertyValueState.CollectionLengthConflict)
                    {
                        GUILayout.Label(info.Count + " / " + info.CollectionResolver.MaxCollectionLength + " items", EditorStyles.centeredGreyMiniLabel);
                    }
                    else
                    {
                        GUILayout.Label(info.IsEmpty ? "Empty" : info.Count + " items", EditorStyles.centeredGreyMiniLabel);
                    }
                }

                bool paging     = info.CustomListDrawerOptions.PagingHasValue ? info.CustomListDrawerOptions.ShowPaging : true;
                bool hidePaging =
                    info.ListConfig.HidePagingWhileCollapsed && info.Toggled.Value == false ||
                    info.ListConfig.HidePagingWhileOnlyOnePage && info.Count <= info.NumberOfItemsPerPage;

                int numberOfItemsPrPage = Math.Max(1, info.NumberOfItemsPerPage);
                int numberOfPages       = Mathf.CeilToInt(info.Count / (float)numberOfItemsPrPage);
                int pageIndex           = info.Count == 0 ? 0 : (info.StartIndex / numberOfItemsPrPage) % info.Count;

                // Paging
                if (paging)
                {
                    bool disablePaging = paging && !hidePaging && (DragAndDropManager.IsDragInProgress || info.ShowAllWhilePaging || info.Toggled.Value == false);
                    if (disablePaging)
                    {
                        GUIHelper.PushGUIEnabled(false);
                    }

                    if (!hidePaging)
                    {
                        if (pageIndex == 0)
                        {
                            GUIHelper.PushGUIEnabled(false);
                        }

                        if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleLeft, true))
                        {
                            if (Event.current.button == 0)
                            {
                                info.StartIndex -= numberOfItemsPrPage;
                            }
                            else
                            {
                                info.StartIndex = 0;
                            }
                        }
                        if (pageIndex == 0)
                        {
                            GUIHelper.PopGUIEnabled();
                        }

                        var userPageIndex = EditorGUILayout.IntField((numberOfPages == 0 ? 0 : (pageIndex + 1)), GUILayoutOptions.Width(10 + numberOfPages.ToString(CultureInfo.InvariantCulture).Length * 10)) - 1;
                        if (pageIndex != userPageIndex)
                        {
                            info.StartIndex = userPageIndex * numberOfItemsPrPage;
                        }

                        GUILayout.Label("/ " + numberOfPages);

                        if (pageIndex == numberOfPages - 1)
                        {
                            GUIHelper.PushGUIEnabled(false);
                        }

                        if (SirenixEditorGUI.ToolbarButton(EditorIcons.TriangleRight, true))
                        {
                            if (Event.current.button == 0)
                            {
                                info.StartIndex += numberOfItemsPrPage;
                            }
                            else
                            {
                                info.StartIndex = numberOfItemsPrPage * numberOfPages;
                            }
                        }
                        if (pageIndex == numberOfPages - 1)
                        {
                            GUIHelper.PopGUIEnabled();
                        }
                    }

                    pageIndex = info.Count == 0 ? 0 : (info.StartIndex / numberOfItemsPrPage) % info.Count;

                    var newStartIndex = Mathf.Clamp(pageIndex * numberOfItemsPrPage, 0, Mathf.Max(0, info.Count - 1));
                    if (newStartIndex != info.StartIndex)
                    {
                        info.StartIndex = newStartIndex;
                        var newPageIndex = info.Count == 0 ? 0 : (info.StartIndex / numberOfItemsPrPage) % info.Count;
                        if (pageIndex != newPageIndex)
                        {
                            pageIndex       = newPageIndex;
                            info.StartIndex = Mathf.Clamp(pageIndex * numberOfItemsPrPage, 0, Mathf.Max(0, info.Count - 1));
                        }
                    }

                    info.EndIndex = Mathf.Min(info.StartIndex + numberOfItemsPrPage, info.Count);

                    if (disablePaging)
                    {
                        GUIHelper.PopGUIEnabled();
                    }
                }
                else
                {
                    info.StartIndex = 0;
                    info.EndIndex   = info.Count;
                }

                if (paging && hidePaging == false && info.ListConfig.ShowExpandButton)
                {
                    if (info.Count < 300)
                    {
                        if (SirenixEditorGUI.ToolbarButton(info.ShowAllWhilePaging ? EditorIcons.TriangleUp : EditorIcons.TriangleDown, true))
                        {
                            info.ShowAllWhilePaging = !info.ShowAllWhilePaging;
                        }
                    }
                    else
                    {
                        info.ShowAllWhilePaging = false;
                    }
                }

                // Add Button
                if (info.IsReadOnly == false && !info.HideAddButton)
                {
                    info.ObjectPicker = ObjectPicker.GetObjectPicker(info, info.CollectionResolver.ElementType);
                    var superHackyAddFunctionWeSeriouslyNeedANewListDrawer = CollectionDrawerStaticInfo.NextCustomAddFunction;
                    CollectionDrawerStaticInfo.NextCustomAddFunction = null;

                    if (SirenixEditorGUI.ToolbarButton(EditorIcons.Plus))
                    {
                        if (superHackyAddFunctionWeSeriouslyNeedANewListDrawer != null)
                        {
                            superHackyAddFunctionWeSeriouslyNeedANewListDrawer();
                        }
                        else if (info.GetCustomAddFunction != null)
                        {
                            var objs = new object[info.Property.Tree.WeakTargets.Count];

                            for (int i = 0; i < objs.Length; i++)
                            {
                                objs[i] = info.GetCustomAddFunction(info.Property.ParentValues[i]);
                            }

                            info.CollectionResolver.QueueAdd(objs);
                        }
                        else if (info.GetCustomAddFunctionVoid != null)
                        {
                            info.GetCustomAddFunctionVoid(info.Property.ParentValues[0]);

                            this.Property.ValueEntry.WeakValues.ForceMarkDirty();
                        }
                        else if (info.CustomListDrawerOptions.AlwaysAddDefaultValue)
                        {
                            var objs = new object[info.Property.Tree.WeakTargets.Count];

                            if (info.Property.ValueEntry.SerializationBackend == SerializationBackend.Unity)
                            {
                                for (int i = 0; i < objs.Length; i++)
                                {
                                    objs[i] = UnitySerializationUtility.CreateDefaultUnityInitializedObject(info.CollectionResolver.ElementType);
                                }
                            }
                            else
                            {
                                for (int i = 0; i < objs.Length; i++)
                                {
                                    if (info.CollectionResolver.ElementType.IsValueType)
                                    {
                                        objs[i] = Activator.CreateInstance(info.CollectionResolver.ElementType);
                                    }
                                    else
                                    {
                                        objs[i] = null;
                                    }
                                }
                            }

                            //info.ListValueChanger.AddListElement(objs, "Add default value");
                            info.CollectionResolver.QueueAdd(objs);
                        }
                        else if (info.CollectionResolver.ElementType.InheritsFrom <UnityEngine.Object>() && Event.current.modifiers == EventModifiers.Control)
                        {
                            info.CollectionResolver.QueueAdd(new object[info.Property.Tree.WeakTargets.Count]);
                        }
                        else
                        {
                            info.ObjectPicker.ShowObjectPicker(
                                null,
                                info.Property.GetAttribute <AssetsOnlyAttribute>() == null,
                                GUIHelper.GetCurrentLayoutRect(),
                                info.Property.ValueEntry.SerializationBackend == SerializationBackend.Unity);
                        }
                    }

                    info.JumpToNextPageOnAdd = paging && (info.Count % numberOfItemsPrPage == 0) && (pageIndex + 1 == numberOfPages);
                }

                if (info.OnTitleBarGUI != null)
                {
                    info.OnTitleBarGUI(info.Property.ParentValues[0]);
                }
            }
            SirenixEditorGUI.EndHorizontalToolbar();
        }
예제 #2
0
 void ISerializationCallbackReceiver.OnBeforeSerialize()
 {
     UnitySerializationUtility.SerializeUnityObject((UnityEngine.Object) this, ref this.serializationData, false, (SerializationContext)null);
 }
        public virtual void ValidateUnityObjectRecursively(UnityEngine.Object value, ref List <ValidationResult> results)
        {
            if (results == null)
            {
                results = new List <ValidationResult>();
            }

            if (object.ReferenceEquals(value, null))
            {
                return;
            }

            var type = value.GetType();

            bool odinSerialized             = type.IsDefined <ShowOdinSerializedPropertiesInInspectorAttribute>(inherit: true);
            bool odinSerializesUnityMembers = false;

            IMemberSelector selector;

            if (odinSerialized)
            {
                var policyOverride = value as IOverridesSerializationPolicy;

                if (policyOverride != null)
                {
                    selector = new SerializationPolicyMemberSelector(policyOverride.SerializationPolicy ?? SerializationPolicies.Unity);
                    odinSerializesUnityMembers = policyOverride.OdinSerializesUnityFields;
                }
                else
                {
                    selector = OdinMemberSelector;
                }
            }
            else
            {
                selector = UnityMemberSelector;
            }

            this.ValidateValue(value, value, ref results);

            HashSet <object>     seenReferences = new HashSet <object>(ReferenceEqualityComparer <object> .Default);
            HashSet <MemberInfo> seenMembers    = new HashSet <MemberInfo>(FastMemberComparer.Instance);

            foreach (var member in selector.SelectMembers(type))
            {
                IMemberSelector childSelector = selector;

                if (odinSerialized && !odinSerializesUnityMembers && UnitySerializationUtility.GuessIfUnityWillSerialize(member))
                {
                    childSelector = UnityMemberSelector;
                }

                var memberValue     = GetMemberValue(member, value, results);
                var memberValueType = memberValue == null?member.GetReturnType() : memberValue.GetType();

                ValidateMemberRecursive(value, member, memberValue, memberValueType, childSelector, value, new List <ValidationPathStep>()
                {
                    new ValidationPathStep()
                    {
                        Value = memberValue, Member = member, StepString = member.Name
                    }
                }, seenReferences, seenMembers, results, 0);
            }
        }
예제 #4
0
            public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node)
            {
                FieldDeclarationSyntax fieldDeclaration = (FieldDeclarationSyntax)base.VisitFieldDeclaration(node);

                var typeInfo = model.GetTypeInfo(node.Declaration.Type);

                if (typeInfo.Type == null)
                {
                    UdonSharpUtils.LogWarning($"Could not find symbol for {node}");
                    return(fieldDeclaration);
                }

                ITypeSymbol rootType = typeInfo.Type;

                while (rootType.TypeKind == TypeKind.Array)
                {
                    rootType = ((IArrayTypeSymbol)rootType).ElementType;
                }

                if (rootType.TypeKind == TypeKind.Error ||
                    rootType.TypeKind == TypeKind.Unknown)
                {
                    UdonSharpUtils.LogWarning($"Type {typeInfo.Type} for field '{fieldDeclaration.Declaration}' is invalid");
                    return(fieldDeclaration);
                }

                IFieldSymbol firstFieldSymbol = (IFieldSymbol)model.GetDeclaredSymbol(node.Declaration.Variables.First());

                rootType = firstFieldSymbol.Type;

                // If the field is not serialized or is using Odin already, we don't need to do anything.
                if (!IsFieldSerializedWithoutOdin(firstFieldSymbol))
                {
                    return(fieldDeclaration);
                }

                // Getting the type may fail if it's a user type that hasn't compiled on the C# side yet. For now we skip it, but we should do a simplified check for jagged arrays
                if (!TypeSymbol.TryGetSystemType(rootType, out Type systemType))
                {
                    return(fieldDeclaration);
                }

                // If Unity can serialize the type, we're good
                if (UnitySerializationUtility.GuessIfUnityWillSerialize(systemType))
                {
                    return(fieldDeclaration);
                }

                // Common type that gets picked up as serialized but shouldn't be
                // todo: Add actual checking for if a type is serializable, which isn't consistent. Unity/System library types in large part are serializable but don't have the System.Serializable tag, but types outside those assemblies need the tag to be serialized.
                if (systemType == typeof(VRCPlayerApi) || systemType == typeof(VRCPlayerApi[]))
                {
                    return(fieldDeclaration);
                }

                Modified = true;

                NameSyntax odinSerializeName = IdentifierName("VRC");

                odinSerializeName = QualifiedName(odinSerializeName, IdentifierName("Udon"));
                odinSerializeName = QualifiedName(odinSerializeName, IdentifierName("Serialization"));
                odinSerializeName = QualifiedName(odinSerializeName, IdentifierName("OdinSerializer"));
                odinSerializeName = QualifiedName(odinSerializeName, IdentifierName("OdinSerialize"));

                // Somehow it seems like there's literally no decent way to maintain the indent on inserted code so we'll just inline the comment because Roslyn is dumb
                SyntaxTrivia        commentTrivia = Comment(" /* UdonSharp auto-upgrade: serialization */ ");
                AttributeListSyntax newAttribList = AttributeList(SeparatedList(new [] { Attribute(odinSerializeName) })).WithTrailingTrivia(commentTrivia);

                SyntaxList <AttributeListSyntax> attributeList = fieldDeclaration.AttributeLists;

                if (attributeList.Count > 0)
                {
                    SyntaxTriviaList trailingTrivia = attributeList.Last().GetTrailingTrivia();
                    trailingTrivia = trailingTrivia.Insert(0, commentTrivia);
                    attributeList.Replace(attributeList[attributeList.Count - 1], attributeList[attributeList.Count - 1].WithoutTrailingTrivia());

                    newAttribList = newAttribList.WithTrailingTrivia(trailingTrivia);
                }
                else
                {
                    newAttribList    = newAttribList.WithLeadingTrivia(fieldDeclaration.GetLeadingTrivia());
                    fieldDeclaration = fieldDeclaration.WithoutLeadingTrivia();
                }

                attributeList = attributeList.Add(newAttribList);

                return(fieldDeclaration.WithAttributeLists(attributeList));
            }
예제 #5
0
      public bool ScanScenes(string[] scenePaths, bool includeSceneDependencies, bool showProgressBar)
      {
          if (scenePaths.Length == 0)
          {
              return(true);
          }

          bool formerForceEditorModeSerialization = UnitySerializationUtility.ForceEditorModeSerialization;

          try
          {
              UnitySerializationUtility.ForceEditorModeSerialization = true;

              bool hasDirtyScenes = false;

              for (int i = 0; i < EditorSceneManager.sceneCount; i++)
              {
                  if (EditorSceneManager.GetSceneAt(i).isDirty)
                  {
                      hasDirtyScenes = true;
                      break;
                  }
              }

              if (hasDirtyScenes && !EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
              {
                  return(false);
              }

              var oldSceneSetup = EditorSceneManager.GetSceneManagerSetup();

              try
              {
                  for (int i = 0; i < scenePaths.Length; i++)
                  {
                      var scenePath = scenePaths[i];

                      if (showProgressBar && EditorUtility.DisplayCancelableProgressBar("Scanning scenes for AOT support", "Scene " + (i + 1) + "/" + scenePaths.Length + " - " + scenePath, (float)i / scenePaths.Length))
                      {
                          return(false);
                      }

                      EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);

                      var sceneGOs = UnityEngine.Object.FindObjectsOfType <GameObject>();

                      foreach (var go in sceneGOs)
                      {
                          if ((go.hideFlags & HideFlags.DontSaveInBuild) == 0)
                          {
                              foreach (var component in go.GetComponents <ISerializationCallbackReceiver>())
                              {
                                  try
                                  {
                                      this.allowRegisteringScannedTypes = true;
                                      component.OnBeforeSerialize();

                                      var prefabSupporter = component as ISupportsPrefabSerialization;

                                      if (prefabSupporter != null)
                                      {
                                          // Also force a serialization of the object's prefab modifications, in case there are unknown types in there

                                          List <UnityEngine.Object> objs = null;
                                          var mods = UnitySerializationUtility.DeserializePrefabModifications(prefabSupporter.SerializationData.PrefabModifications, prefabSupporter.SerializationData.PrefabModificationsReferencedUnityObjects);
                                          UnitySerializationUtility.SerializePrefabModifications(mods, ref objs);
                                      }
                                  }
                                  finally
                                  {
                                      this.allowRegisteringScannedTypes = false;
                                  }
                              }
                          }
                      }
                  }

                  // Load a new empty scene that will be unloaded immediately, just to be sure we completely clear all changes made by the scan
                  EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
              }
              finally
              {
                  if (oldSceneSetup != null && oldSceneSetup.Length > 0)
                  {
                      if (showProgressBar)
                      {
                          EditorUtility.DisplayProgressBar("Restoring scene setup", "", 1.0f);
                      }
                      EditorSceneManager.RestoreSceneManagerSetup(oldSceneSetup);
                  }
              }

              if (includeSceneDependencies)
              {
                  for (int i = 0; i < scenePaths.Length; i++)
                  {
                      var scenePath = scenePaths[i];
                      if (showProgressBar && EditorUtility.DisplayCancelableProgressBar("Scanning scene dependencies for AOT support", "Scene " + (i + 1) + "/" + scenePaths.Length + " - " + scenePath, (float)i / scenePaths.Length))
                      {
                          return(false);
                      }

                      string[] dependencies = AssetDatabase.GetDependencies(scenePath, recursive: true);

                      foreach (var dependency in dependencies)
                      {
                          this.ScanAsset(dependency, includeAssetDependencies: false);   // All dependencies of this asset were already included recursively by Unity
                      }
                  }
              }

              return(true);
          }
          finally
          {
              if (showProgressBar)
              {
                  EditorUtility.ClearProgressBar();
              }

              UnitySerializationUtility.ForceEditorModeSerialization = formerForceEditorModeSerialization;
          }
      }
예제 #6
0
 void ISerializationCallbackReceiver.OnAfterDeserialize()
 {
     UnitySerializationUtility.DeserializeUnityObject(this, ref this.serializationData);
     this.OnAfterDeserialize();
 }
예제 #7
0
        /// <summary>
        /// Draws The Property.
        /// </summary>
        protected override void DrawPropertyLayout(InspectorProperty property, OdinSerializeAttribute attribute, GUIContent label)
        {
            if (GlobalSerializationConfig.Instance.HideOdinSerializeAttributeWarningMessages || property.Parent != null)
            {
                this.CallNextDrawer(property, label);
                return;
            }

            PropertyContext <string> msg;

            if (property.Context.Get(this, "Message", out msg))
            {
                if (property.Info.PropertyType == PropertyType.ValueType || property.Info.PropertyType == PropertyType.ReferenceType)
                {
                    string message = null;

                    if (property.ValueEntry.SerializationBackend == SerializationBackend.None)
                    {
                        message = "The following property is marked with the [OdinSerialize] attribute, " +
                                  "but the property is not part of any object that uses the ODIN Serialization Protocol. \n\n" +
                                  "Are you perhaps forgetting to inherit from one of our serialized base classes such as SerializedMonoBehaviour or SerializedScriptableObject? \n\n";

                        var fieldInfo = property.Info.MemberInfo as System.Reflection.FieldInfo;
                        if (fieldInfo != null && fieldInfo.IsPublic && property.Info.GetAttribute <System.NonSerializedAttribute>() == null)
                        {
                            message += "ODIN will also serialize public fields by default, so are you sure you need to mark the field with the [OdinSerialize] attribute?\n\n";
                        }
                    }                                                                                 // We need a way to find out if Unity will also serialize it.
                    else if (property.ValueEntry.SerializationBackend == SerializationBackend.ODIN && UnitySerializationUtility.GuessIfUnityWillSerialize(property.Info.MemberInfo))
                    {
                        message = "The following property is marked with the [OdinSerialize] attribute, but Unity is also serializing it. " +
                                  "You can either remove the [OdinSerialize] attribute and let Unity serialize it, or you can use the [NonSerialized] " +
                                  "attribute together with the [OdinSerialize] attribute if you want ODIN to serialize it instead of Unity.\n\n";

                        bool isCustomSerializableType =
                            property.Info.MemberInfo.DeclaringType.GetAttribute <System.SerializableAttribute>() != null &&
                            (property.Info.MemberInfo.DeclaringType.Assembly.GetAssemblyTypeFlag() & AssemblyTypeFlags.CustomTypes) != 0;

                        if (isCustomSerializableType)
                        {
                            message += "ODIN's default serialization protocol does not require a type to be marked with the [Serializable] attribute in order for it to be serialized, which Unity does. " +
                                       "Therefore you could remove the System.Serializable attribute from " + property.Info.MemberInfo.DeclaringType.GetNiceFullName() + " if you want Unity never to serialize the type.\n\n";
                        }
                    }

                    if (message != null)
                    {
                        message += "Check out our online manual for more information.\n\n";
                        message += "This message can be disabled in the 'Tools > ODIN Inspector > Preferences > Serialization' window, but it is recommended that you don't.";
                    }

                    msg.Value = message;
                }
            }

            if (msg.Value != null)
            {
                AllEditorGUI.WarningMessageBox(msg.Value);
            }

            this.CallNextDrawer(property, label);
        }
 public void OnAfterDeserialize()
 {
     UnitySerializationUtility.DeserializeUnityObject(this, ref serializationData);
 }
예제 #9
0
        private static MemberSerializationInfo CreateInfoFor(MemberInfo member, SerializationBackendFlags serializationBackend)
        {
            SerializationFlags flags = 0;

            // Is the member a field, property or auto-property?
            if (member is FieldInfo)
            {
                var f = member as FieldInfo;
                flags |= SerializationFlags.Field;

                if (f.IsPublic)
                {
                    flags |= SerializationFlags.Public;
                }
            }
            else if (member is PropertyInfo)
            {
                var p = member as PropertyInfo;
                flags |= SerializationFlags.Property;

                if (p.GetGetMethod() != null && p.GetGetMethod().IsPublic || p.GetSetMethod() != null && p.GetSetMethod().IsPublic)
                {
                    flags |= SerializationFlags.Public;
                }
                if (p.IsAutoProperty())
                {
                    flags |= SerializationFlags.AutoProperty;
                }
            }

            // Will Unity serialize the member?
            if ((serializationBackend & SerializationBackendFlags.Unity) != 0 && UnitySerializationUtility.GuessIfUnityWillSerialize(member))
            {
                flags |= SerializationFlags.SerializedByUnity;
            }

            // Will Odin serialize the member?
            if ((serializationBackend & SerializationBackendFlags.Odin) != 0 && UnitySerializationUtility.OdinWillSerialize(member, false))
            {
                flags |= SerializationFlags.SerializedByOdin;
            }

            // Does the member have a SerializeField attribute?
            if (member.HasCustomAttribute <SerializeField>())
            {
                flags |= SerializationFlags.SerializeFieldAttribute;
            }

            // Does the member have a OdinSerialize attribute?
            if (member.HasCustomAttribute <OdinSerializeAttribute>())
            {
                flags |= SerializationFlags.OdinSerializeAttribute;
            }

            // Does the member have a NonSerialized attribute?
            if (member.HasCustomAttribute <NonSerializedAttribute>())
            {
                flags |= SerializationFlags.NonSerializedAttribute;
            }

            // Does Unity support serializing the type?
            if (serializationBackend.HasAll(SerializationBackendFlags.Unity) && UnitySerializationUtility.GuessIfUnityWillSerialize(member.GetReturnType()))
            {
                flags |= SerializationFlags.TypeSupportedByUnity;
            }

            return(new MemberSerializationInfo(member, CreateNotes(member, flags, serializationBackend), flags, serializationBackend));
        }
예제 #10
0
        static DrawerLocator()
        {
            // This method is *very* expensive performance-wise and generates lots of garbage due to liberal use of LINQ for readability.
            // This is acceptable, as it only runs once per AppDomain reload, and only ever in the editor.

            //
            // First, get all relevant types
            //

            var allTypes = AssemblyUtilities.GetTypes(AssemblyTypeFlags.CustomTypes | AssemblyTypeFlags.UnityEditorTypes)
                           .Where(type => type.IsAbstract == false && type.IsClass && (typeof(OdinDrawer).IsAssignableFrom(type) || (typeof(GUIDrawer).IsAssignableFrom(type) && (!(type.Namespace ?? "").StartsWith("Unity", StringComparison.InvariantCulture) || !ExcludeUnityDrawers.Contains(type.Name)))))
                           .ToArray();

            //
            // Find all regular Unity property and decorator drawers and create alias drawers for them
            //

            IEnumerable <Type> unityPropertyDrawers;
            IEnumerable <Type> unityPropertyAttributeDrawers;
            IEnumerable <Type> unityDecoratorDrawers;

            if (DrawerLocator.CustomPropertyDrawerTypeField != null && DrawerLocator.CustomPropertyDrawerUseForChildrenField != null)
            {
                unityPropertyDrawers =
                    allTypes.Where(type => type.IsGenericTypeDefinition == false && typeof(PropertyDrawer).IsAssignableFrom(type) && type.GetConstructor(Type.EmptyTypes) != null)
                    .SelectMany(type => type.GetCustomAttributes <CustomPropertyDrawer>(true).Select(attr => new { Type = type, Attribute = attr }))
                    .Where(n =>
                {
                    if (n.Attribute != null)
                    {
                        var drawnType = CustomPropertyDrawerTypeField.GetValue(n.Attribute) as Type;

                        if (drawnType != null && !typeof(PropertyAttribute).IsAssignableFrom(drawnType) && UnitySerializationUtility.GuessIfUnityWillSerialize(drawnType))
                        {
                            return(true);
                        }
                    }

                    return(false);
                })
                    .Select(n =>
                {
                    var drawnType = (Type)CustomPropertyDrawerTypeField.GetValue(n.Attribute);

                    if (drawnType.IsAbstract || (bool)DrawerLocator.CustomPropertyDrawerUseForChildrenField.GetValue(n.Attribute))
                    {
                        var tArg = typeof(AbstractTypeUnityPropertyDrawer <, ,>).GetGenericArguments()[2];
                        return(typeof(AbstractTypeUnityPropertyDrawer <, ,>).MakeGenericType(n.Type, drawnType, tArg));
                    }
                    else
                    {
                        return(typeof(UnityPropertyDrawer <,>).MakeGenericType(n.Type, drawnType));
                    }
                });

                unityPropertyAttributeDrawers =
                    allTypes.Where(type => type.IsGenericTypeDefinition == false && typeof(PropertyDrawer).IsAssignableFrom(type) && type.GetConstructor(Type.EmptyTypes) != null)
                    .SelectMany(type => type.GetCustomAttributes <CustomPropertyDrawer>(true).Select(attr => new { Type = type, Attribute = attr }))
                    .Where(n =>
                {
                    if (n.Attribute != null)
                    {
                        var drawnType = CustomPropertyDrawerTypeField.GetValue(n.Attribute) as Type;

                        if (drawnType != null && typeof(PropertyAttribute).IsAssignableFrom(drawnType))
                        {
                            return(true);
                        }
                    }

                    return(false);
                })
                    .Select(n =>
                {
                    Type drawnType = (Type)CustomPropertyDrawerTypeField.GetValue(n.Attribute);

                    if ((bool)DrawerLocator.CustomPropertyDrawerUseForChildrenField.GetValue(n.Attribute))
                    {
                        var tAttributeArgParam = typeof(UnityPropertyAttributeDrawer <, ,>).GetGenericArguments()[1];
                        return(typeof(UnityPropertyAttributeDrawer <, ,>).MakeGenericType(n.Type, tAttributeArgParam, drawnType));
                    }
                    else
                    {
                        return(typeof(UnityPropertyAttributeDrawer <, ,>).MakeGenericType(n.Type, drawnType, typeof(PropertyAttribute)));
                    }
                });

                unityDecoratorDrawers =
                    allTypes.Where(type => type.IsGenericTypeDefinition == false && typeof(DecoratorDrawer).IsAssignableFrom(type) && type.GetConstructor(Type.EmptyTypes) != null)
                    .Select(type => new { Type = type, Attribute = type.GetCustomAttribute <CustomPropertyDrawer>(true) })
                    .Where(n => n.Attribute != null)
                    .Select(n => new { Type = n.Type, Attribute = n.Attribute, DrawnType = CustomPropertyDrawerTypeField.GetValue(n.Attribute) as Type })
                    .Where(n => n.DrawnType != null && typeof(PropertyAttribute).IsAssignableFrom(n.DrawnType))
                    .Select(n =>
                {
                    if ((bool)DrawerLocator.CustomPropertyDrawerUseForChildrenField.GetValue(n.Attribute))
                    {
                        var tAttributeArgParam = typeof(UnityDecoratorAttributeDrawer <, ,>).GetGenericArguments()[1];
                        return(typeof(UnityDecoratorAttributeDrawer <, ,>).MakeGenericType(n.Type, tAttributeArgParam, n.DrawnType));
                    }
                    else
                    {
                        return(typeof(UnityDecoratorAttributeDrawer <, ,>).MakeGenericType(n.Type, n.DrawnType, typeof(PropertyAttribute)));
                    }
                });
            }
            else
            {
                Debug.LogWarning("Could not find internal fields 'm_Type' and/or 'm_UseForChildren' in type CustomPropertyDrawer; Unity PropertyDrawers and DecoratorDrawers have been disabled in the inspector.");
                unityPropertyDrawers          = Enumerable.Empty <Type>();
                unityPropertyAttributeDrawers = Enumerable.Empty <Type>();
                unityDecoratorDrawers         = Enumerable.Empty <Type>();
            }

            //
            // Find, group and sort all defined property drawer types
            //

            DrawerLocator.PropertyDrawerInfos =
                allTypes.Where(type => type.ImplementsOpenGenericClass(typeof(OdinValueDrawer <>)) && type.GetConstructor(Type.EmptyTypes) != null && type.IsDefined <OdinDrawerAttribute>(false))
                .Append(unityPropertyDrawers)
                .Select(drawerType =>
            {
                Type drawnType;

                if (!DrawerIsValid(drawerType, out drawnType) || drawnType == null)
                {
                    return(null);
                }

                return(new DrawerInfo(drawerType, drawnType, null, drawerType.GetAttribute <OdinDrawerAttribute>(false)));
            })
                .Where(info => info != null)
                .Distinct()
                .OrderByDescending(info => info.Priority)
                .ToList();

            DrawerLocator.AttributeDrawerInfos =
                allTypes.Where(type => type.ImplementsOpenGenericClass(typeof(OdinAttributeDrawer <>)) && type.GetConstructor(Type.EmptyTypes) != null && type.IsDefined <OdinDrawerAttribute>(false))
                .Append(unityDecoratorDrawers)
                .Append(unityPropertyAttributeDrawers)
                .Select(type =>
            {
                if (type.ImplementsOpenGenericClass(typeof(OdinAttributeDrawer <,>)))
                {
                    Type drawnType;

                    if (!DrawerIsValid(type, out drawnType))
                    {
                        return(null);
                    }

                    Type[] args = type.GetArgumentsOfInheritedOpenGenericClass(typeof(OdinAttributeDrawer <,>));
                    return(new DrawerInfo(type, drawnType, args[0], type.GetAttribute <OdinDrawerAttribute>(false)));
                }
                else
                {
                    return(new DrawerInfo(type, null, type.GetArgumentsOfInheritedOpenGenericClass(typeof(OdinAttributeDrawer <>))[0], type.GetAttribute <OdinDrawerAttribute>(false)));
                }
            })
                .Where(info => info != null)
                .Distinct()
                .OrderByDescending(info => info.Priority)
                .ToList();

            DrawerLocator.GroupDrawerInfos =
                allTypes.Where(type => type.IsGenericTypeDefinition == false && type.IsGenericType == false && type.ImplementsOpenGenericClass(typeof(OdinGroupDrawer <>)) && type.GetConstructor(Type.EmptyTypes) != null)
                .Select(type => new DrawerInfo(type, null, type.GetArgumentsOfInheritedOpenGenericClass(typeof(OdinGroupDrawer <>))[0], type.GetAttribute <OdinDrawerAttribute>(false)))
                .Where(info => info.OdinDrawerAttribute != null)
                .Distinct()
                .OrderByDescending(info => info.Priority)
                .ToList();

            //
            // Register found drawers in various dictionaries
            //

            for (int i = 0; i < DrawerLocator.PropertyDrawerInfos.Count; i++)
            {
                var info = DrawerLocator.PropertyDrawerInfos[i];
                DrawerLocator.DrawerTypePriorityLookup[info.DrawerType] = info.Priority;

                //Debug.Log("Found value drawer: " + info);
            }

            for (int i = 0; i < DrawerLocator.AttributeDrawerInfos.Count; i++)
            {
                var info = DrawerLocator.AttributeDrawerInfos[i];
                DrawerLocator.DrawerTypePriorityLookup[info.DrawerType] = info.Priority;

                //Debug.Log("Found attribute drawer: " + info);

                // Also register in attribute value drawer maps

                if (info.DrawnValueType != null)
                {
                    List <DrawerInfo> list;

                    if (!DrawerLocator.AttributeDrawerMap.TryGetValue(info.DrawnAttributeType, out list))
                    {
                        list = new List <DrawerInfo>();
                        DrawerLocator.AttributeDrawerMap.Add(info.DrawnAttributeType, list);
                    }

                    list.Add(info);
                }
            }
        }
 public void OnBeforeSerialize()
 {
     UnitySerializationUtility.SerializeUnityObject(this, ref serializationData);
 }
예제 #12
0
 public void LoadData()
 {
     UnitySerializationUtility.DeserializeUnityObject(this, ref this.serialization_data);
     //Debug.Log("LoadData");
 }
예제 #13
0
        public static bool GuessIfUnityWillSerialize([NotNull] System.Reflection.MemberInfo memberInfo, [CanBeNull] object value)
        {
                        #if DONT_USE_ODIN_SERIALIZER
            if (memberInfo.IsStatic())
            {
                return(false);
            }
            var declaringType = memberInfo.DeclaringType;

            if (!(memberInfo is System.Reflection.FieldInfo))
            {
                return(false);
            }

            if (!declaringType.IsSerializable)
            {
                return(false);
            }

            if (declaringType.IsGenericType)
            {
                if (declaringType.IsGenericTypeDefinition)
                {
                    return(false);
                }
                return(declaringType.GetGenericTypeDefinition() == Types.List);
            }

            return(declaringType.IsSerializable && memberInfo is System.Reflection.FieldInfo);
                        #else
            var field = memberInfo as System.Reflection.FieldInfo;
            if (field != null && field.IsInitOnly)
            {
                return(false);
            }

            var fieldType = memberInfo.DeclaringType;

            // Generic types are not supported, even with the SerializeReference attribute - with the exceptin of List<>.
            if (fieldType.IsGenericType)
            {
                return(fieldType.GetGenericTypeDefinition() == Types.List);
            }

                        #if UNITY_2019_3_OR_NEWER
            // With SerializeReference attribute Unity can serialize interface values if value does not derive from UnityEngine.Object
            if (memberInfo.GetCustomAttributes(typeof(SerializeReference), false).Length > 0)
            {
                return(value == null || !Types.UnityObject.IsAssignableFrom(value.GetType()));
            }
                        #endif

            if (fieldType.IsAbstract)
            {
                return(false);
            }

            if (fieldType == Types.SystemObject)
            {
                return(false);
            }

            return(UnitySerializationUtility.GuessIfUnityWillSerialize(memberInfo));
                        #endif
        }
예제 #14
0
 public void LoadData()
 {
     UnitySerializationUtility.DeserializeUnityObject(this, ref this.serialization_data);
     FixNullGraphInstace(!is_ready);
     is_ready = true;
 }
예제 #15
0
        private bool ProcessScenes()
        {
            var scenePaths =
                AssetDatabase.FindAssets("t:Scene")
                .Select(n => AssetDatabase.GUIDToAssetPath(n))
                .ToList();

            bool hasDirtyScenes = false;

            for (int i = 0; i < EditorSceneManager.sceneCount; i++)
            {
                if (EditorSceneManager.GetSceneAt(i).isDirty)
                {
                    hasDirtyScenes = true;
                    break;
                }
            }

            if (hasDirtyScenes && !EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
            {
                return(false);
            }

            var oldSceneSetup = EditorSceneManager.GetSceneManagerSetup();

            try
            {
                for (int i = 0; i < scenePaths.Count; i++)
                {
                    var scenePath = scenePaths[i];

                    if (EditorUtility.DisplayCancelableProgressBar("Scanning Scenes", "Scene " + (i + 1) + "/" + scenePaths.Count + " - " + scenePath, (float)i / scenePaths.Count))
                    {
                        return(false);
                    }

                    EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);

                    var sceneGOs = UnityEngine.Object.FindObjectsOfType <GameObject>();

                    foreach (var go in sceneGOs)
                    {
                        if ((go.hideFlags & HideFlags.DontSaveInBuild) == 0)
                        {
                            foreach (var component in go.GetComponents <ISerializationCallbackReceiver>())
                            {
                                component.OnBeforeSerialize();

                                var prefabSupporter = component as ISupportsPrefabSerialization;

                                if (prefabSupporter != null)
                                {
                                    // Also force a serialization of the object's prefab modifications, in case there are unknown types in there

                                    List <UnityEngine.Object> objs = null;
                                    var mods = UnitySerializationUtility.DeserializePrefabModifications(prefabSupporter.SerializationData.PrefabModifications, prefabSupporter.SerializationData.PrefabModificationsReferencedUnityObjects);
                                    UnitySerializationUtility.SerializePrefabModifications(mods, ref objs);
                                }
                            }
                        }
                    }
                }

                // Load a new empty scene that will be unloaded immediately, just to be sure we completely clear all changes made by the scan
                EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
            }
            finally
            {
                try
                {
                    EditorUtility.DisplayProgressBar("Restoring scene setup", "", 0.5f);
                    EditorSceneManager.RestoreSceneManagerSetup(oldSceneSetup);
                }
                finally
                {
                    EditorUtility.ClearProgressBar();
                }
            }

            return(true);
        }
예제 #16
0
        private static string[] CreateNotes(MemberInfo member, SerializationFlags flags, SerializationBackendFlags serializationBackend)
        {
            List <string> notes = new List <string>();

            StringBuilder buffer = new StringBuilder();

            // Member type
            if (flags.HasAll(SerializationFlags.Property | SerializationFlags.AutoProperty))
            {
                buffer.AppendFormat("The auto property {0} ", member.GetNiceName());
            }
            else if (flags.HasAll(SerializationFlags.Property))
            {
                buffer.AppendFormat("The non-auto property {0} ", member.GetNiceName());
            }
            else
            {
                if (flags.HasAll(SerializationFlags.Public))
                {
                    buffer.AppendFormat("The public field {0} ", member.GetNiceName());
                }
                else
                {
                    buffer.AppendFormat("The field {0} ", member.GetNiceName());
                }
            }

            // Is the member serialized?
            if (flags.HasAny(SerializationFlags.SerializedByOdin | SerializationFlags.SerializedByUnity))
            {
                buffer.Append("is serialized by ");

                // Who?
                if (flags.HasAll(SerializationFlags.SerializedByUnity | SerializationFlags.SerializedByOdin))
                {
                    buffer.Append("both Unity and Odin ");
                }
                else if (flags.HasAll(SerializationFlags.SerializedByUnity))
                {
                    buffer.Append("Unity ");
                }
                else
                {
                    buffer.Append("Odin ");
                }

                buffer.Append("because ");

                // Why?
                var relevant = flags & (SerializationFlags.Public | SerializationFlags.SerializeFieldAttribute | SerializationFlags.NonSerializedAttribute);

                if (flags.HasAll(SerializationFlags.OdinSerializeAttribute) && serializationBackend.HasAll(SerializationBackendFlags.Odin)) // The OdinSerialize attribute is only relevant when the Odin serialization backend is available.
                {
                    relevant |= SerializationFlags.OdinSerializeAttribute;
                }

                switch (relevant)
                {
                case SerializationFlags.Public:
                    buffer.Append("its access modifier is public. ");
                    break;

                case SerializationFlags.SerializeFieldAttribute:
                    buffer.Append("it has the [SerializeField] attribute. ");
                    break;

                case SerializationFlags.Public | SerializationFlags.SerializeFieldAttribute:
                    buffer.Append("it has the [SerializeField] attribute, and it's public. ");
                    break;

                case SerializationFlags.OdinSerializeAttribute:
                    buffer.Append("it has the [OdinSerialize] attribute. ");
                    break;

                case SerializationFlags.Public | SerializationFlags.OdinSerializeAttribute:
                    buffer.Append("it has the [OdinSerialize] attribute, and it's public.");
                    break;

                case SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute:
                    buffer.Append("it has the [SerializeField] and [OdinSerialize] attribute. ");
                    break;

                case SerializationFlags.Public | SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute:
                    buffer.Append("its access modifier is public and has the [SerializeField] and [OdinSerialize] attribute. ");
                    break;

                case SerializationFlags.OdinSerializeAttribute | SerializationFlags.NonSerializedAttribute:
                case SerializationFlags.Public | SerializationFlags.OdinSerializeAttribute | SerializationFlags.NonSerializedAttribute:
                case SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute | SerializationFlags.NonSerializedAttribute:
                case SerializationFlags.Public | SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute | SerializationFlags.NonSerializedAttribute:
                    buffer.Append("it has the [OdinSerialize] and [NonSerialzied] attribute. ");
                    break;

                default:
                    buffer.Append("(MISSING CASE: " + relevant.ToString() + ")");
                    break;
                }

                // Empty the buffer.
                if (buffer.Length > 0)
                {
                    notes.Add(buffer.ToString());
                    buffer.Length = 0;
                }

                // Why is the value not serialized by Unity?
                if (serializationBackend.HasAll(SerializationBackendFlags.Unity) && flags.HasNone(SerializationFlags.SerializedByUnity))
                {
                    buffer.Append("The member is not being serialized by Unity since ");

                    if (flags.HasAll(SerializationFlags.Property))
                    {
                        buffer.Append("Unity does not serialize properties.");
                    }
                    else if (UnitySerializationUtility.GuessIfUnityWillSerialize(member.GetReturnType()) == false)
                    {
                        buffer.Append("Unity does not support the type.");
                    }
                    else if (flags.HasAll(SerializationFlags.NonSerializedAttribute))
                    {
                        buffer.Append("the [NonSerialized] attribute is defined.");
                    }
                    else if (flags.HasAny(SerializationFlags.Public | SerializationFlags.SerializeFieldAttribute) == false)
                    {
                        buffer.Append("it is neither a public field or has the [SerializeField] attribute.");
                    }
                    else
                    {
                        buffer.Append("# Missing case, please report: " + flags.ToString());
                    }
                }

                // Empty the buffer.
                if (buffer.Length > 0)
                {
                    notes.Add(buffer.ToString());
                    buffer.Length = 0;
                }

                // Why is the value not serialized by Odin?
                if (flags.HasAll(SerializationFlags.SerializedByOdin) == false)
                {
                    buffer.Append("Member is not serialized by Odin because ");

                    if ((serializationBackend & SerializationBackendFlags.Odin) != 0)
                    {
                        if (flags.HasAll(SerializationFlags.SerializedByUnity))
                        {
                            buffer.Append("the member is already serialized by Unity. ");
                        }
                    }
                    else
                    {
                        buffer.Append("Odin serialization is not implemented. ");

                        if (flags.HasAll(SerializationFlags.OdinSerializeAttribute))
                        {
                            buffer.Append("The use of [OdinSerialize] attribute is invalid.");
                        }
                    }
                }
            }
            else // Why not?
            {
                // Property members with Odin implementation.
                if (flags.HasAll(SerializationFlags.Property) && serializationBackend.HasAll(SerializationBackendFlags.Odin))
                {
                    if (flags.HasAll(SerializationFlags.AutoProperty) == false)
                    {
                        buffer.Append("is skipped by Odin because non-auto properties are not serialized. ");

                        if (flags.HasAll(SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute))
                        {
                            buffer.Append("The use of [SerializeField] and [OdinSerialize] attributes is invalid. ");
                        }
                        else if (flags.HasAll(SerializationFlags.OdinSerializeAttribute))
                        {
                            buffer.Append("The use of [OdinSerialize] attribute is invalid. ");
                        }
                        else if (flags.HasAll(SerializationFlags.SerializeFieldAttribute))
                        {
                            buffer.Append("The use of [SerializeField] attribute is invalid. ");
                        }
                        else if (flags.HasAll(SerializationFlags.NonSerializedAttribute))
                        {
                            buffer.Append("The use of [NonSerialized] attribute is unnecessary. ");
                        }
                    }
                    else
                    {
                        buffer.Append("Auto property member is skipped by Odin because ");

                        if (flags.HasNone(SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute))
                        {
                            buffer.Append("neither [SerializeField] nor [OdinSerialize] attributes have been used.");
                        }
                    }
                }
                // Property members without Odin implementation.
                else if (flags.HasAll(SerializationFlags.Property))
                {
                    buffer.Append("is skipped by Unity because Unity does not serialize properties. ");

                    if (flags.HasAll(SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute))
                    {
                        buffer.Append("The use of [SerializeField] and [OdinSerialize] attributes is invalid. ");
                    }
                    else if (flags.HasAll(SerializationFlags.OdinSerializeAttribute))
                    {
                        buffer.Append("The use of [OdinSerialize] attribute is invalid. ");
                    }
                    else if (flags.HasAny(SerializationFlags.SerializeFieldAttribute))
                    {
                        buffer.Append("The use of [SerializeField] attribute is invalid. ");
                    }

                    if (flags.HasAny(SerializationFlags.NonSerializedAttribute))
                    {
                        buffer.Append("The use of [NonSerialized] attribute is unnecessary.");
                    }
                }
                // Field members.
                else
                {
                    // Backend ?
                    buffer.Append("is skipped by ");
                    switch (serializationBackend)
                    {
                    case SerializationBackendFlags.Unity:
                        buffer.Append("Unity ");
                        break;

                    case SerializationBackendFlags.Odin:
                        buffer.Append("Odin ");
                        break;

                    case SerializationBackendFlags.UnityAndOdin:
                        buffer.Append("both Unity and Odin ");
                        break;
                    }

                    buffer.Append("because ");

                    if (serializationBackend == SerializationBackendFlags.None)
                    {
                        buffer.Append("there is no serialization backend? ");
                    }
                    else if (flags.HasAll(SerializationFlags.NonSerializedAttribute))
                    {
                        buffer.Append("the [NonSerialized] attribute is defined. ");
                    }
                    else if (flags.HasNone(SerializationFlags.Public | SerializationFlags.SerializeFieldAttribute))
                    {
                        buffer.Append("the field is neither public nor a [SerializeField] attribute. ");
                    }
                    else if (serializationBackend == SerializationBackendFlags.Unity && flags.HasAny(SerializationFlags.Public | SerializationFlags.SerializeFieldAttribute))
                    {
                        buffer.Append("Unity does not support the type " + member.GetReturnType().GetNiceName());
                    }

                    // Empty the buffer.
                    if (buffer.Length > 0)
                    {
                        notes.Add(buffer.ToString());
                        buffer.Length = 0;
                    }

                    // Invalid use of OdinSerialize.
                    if ((serializationBackend & SerializationBackendFlags.Odin) == 0 && flags.HasAll(SerializationFlags.OdinSerializeAttribute))
                    {
                        notes.Add("Odin serialization is not implemented. The use of [OdinSerialize] attribute is invalid."); // Just add this line directly to the notes list.
                    }
                }

                // Using both [SerializeField] and [NonSerialized] attributes.
                if (flags.HasAll(SerializationFlags.SerializeFieldAttribute | SerializationFlags.NonSerializedAttribute) && flags.HasNone(SerializationFlags.OdinSerializeAttribute))
                {
                    notes.Add("Use of [SerializeField] along with [NonSerialized] attributes is weird. Remove either the [SerializeField] or [NonSerialized] attribute.");
                }
            }

            // Empty the buffer.
            if (buffer.Length > 0)
            {
                notes.Add(buffer.ToString());
                buffer.Length = 0;
            }

            // Add notes on Unity serialization support.
            if (serializationBackend.HasAll(SerializationBackendFlags.UnityAndOdin))
            {
                if (flags.HasAll(SerializationFlags.SerializedByOdin | SerializationFlags.TypeSupportedByUnity) && flags.HasNone(SerializationFlags.SerializedByUnity))
                {
                    buffer.Append("The type " + member.GetReturnType().GetNiceName() + " appears to be supported by Unity. Are you certain that you want to use Odin for serializing?");
                }
                else if (flags.HasAll(SerializationFlags.SerializedByOdin) && flags.HasNone(SerializationFlags.TypeSupportedByUnity))
                {
                    buffer.Append("The type " + member.GetReturnType().GetNiceName() + " is not supported by Unity" + GuessWhyUnityDoesNotSupport(member.GetReturnType()));
                }
            }
            else if (serializationBackend.HasAll(SerializationBackendFlags.Unity) && flags.HasNone(SerializationFlags.TypeSupportedByUnity))
            {
                buffer.Append("The type " + member.GetReturnType().GetNiceName() + " is not supported by Unity" + GuessWhyUnityDoesNotSupport(member.GetReturnType()));
            }

            // Empty the buffer.
            if (buffer.Length > 0)
            {
                notes.Add(buffer.ToString());
                buffer.Length = 0;
            }

            // Implement Odin support.
            if (serializationBackend.HasAll(SerializationBackendFlags.Unity) &&
                serializationBackend.HasNone(SerializationBackendFlags.Odin) &&
                flags.HasNone(SerializationFlags.TypeSupportedByUnity) &&
                flags.HasAny(SerializationFlags.Public | SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute) &&
                flags.HasAny(SerializationFlags.Field | SerializationFlags.AutoProperty))
            {
                string inheritFrom = "You could implement Odin serializing by inheriting " + member.DeclaringType.GetNiceName() + " from ";

                if (typeof(MonoBehaviour).IsAssignableFrom(member.DeclaringType))
                {
                    buffer.Append(inheritFrom + typeof(SerializedMonoBehaviour).GetNiceName());
                }
                else if (typeof(UnityEngine.Networking.NetworkBehaviour).IsAssignableFrom(member.DeclaringType))
                {
                    buffer.Append(inheritFrom + typeof(SerializedNetworkBehaviour).GetNiceName());
                }
                else if (typeof(Behaviour).IsAssignableFrom(member.DeclaringType))
                {
                    buffer.Append(inheritFrom + typeof(SerializedBehaviour).GetNiceName());
                }
                else if (typeof(ScriptableObject).IsAssignableFrom(member.DeclaringType))
                {
                    buffer.Append(inheritFrom + typeof(SerializedScriptableObject).GetNiceName());
                }
            }

            // Empty the buffer.
            if (buffer.Length > 0)
            {
                notes.Add(buffer.ToString());
                buffer.Length = 0;
            }

            // Recommend using fields instead of auto properties.
            if (serializationBackend.HasAll(SerializationBackendFlags.Odin) &&
                flags.HasAll(SerializationFlags.AutoProperty | SerializationFlags.SerializedByOdin))
            {
                buffer.Append("It's recommend to use backing fields for serializing instead of auto-properties.");
            }

            // Empty the buffer.
            if (buffer.Length > 0)
            {
                notes.Add(buffer.ToString());
                buffer.Length = 0;
            }

            return(notes.ToArray());
        }
예제 #17
0
 protected override void OnAfterDeserialize()
 {
     UnitySerializationUtility.DeserializeUnityObject(this, ref serializationData);
     base.OnAfterDeserialize();
 }
예제 #18
0
        private MemberSerializationInfo(MemberInfo member, string[] notes, SerializationFlags flags, SerializationBackendFlags serializationBackend)
        {
            Assert.IsNotNull(member);
            Assert.IsFalse(flags == 0);

            this.MemberInfo = member;
            this.Notes      = notes;
            this.Info       = flags;
            this.Backend    = serializationBackend;

            this.OdinMessageType  = InfoMessageType.None;
            this.UnityMessageType = InfoMessageType.None;

            // Should the member be serialized, but isn't?
            if (flags.HasNone(SerializationFlags.SerializedByUnity | SerializationFlags.SerializedByOdin | SerializationFlags.NonSerializedAttribute) &&
                flags.HasAny(SerializationFlags.Public | SerializationFlags.SerializeFieldAttribute) &&
                (flags.HasAll(SerializationFlags.Field) || flags.HasAll(SerializationFlags.AutoProperty)))
            {
                if (serializationBackend.HasNone(SerializationBackendFlags.Odin))
                {
                    this.OdinMessageType = InfoMessageType.Info;
                }

                if (flags.HasNone(SerializationFlags.Property) && UnitySerializationUtility.GuessIfUnityWillSerialize(member.GetReturnType()) == false)
                {
                    this.UnityMessageType = InfoMessageType.Info;
                }
            }

            // Is the member serialized by both Odin and Unity?
            if (this.Info.HasAny(SerializationFlags.SerializedByOdin) && this.Info.HasAny(SerializationFlags.SerializedByUnity))
            {
                this.OdinMessageType  = InfoMessageType.Warning;
                this.UnityMessageType = InfoMessageType.Warning;
            }

            // Does the member have both SerializeField and NonSerialized attributes?
            if (this.Info.HasAll(SerializationFlags.SerializeFieldAttribute | SerializationFlags.NonSerializedAttribute))
            {
                this.UnityMessageType = InfoMessageType.Warning;
            }

            // Does the member have both SerializeField and OdinSerialize attributes?
            if (this.Info.HasAll(SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute))
            {
                if (this.Info.HasAll(SerializationFlags.SerializedByOdin))
                {
                    this.OdinMessageType = InfoMessageType.Warning;
                }
                if (this.Info.HasAll(SerializationFlags.SerializedByUnity))
                {
                    this.UnityMessageType = InfoMessageType.Warning;
                }
            }

            if (serializationBackend.HasAll(SerializationBackendFlags.UnityAndOdin) && this.Info.HasAll(SerializationFlags.SerializedByOdin | SerializationFlags.TypeSupportedByUnity) && this.Info.HasNone(SerializationFlags.SerializedByUnity))
            {
                this.OdinMessageType = InfoMessageType.Warning;
            }

            // Does the member have a OdinSerialize attribute, but no Odin backend is available?
            if (!serializationBackend.HasAll(SerializationBackendFlags.Odin) &&
                flags.HasAny(SerializationFlags.OdinSerializeAttribute))
            {
                this.OdinMessageType = InfoMessageType.Error;
            }

            // Does the member have OdinSerialize attribute, but is not serialized by Odin?
            if (this.Info.HasAny(SerializationFlags.OdinSerializeAttribute) && !this.Info.HasAny(SerializationFlags.SerializedByOdin))
            {
                this.OdinMessageType = InfoMessageType.Error;
            }

            // Is the member marked for serialzation but not serialized?
            if (this.Info.HasAny(SerializationFlags.SerializeFieldAttribute | SerializationFlags.OdinSerializeAttribute) &&
                !this.Info.HasAny(SerializationFlags.SerializedByUnity | SerializationFlags.SerializedByOdin | SerializationFlags.NonSerializedAttribute))
            {
                if (serializationBackend.HasAll(SerializationBackendFlags.Odin))
                {
                    this.OdinMessageType = InfoMessageType.Error;
                }

                if (!this.Info.HasAny(SerializationFlags.Property) && UnitySerializationUtility.GuessIfUnityWillSerialize(member.GetReturnType()))
                {
                    this.UnityMessageType = InfoMessageType.Error;
                }
            }

            // Is the member public, not marked with NonSerialized, but not serialized?
            if (this.Info.HasAll(SerializationFlags.Public | SerializationFlags.Field) &&
                !this.Info.HasAny(SerializationFlags.NonSerializedAttribute) &&
                !this.Info.HasAny(SerializationFlags.SerializedByUnity | SerializationFlags.SerializedByOdin))
            {
                if (serializationBackend.HasAll(SerializationBackendFlags.Odin))
                {
                    this.OdinMessageType = InfoMessageType.Error;
                }

                if (!this.Info.HasAny(SerializationFlags.Property) && UnitySerializationUtility.GuessIfUnityWillSerialize(member.GetReturnType()))
                {
                    this.UnityMessageType = InfoMessageType.Error;
                }
            }
        }
예제 #19
0
 void ISerializationCallbackReceiver.OnBeforeSerialize()
 {
     this.OnBeforeSerialize();
     UnitySerializationUtility.SerializeUnityObject(this, ref this.serializationData);
 }
예제 #20
0
        private static string GuessWhyUnityDoesNotSupport(Type type)
        {
            if (type == typeof(Coroutine))
            {
                return(" because Unity will never serialize Coroutines.");
            }
            if (typeof(Delegate).IsAssignableFrom(type))
            {
                return(" because Unity does not support delegates.");
            }
            if (type.IsInterface)
            {
                return(" because the type is an interface.");
            }
            if (type.IsAbstract)
            {
                return(" because the type is abstract.");
            }
            if (type == typeof(System.Object))
            {
                return(" because Unity does not support serializing System.Object.");
            }
            if (typeof(Enum).IsAssignableFrom(type))
            {
                Type underlying = Enum.GetUnderlyingType(type);

                if (UnityVersion.IsVersionOrGreater(5, 6) && (underlying == typeof(long) || underlying == typeof(ulong)))
                {
                    return(" because Unity does not support enums with underlying type of long or ulong.");
                }
                else if (UnityVersion.Major <= 5 && UnityVersion.Minor < 6 && underlying != typeof(int) && underlying != typeof(byte))
                {
                    return(" because prior to Version 5.6 Unity only supports enums with underlying type of int or byte.");
                }

                return(". Was unable to determine why Unity does not support enum with underlying type of: " + underlying.GetNiceName() + ".");
            }
            if (typeof(UnityEngine.Events.UnityEventBase).IsAssignableFrom(type) && type.IsGenericType)
            {
                return(" because the type is a generic implementation of UnityEventBase.");
            }

            if (type.IsArray)
            {
                if (type.GetArrayRank() > 1 || type.GetElementType().IsArray || type.GetElementType().ImplementsOpenGenericClass(typeof(List <>)))
                {
                    return(" because Unity does not support multi-dimensional arrays.");
                }
                else if (UnitySerializationUtility.GuessIfUnityWillSerialize(type.GetElementType()) == false)
                {
                    return(" because Unity does not support the type " + type.GetElementType().GetNiceName() + " as an array element.");
                }
            }

            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List <>))
            {
                var elementType = type.GetArgumentsOfInheritedOpenGenericClass(typeof(List <>))[0];
                if (elementType.IsArray)
                {
                    return(" because Unity does not support Lists of arrays.");
                }
                else if (elementType.ImplementsOpenGenericClass(typeof(List <>)))
                {
                    return(" because Unity does not support Lists of Lists.");
                }
                else if (UnitySerializationUtility.GuessIfUnityWillSerialize(elementType) == false)
                {
                    return(" because Unity does not support the element type of " + elementType.GetNiceName() + ".");
                }
            }

            if (type.IsGenericType || type.GetGenericArguments().Length > 0)
            {
                return(" because Unity does not support generic types.");
            }

            if (type.Assembly == typeof(string).Assembly)
            {
                return(" because Unity does not serialize [Serializable] structs and classes if they are defined in mscorlib.");
            }

            if (type.IsDefined <SerializableAttribute>(false) == false)
            {
                return(" because the type is missing a [Serializable] attribute.");
            }

            // No reason found.
            return(". Was unable to determine reason, please report this to Sirenix.");
        }
예제 #21
0
        public bool ScanScenes(string[] scenePaths, bool includeSceneDependencies, bool showProgressBar)
        {
            if (scenePaths.Length == 0)
            {
                return(true);
            }

            bool formerForceEditorModeSerialization = UnitySerializationUtility.ForceEditorModeSerialization;

            try
            {
                UnitySerializationUtility.ForceEditorModeSerialization = true;

                bool hasDirtyScenes = false;

                for (int i = 0; i < EditorSceneManager.sceneCount; i++)
                {
                    if (EditorSceneManager.GetSceneAt(i).isDirty)
                    {
                        hasDirtyScenes = true;
                        break;
                    }
                }

                if (hasDirtyScenes && !EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
                {
                    return(false);
                }

                var oldSceneSetup = EditorSceneManager.GetSceneManagerSetup();

                try
                {
                    for (int i = 0; i < scenePaths.Length; i++)
                    {
                        var scenePath = scenePaths[i];

                        if (showProgressBar && DisplaySmartUpdatingCancellableProgressBar("Scanning scenes for AOT support", "Scene " + (i + 1) + "/" + scenePaths.Length + " - " + scenePath, (float)i / scenePaths.Length))
                        {
                            return(false);
                        }

                        if (!System.IO.File.Exists(scenePath))
                        {
                            Debug.LogWarning("Skipped AOT scanning scene '" + scenePath + "' for a file not existing at the scene path.");
                            continue;
                        }

                        Scene openScene = default(Scene);

                        try
                        {
                            openScene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);
                        }
                        catch
                        {
                            Debug.LogWarning("Skipped AOT scanning scene '" + scenePath + "' for throwing exceptions when trying to load it.");
                            continue;
                        }

                        var sceneGOs = Resources.FindObjectsOfTypeAll <GameObject>();

                        foreach (var go in sceneGOs)
                        {
                            if (go.scene != openScene)
                            {
                                continue;
                            }

                            if ((go.hideFlags & HideFlags.DontSaveInBuild) == 0)
                            {
                                foreach (var component in go.GetComponents <ISerializationCallbackReceiver>())
                                {
                                    try
                                    {
                                        this.allowRegisteringScannedTypes = true;
                                        component.OnBeforeSerialize();

                                        var prefabSupporter = component as ISupportsPrefabSerialization;

                                        if (prefabSupporter != null)
                                        {
                                            // Also force a serialization of the object's prefab modifications, in case there are unknown types in there

                                            List <UnityEngine.Object> objs = null;
                                            var mods = UnitySerializationUtility.DeserializePrefabModifications(prefabSupporter.SerializationData.PrefabModifications, prefabSupporter.SerializationData.PrefabModificationsReferencedUnityObjects);
                                            UnitySerializationUtility.SerializePrefabModifications(mods, ref objs);
                                        }
                                    }
                                    finally
                                    {
                                        this.allowRegisteringScannedTypes = false;
                                    }
                                }
                            }
                        }
                    }

                    // Load a new empty scene that will be unloaded immediately, just to be sure we completely clear all changes made by the scan
                    // Sometimes this fails for unknown reasons. In that case, swallow any exceptions, and just soldier on and hope for the best!
                    // Additionally, also eat any debug logs that happen here, because logged errors can stop the build process, and we don't want
                    // that to happen.

                    UnityEngine.ILogger logger = null;

                    if (Debug_Logger_Property != null)
                    {
                        logger = (UnityEngine.ILogger)Debug_Logger_Property.GetValue(null, null);
                    }

                    bool previous = true;

                    try
                    {
                        if (logger != null)
                        {
                            previous          = logger.logEnabled;
                            logger.logEnabled = false;
                        }

                        EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
                    }
                    catch { }
                    finally
                    {
                        if (logger != null)
                        {
                            logger.logEnabled = previous;
                        }
                    }
                }
                finally
                {
                    if (oldSceneSetup != null && oldSceneSetup.Length > 0)
                    {
                        if (showProgressBar)
                        {
                            EditorUtility.DisplayProgressBar("Restoring scene setup", "", 1.0f);
                        }
                        EditorSceneManager.RestoreSceneManagerSetup(oldSceneSetup);
                    }
                }

                if (includeSceneDependencies)
                {
                    for (int i = 0; i < scenePaths.Length; i++)
                    {
                        var scenePath = scenePaths[i];
                        if (showProgressBar && DisplaySmartUpdatingCancellableProgressBar("Scanning scene dependencies for AOT support", "Scene " + (i + 1) + "/" + scenePaths.Length + " - " + scenePath, (float)i / scenePaths.Length))
                        {
                            return(false);
                        }

                        string[] dependencies = AssetDatabase.GetDependencies(scenePath, recursive: true);

                        foreach (var dependency in dependencies)
                        {
                            this.ScanAsset(dependency, includeAssetDependencies: false); // All dependencies of this asset were already included recursively by Unity
                        }
                    }
                }

                return(true);
            }
            finally
            {
                if (showProgressBar)
                {
                    EditorUtility.ClearProgressBar();
                }

                UnitySerializationUtility.ForceEditorModeSerialization = formerForceEditorModeSerialization;
            }
        }
예제 #22
0
 void ISerializationCallbackReceiver.OnBeforeSerialize()
 {
     UnitySerializationUtility.SerializeUnityObject(this, ref serializationData);
     _backingUdonBehaviourDump = _udonSharpBackingUdonBehaviour;
 }