-
-
Save oxysoft/b790dba3125b3ae36535f52e4469e65d to your computer and use it in GitHub Desktop.
#if UNITY_EDITOR | |
using System; | |
using System.Linq; | |
using OdinExtensions; | |
using Sirenix.OdinInspector.Editor; | |
using Sirenix.OdinInspector.Editor.Validation; | |
using Sirenix.Serialization; | |
using UnityEngine; | |
using Object = UnityEngine.Object; | |
[assembly: RegisterValidator(typeof(AllRequiredValidator), Priority = 500)] | |
namespace OdinExtensions | |
{ | |
/// <summary> | |
/// Makes all fields that take an object to be REQUIRED by default. | |
/// An 'OptionalAttribute' can be used to make objects optional. | |
/// | |
/// Built-in unity types and other plugins things should not be included, | |
/// as they can often introduce random errors since they were not designed | |
/// with this in mind. | |
/// | |
/// Use the whitelist to select namespaces to include. | |
/// You can also use the blacklist to block subsections | |
/// of the whitelist. | |
/// </summary> | |
public class AllRequiredValidator : Validator | |
{ | |
public override RevalidationCriteria RevalidationCriteria => RevalidationCriteria.OnValueChange; | |
// CUSTOMIZABLE WHITELIST (namespaces) | |
// ---------------------------------------- | |
private static readonly string[] Whitelist = | |
{ | |
// Fill me up | |
"Demo" | |
}; | |
// CUSTOMIZABLE BLACKLIST (namespaces) | |
// ---------------------------------------- | |
private static readonly string[] Blacklist = | |
{ | |
// Fill me up | |
}; | |
private static bool IsTypeSupported(Type type) | |
{ | |
string typeNamespace = type.Namespace; | |
if (typeNamespace == null) | |
return false; | |
return Whitelist.Any(w => typeNamespace.StartsWith(w)) && | |
!Blacklist.Any(b => typeNamespace.StartsWith(b)); | |
} | |
private static bool IsValid(IPropertyValueEntry valueEntry) | |
{ | |
object v = valueEntry?.WeakSmartValue; | |
if (v == null) return false; | |
if (v is Object o && o == null) return false; | |
if (v is string s && string.IsNullOrEmpty(s)) return false; | |
return true; | |
} | |
public override void RunValidation(ref ValidationResult result) | |
{ | |
if (Property.ValueEntry == null) return; | |
if (Property.Name.StartsWith("$")) return; | |
if (result == null) | |
{ | |
result = new ValidationResult | |
{ | |
Setup = new ValidationSetup | |
{ | |
Root = Property.SerializationRoot.ValueEntry.WeakValues[0] as Object, | |
Member = Property.Info.GetMemberInfo(), | |
Validator = this | |
}, | |
ResultType = ValidationResultType.Valid | |
}; | |
} | |
// Check to see that this property is allowed for AllRequired | |
Type parentType = Property.ParentType; | |
if (!IsTypeSupported(parentType)) | |
return; | |
// Apply the result | |
if (IsValid(Property.ValueEntry)) | |
{ | |
result.ResultType = ValidationResultType.Valid; | |
result.Message = null; | |
} | |
else | |
{ | |
if (Property.GetAttribute<OptionalAttribute>() != null) | |
return; | |
result.ResultType = ValidationResultType.Error; | |
result.Message = $"'{Property.Name}' must be assigned. All public values are serialized in Unity. Values which are not meant for configuration must be marked with NonSerialized."; | |
} | |
} | |
public override bool CanValidateProperty(InspectorProperty property) | |
{ | |
bool is_public_field = property.Info.IsEditable && property.Info.HasBackingMembers; | |
bool serialized_attr = property.GetAttribute<SerializeField>() != null; | |
bool serialized_attr_odin = property.GetAttribute<OdinSerializeAttribute>() != null; | |
return is_public_field || serialized_attr || serialized_attr_odin; | |
} | |
} | |
} | |
#endif | |
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] | |
public class OptionalAttribute : Attribute | |
{ } |
Does not work with new version of Odin
@funnymanwin got an updated version somewhat working:
Odin version: 3.1.8 (~ 2022/12/01)
using UnityEngine;
using Sirenix.OdinInspector.Editor;
using Sirenix.OdinInspector;
using System.Collections.Generic;
using System;
using System.Reflection;
using Sirenix.Serialization;
/// <summary>
/// Makes every nullable property field show an Error warning in inspector if null.
/// Can be overriden by using <see cref="OptionalAttribute"/>
/// </summary>
/// <typeparam name="T"></typeparam>
public class DefaultRequiredAttributeProcessor<T> : OdinAttributeProcessor<T>
{
public override void ProcessChildMemberAttributes(
InspectorProperty parentProperty,
MemberInfo member,
List<Attribute> attributes)
{
// These attributes will be added to all of the child elements.
if (member.GetCustomAttribute<OptionalAttribute>() == null &&
member.GetCustomAttribute<NonSerializedAttribute>() == null &&
(member.GetCustomAttribute<SerializeField>() != null ||
member.GetCustomAttribute<OdinSerializeAttribute>() != null)
)
{
attributes.Add(new RequiredAttribute("Missing value", InfoMessageType.Error));
}
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
/// OURS ! USE THIS ONE.
public class OptionalAttribute : Attribute
{ }
@funnymanwin got an updated version somewhat working: Odin version: 3.1.8 (~ 2022/12/01)
using UnityEngine; using Sirenix.OdinInspector.Editor; using Sirenix.OdinInspector; using System.Collections.Generic; using System; using System.Reflection; using Sirenix.Serialization; /// <summary> /// Makes every nullable property field show an Error warning in inspector if null. /// Can be overriden by using <see cref="OptionalAttribute"/> /// </summary> /// <typeparam name="T"></typeparam> public class DefaultRequiredAttributeProcessor<T> : OdinAttributeProcessor<T> { public override void ProcessChildMemberAttributes( InspectorProperty parentProperty, MemberInfo member, List<Attribute> attributes) { // These attributes will be added to all of the child elements. if (member.GetCustomAttribute<OptionalAttribute>() == null && member.GetCustomAttribute<NonSerializedAttribute>() == null && (member.GetCustomAttribute<SerializeField>() != null || member.GetCustomAttribute<OdinSerializeAttribute>() != null) ) { attributes.Add(new RequiredAttribute("Missing value", InfoMessageType.Error)); } } } [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] /// OURS ! USE THIS ONE. public class OptionalAttribute : Attribute { }
What does "somewhat" mean in this instance? XD
I understood why it doesn't work with new version of Odin inspector!
After one of updates Odin Inspector split up to Odin inspector and Odin validator. All validation functionality was removed from Odin Inspector. And now if you want to have validation addons like this you must pay another $45! Totally Odin Inspector and Validator cost almost $100. Now it became so expensive...
I updated your code. Compatible with new versions of Odin. Anyway u will not read this, because you abandoned this script long time ago. So I hope somebody will say thanks to me (i spent a lot of hours trying to fix it):
#if UNITY_EDITOR
using System;
using System.Linq;
using OdinExtensions;
using Sirenix.OdinInspector.Editor;
using Sirenix.OdinInspector.Editor.Validation;
using Sirenix.Serialization;
using UnityEngine;
using UnityEngine.AddressableAssets;
using Object = UnityEngine.Object;
[assembly: RegisterValidator(typeof(AllRequiredValidator), Priority = 500)]
namespace OdinExtensions
{
/// <summary>
/// Makes all fields that take an object to be REQUIRED by default.
/// An 'OptionalAttribute' can be used to make objects optional.
///
/// Built-in unity types and other plugins things should not be included,
/// as they can often introduce random errors since they were not designed
/// with this in mind.
///
/// Use the whitelist to select namespaces to include.
/// You can also use the blacklist to block subsections
/// of the whitelist.
/// </summary>
public class AllRequiredValidator : Validator
{
public override RevalidationCriteria RevalidationCriteria => RevalidationCriteria.OnValueChange;
private static bool IsValid(IPropertyValueEntry valueEntry)
{
object v = valueEntry?.WeakSmartValue;
if (v == null) return false;
if (v is Object o && o == null) return false;
if (v is string s && string.IsNullOrEmpty(s)) return false;
if (v is AssetReference assetReference && !assetReference.RuntimeKeyIsValid()) return false;
return true;
}
public override void RunValidation(ref ValidationResult result)
{
if (Property.ValueEntry == null) return;
if (Property.Name.StartsWith("$")) return;
if (result == null)
{
result = new ValidationResult
{
Setup = new ValidationSetup
{
Root = Property.SerializationRoot.ValueEntry.WeakValues[0] as Object,
ParentInstance = Property.Parent,
//Member = Property.Info.GetMemberInfo(),
Validator = this
},
ResultType = ValidationResultType.Valid
};
}
// Apply the result
if (IsValid(Property.ValueEntry))
{
result.ResultType = ValidationResultType.Valid;
result.Message = null;
}
else
{
if (Property.GetAttribute<OptionalAttribute>() != null)
return;
result.ResultType = ValidationResultType.Error;
result.Message = $"'{Property.Name}' must be assigned. All public values are serialized in Unity. Values which are not meant for configuration must be marked with NonSerialized.";
}
}
public override bool CanValidateProperty(InspectorProperty property)
{
bool is_public_field = property.Info.IsEditable && property.Info.HasBackingMembers;
bool serialized_attr = property.GetAttribute<SerializeField>() != null;
bool serialized_attr_odin = property.GetAttribute<OdinSerializeAttribute>() != null;
return is_public_field || serialized_attr || serialized_attr_odin;
}
}
}
#endif
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class OptionalAttribute : Attribute
{ }
Or you can just download final version as Unity Package with MiniValidationDrawer.cs from my Google Drive:
https://drive.google.com/file/d/1i1Kmzrd8fikuAZqnFYe4-jsAnwO_YnHO/view?usp=sharing
AllRequiredValidator
An Odin Validator which will make everything
[Required]
by default. A new[Optional]
attribute is added instead to flip the logic.Usage
These screenshots use the MiniValidationDrawers