Serializable settings for custom PropertyDrawer

Setup

I have constructed a custom PropertyDrawer for a custom PropertyAttribute to create something similar to the RangeAttribute, but for all data types. My PropertyDrawer requires an int to draw the inspector UI because ‘the int’ dictates the UI. In most other PropertyDrawers you can assume the data type under the attribute (i.e. float, Vector2, etc.) and have the PropertyDrawer read and write to that data type.

###Question###

However, I can’t assume the data type because I’d like this attribute to be available for all data types. Therefore, I can’t store ‘the int’ in the method mentioned above. I need a way to serialize ‘the int’ so that it persists through assembly reload and Unity closing. Got any ideas?

###Attempts###

  • Creating a serializable ScriptableObject class to hold ‘the int’ and reference that in either my custom PropertyDrawer or PropertyAttribute.
  • Throw around [SerializeField] and [Serializable] attributes on ‘the int’ and PropertyDrawer and PropertyAttribute classes
  • Try to learn more about serialization, but PropertyDrawers or PropertyAttributes are never mentioned.

###Example###

  public class MyBehavior : MonoBehaviour
{
    [My]
    public Vector2 data1;

    [My(2)]
    public SomeSerializedClass data2;
}

[AttributeUsage(AttributeTargets.Field)]
public class MyAttribute : PropertyAttribute
{
    public int value;  // what needs to be serialized

    public MyAttribute(int startingValue = 1)
    {
        value = startingValue;
    }
}

[CustomPropertyDrawer(typeof(MyAttribute))]
public class MyDrawer : PropertyDrawer
{
    private int value;  // or maybe this can be serialized instead?

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        var attr = attribute as MyAttribute;
        value = attr.value;

        // Here I need `value` to be persistent upon Unity open/close
        //   and script reloading, hence the issue.
        value = EditorGUI.IntSlider(position, value, 1, 2);

        // ... draw `property` based on `value` ...
    }
}

value must be serialized within MyAttribute or MyDrawer due to value’s independence on property’s underlying type.


Please let me know what I need to clarify. Thanks for any help! :slight_smile:

I’m not 100% clear what you’re trying to do, but depending what meets your needs, I would recommend one of the following (in order of decreasing recommendation):

  1. Use property.propertyType to find out what type of field you’re drawing and respond accordingly
  2. Use PropertyDrawer.fieldInfo to find out exactly what field you’re drawing and respond accordingly
  3. Use PropertyDrawer.attribute to find out metadata for the field you’re drawing and respond accordingly

To clarify case 3, it would look something like this:

public enum MyCustomMetadata { Something, SomethingElse, AndSoOn }

public class MyCustomAttribute : PropertyAttribute {
    public readonly MyCustomMetadata CustomMetadata;
    public MyCustomAttribute(MyCustomMetadata customMetadata) {
        CustomMetadata = customMetadata;
    }
}

public class MyBehavior : MonoBehaviour {
    [SerializeField, MyCustomAttribute(MyCustomMetadata.Something)]
    private int m_MyIntField;
}

[CustomPropertyDrawer(typeof(MyCustomAttribute))]
public class MyCustomDrawer : PropertyDrawer {
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
        MyCustomMetadata customMetadata = (attribute as MyCustomAttribute).CustomMetadata;
        // do something based on value of customMetadata
    }
}