Applying a PropertyDrawer to elements of a List<>

I have set up a PropertyDrawer, and it works for single elements:

public class ResourceReferenceAttribute : PropertyAttribute
{
    public ResourceReferenceAttribute()
    {
    }
}

[CustomPropertyDrawer(typeof(ResourceReferenceAttribute))]
public class ResourceReferenceDrawer : PropertyDrawer
{
    public override void OnGUI(Rect pos,
                                SerializedProperty prop,
                                GUIContent label)
    {
        Object obj = AssetDatabase.LoadMainAssetAtPath(prop.stringValue);
        Object newObj = EditorGUI.ObjectField(pos, label, obj, typeof(GameObject), false);
        if (obj != newObj)
        {
            prop.stringValue = AssetDatabase.GetAssetPath(newObj);
        }
    }
}

[ResourceReference] public string healthyString;

Which works as you would expect.

I would also like to apply this to arrays of items, but am having no luck:

[ResourceReference] public List<string> rootSoundsPaths = new List<string>();

The result of this is that I get the entire array field replaced in the Inspector with an ObjectField, and an error occurs, complaining that there’s no prop.stringValue.

While researching this, I came across this post on the forums that suggests that this ought to be possible.

I have tried changing rootSoundsPaths to be of type string[], but no change. It’s also possible this is breaking because this is a defined within a nested serialized class, but that seems to be clutching at straws…

The reason you got the error at prop.stringvalue is that prop wasn’t a string; it was an array. So after a few tweaks and Unity crashes, I managed to get this cobbled together. It’s not pretty; all the rects overlap eachother… but it works, at least for the List. Didn’t check if it worked for the actual string…

[CustomPropertyDrawer(typeof(ResourceReferenceAttribute))]
    public class ResourceReferenceDrawer : PropertyDrawer
{
	List<string> debugList = new List<string>();
	int index = 0;
	public override void OnGUI (Rect pos,
    SerializedProperty prop,
    GUIContent label)
	{
		index = EditorGUI.IntField(pos,"Size:",index);
		
		if(prop.isArray && index > 0){
			while(index > prop.arraySize)
				prop.InsertArrayElementAtIndex(prop.arraySize);
			while(index < prop.arraySize)
				prop.DeleteArrayElementAtIndex(prop.arraySize-1);
		}
		
		if(prop.arraySize>0){
			for(int i = 0; i<prop.arraySize;i++){
				Object obj = AssetDatabase.LoadMainAssetAtPath (prop.GetArrayElementAtIndex(i).stringValue);
				Object newObj = EditorGUI.ObjectField (pos, label, obj, typeof(GameObject), false);
				if (obj != newObj) {
					prop.GetArrayElementAtIndex(i).stringValue = AssetDatabase.GetAssetPath (newObj);
				}
				debugList.Add(prop.GetArrayElementAtIndex(i).stringValue);
				pos.y += 20;
			}
		}
		if(!prop.isArray || prop.arraySize == 0){
			Object newObj = null;
			newObj = EditorGUI.ObjectField (pos, label, newObj, typeof(GameObject), false);
			if (newObj != null) {
				prop.InsertArrayElementAtIndex(0);
				prop.GetArrayElementAtIndex(0).stringValue = AssetDatabase.GetAssetPath (newObj);
			}			
		}
		foreach(string s in debugList)
			Debug.Log(s);
		debugList.Clear();
	}
}