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; } } }
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()); }