mackysoft / Unity-SerializeReferenceExtensions

Provide popup to specify the type of the field serialized by the [SerializeReference] attribute in the inspector.
https://qiita.com/makihiro_dev/items/26daeb3e5f176934bf0a
MIT License
770 stars 59 forks source link

[IMPROVE] CustomPropertyDrawers not working #24

Closed ghost closed 1 year ago

ghost commented 1 year ago

Improvement destription

Here there,

amazing work! Unfortunately 'CustomPropertyDrawers' aren't working if I use the 'SubclassSelectorAttribute'. I tried to solve it but failed horribly. Do you have any idea how one might get them to work?

Greetings, Ben

mackysoft commented 1 year ago

Are you saying that SubclassSelectorAttribute cannot be used to display the type selection menu implemented in this library in the editor?

If so, the variable may have been serialized with a SerializeField instead of a SerializeReference attribute.

// Not work
[SerializeField, SubclassSelector]
IHoge m_Hoge1;

// It work
[SerializeReference, SubclassSelector]
IHoge m_Hoge2;

At least I make this mistake sometimes...

ghost commented 1 year ago

This is not exactly what I was going for. In Unity you may use CustomPropertyDrawer to build a custom inspector for classes which are serialized but do not derive from MonoBehaviour or ScriptableObject.

So consider the following example:

[Serializable]
public abstract class Food
{
    public string name;

    public float kcal;
}

[Serializable]
public class Apple : Food
{
    public Apple()
    {
        name = "Apple";
        kcal = 100f;
    }
}

[Serializable]
public class Peach : Food
{
    public Peach()
    {
        name = "Peach";
        kcal = 100f;
    }
}

public class Tester : MonoBehaviour
{
    [SerializeReference]
    public List<Food> foodsOne = new List<Food>
    {
        new Apple(),
        new Peach()
    };

    [SerializeReference,SubclassSelector]
    public List<Food> foodsTwo = new List<Food>
    {
        new Apple(),
        new Peach()
    };
}

/// These classes are in a folder named "Editor" in the project

    [CustomPropertyDrawer(typeof(Peach))]
    public class PeachDrawer : PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            EditorGUI.LabelField(position,"I'm a peach!");
        }
    }

    [CustomPropertyDrawer(typeof(Apple))]
    public class AppleDrawer : PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            EditorGUI.LabelField(position,"I'm an apple!");
        }
    }

As soon as I use the 'SubclassSelector' attribute the 'CustomPropertyDrawer's stop working. Check the picture below. So I was wondering whether there is a solution to this or not. Custom inspector for serialized non MonoBehaviour classes would be really nice

image

Greetings, Ben

mackysoft commented 1 year ago

OK, now I understand the problem. I will investigate.

NickMercer commented 1 year ago

I'd like to add to this that whatever Odin Inspector does with it's attributes (I assume it makes property drawers behind the scenes) gets wiped out by this too.

I just added the code from this PR: https://github.com/mackysoft/Unity-SerializeReferenceExtensions/pull/26 and it seems to fix the issue, with the only downside being the added .Value needed to get to the interface reference.

AnisimovArthur commented 1 year ago

Any updates? 🙂

mackysoft commented 1 year ago

Hey guys. Sorry, I have been unable to update OSS for a while.

I am currently working on this issue. Once we are sure that the behavior is stabilized, I will merge the pull request and create a new release.

image

using System.Collections.Generic;
using System;
using UnityEditor;
using UnityEngine;

[Serializable]
public abstract class Food
{
    public string name;

    public float kcal;
}

[Serializable]
public class Apple : Food
{
    public Apple ()
    {
        name = "Apple";
        kcal = 100f;
    }
}

[Serializable]
public class Peach : Food
{
    public Peach ()
    {
        name = "Peach";
        kcal = 100f;
    }
}

[Serializable]
public class Grape : Food
{
    public Grape ()
    {
        name = "Grape";
        kcal = 100f;
    }
}

public class Example : MonoBehaviour
{

    [SerializeReference]
    public Food food1 = new Apple();

    [SerializeReference]
    public Food food2 = new Peach();

    [SerializeReference]
    public Food food3 = new Grape();

    [SerializeReference, SubclassSelector]
    public Food foodOne = new Apple();

    [SerializeReference, SubclassSelector]
    public Food foodTwo = new Peach();

    [SerializeReference, SubclassSelector]
    public Food foodThree = new Grape();

    [SerializeReference]
    public List<Food> foodsOne = new List<Food>
    {
        new Apple(),
        new Peach(),
        new Grape()
    };

    [SerializeReference, SubclassSelector]
    public List<Food> foodsTwo = new List<Food>
    {
        new Apple(),
        new Peach(),
        new Grape()
    };
}

#if UNITY_EDITOR

/// These classes are in a folder named "Editor" in the project

[CustomPropertyDrawer(typeof(Peach), true)]
public class PeachDrawer : PropertyDrawer
{
    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {
        position.height = EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(position, property.FindPropertyRelative("name"));

        position.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
        EditorGUI.PropertyField(position, property.FindPropertyRelative("kcal"));
    }

    public override float GetPropertyHeight (SerializedProperty property, GUIContent label)
    {
        return EditorGUIUtility.singleLineHeight * 2 + EditorGUIUtility.standardVerticalSpacing * 1;
    }
}

[CustomPropertyDrawer(typeof(Apple), true)]
public class AppleDrawer : PropertyDrawer
{
    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.LabelField(position, "I'm an apple!");
    }

    public override float GetPropertyHeight (SerializedProperty property, GUIContent label)
    {
        return EditorGUIUtility.singleLineHeight;
    }
}
#endif
mackysoft commented 1 year ago

Version 1.1.9 is now available ! https://github.com/mackysoft/Unity-SerializeReferenceExtensions/releases/tag/1.1.9