Esempio n. 1
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;
                }
            }
        }
Esempio n. 2
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());
        }