0
\$\begingroup\$

Is there a way to access info about the script that a PropertyAttribute is part of in Unity? In my case: getting the memberInfos of the script:

class MyBehavior : MonoBehavior 
{
   [MyAttribute] public float dog;
   public float cat;
   //I want "myAttribute" to be able to know about the "cat" float.
}

I want to recreate SirenX Odin Inspector's TabGroup and other render-by-group attributes and am wondering how to go about it in a path-of-least-resistance way.

My plan was to have a [LabelTag(string label)] which amassed all relevant members via reflection and then renders them in one go in OnGUI(){}. But the declaringType of the property attributes are returning null so I'm at a loss.

[CustomPropertyDrawer(typeof(MyAttribute))]
public class MyDrawer : DecoratorDrawer 
{
  public override void OnGUI(Rect position)
  {
     GroupLabel groupLabel = (GroupLabel) attribute;
     Type attribType = attribute.GetType();
     Type declaringType_ISNULL = attribType.DeclaringType;
     //declaring type is null
  }
}

The only other solution I can think of is using something like sourceGenerators to autogenerate editor windows based off these attributes on the fly. While Unity doesn't support sourceGenerators yet, there's probably some equivalent more hacky thing I can do to insert myself into the editor build pipeline, but that seems like more hassle and potential jankinesss then I'm willing to attempt.

If anybody has any suggestions, or any insights into how SirenX Odin Inspector achieved this, that would be great!

Thanks.

\$\endgroup\$
1

1 Answer 1

1
\$\begingroup\$

You want the declaring type of the field that uses the attribute, not the declaring type of the attribute itself. (The attribute type is defined in its own class file, so it has no tie back to the many different classes that might reference it)

Here's a quick & dirty demo of this, gathering up field names that occur after the label but before a different label:

[System.AttributeUsage(System.AttributeTargets.Field)]
public class GroupLabelAttribute : PropertyAttribute
{
    public string label;
    public GroupLabelAttribute(string label) {
        this.label = label;
    }
}

[CustomPropertyDrawer(typeof(GroupLabelAttribute))]
public class GroupLabelDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {    
        var fields = fieldInfo.DeclaringType.GetFields();

        string names = fieldInfo.Name;

        int start = System.Array.IndexOf(fields, fieldInfo);
        int end = start;
        for (int i = start + 1; i < fields.Length; i++) {
            if (fields[i].GetCustomAttribute(typeof(GroupLabelAttribute)) != null)
                break;
            names += ", " + fields[i].Name;
            end++;
        }

        // Now we know the range of fields start to end that belong under this group.
        // For a quick demo, we'll just print out their names in place of the field:
        EditorGUI.LabelField(position,
            ((GroupLabelAttribute)attribute).label 
            + "->" + fieldInfo.DeclaringType.ToString()
            + ":" + names);   
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ I was only using a decorator drawer which only had access to the attribute and nothing actually declared in the script. I didn't realize A PropertyDrawer is more powerful in this way. \$\endgroup\$
    – Charly
    Nov 24, 2021 at 13:16
  • \$\begingroup\$ Ah, that would be good information to include in your question. I had to try to guess at what you were doing since you didn't show that part. \$\endgroup\$
    – DMGregory
    Nov 24, 2021 at 13:18
  • \$\begingroup\$ Could you show getting the SerializedProperties of the members on the declared type via reflection? I'm struggling to accomplish this -- getting the serializedProperties on anything that isn't relative to the one given to me in OnGUI(). I'm not sure how (or if it's possible) to get the value of the declared type via reflection. \$\endgroup\$
    – Charly
    Nov 26, 2021 at 4:55
  • \$\begingroup\$ Presumably you tried SerializedProperty.Next() to iterate over the members? If you're having trouble with it, please consider posting a new question about this specifically. \$\endgroup\$
    – DMGregory
    Nov 26, 2021 at 5:03
  • \$\begingroup\$ Didn't realize serializedProperty had a reference to the serializedObject that it was contained in... \$\endgroup\$
    – Charly
    Nov 26, 2021 at 13:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .