Editor/TypeSelectAttributeExtensions.cs
using ExtendedEditor.Attributes;
using Sandbox;
using System;
using System.Linq;
using System.Reflection;
namespace ExtendedEditor;
public static class TypeSelectAttributeExtensions
{
extension(TypeSelectAttribute attribute)
{
public MethodInfo? FindValidatorMethod(SerializedProperty property, out object? target)
{
if(property.IsMultipleValues)
throw new InvalidOperationException("Property targeting multiple values is not supported.");
target = null;
if(attribute.ValidatorName is null)
return null;
var parent = property.Parent;
if(parent is null)
return null;
Type? parentType = TypeLibrary.GetType(property.Parent.TypeName)?.TargetType;
var parentProperty = parent.ParentProperty;
target = parentProperty?.GetValue<object>() ?? parent.Targets.FirstOrDefault();
if(parentType is null)
{
if(parentProperty is not null)
parentType = parentProperty.IsNullable ? parentProperty.NullableType : parentProperty.PropertyType;
}
parentType ??= target?.GetType();
if(parentType is null)
return null;
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy;
if(target is not null)
flags |= BindingFlags.Instance;
var method = parentType.GetMethods(flags).FirstOrDefault(x =>
x.Name == attribute.ValidatorName &&
x.GetParameters().Length == 1 &&
x.GetParameters()[0].ParameterType == typeof(Type) &&
x.ReturnType == typeof(bool));
if(method?.IsStatic ?? true)
target = null;
return method;
}
public void FindAndAppendValidatorMethod(SerializedProperty serializedProperty)
{
var validatorMethod = attribute.FindValidatorMethod(serializedProperty, out var target);
if(validatorMethod is null)
{
attribute.ValidatorName = null;
return;
}
var oldValidator = attribute.Validator;
attribute.Validator = t =>
{
if(!(oldValidator?.Invoke(t) ?? true))
return false;
return (bool)validatorMethod?.Invoke(target, [t])!;
};
attribute.ValidatorName = null;
}
}
}