I am creating a custom drawer for a custom attribute that helps me initialize the value of a field marked with the attribute SerializeReference.
Basically, the custom drawer will show a dropdown menu that allows me to select the Type to create and assign to the field.
I have the following code so far, to test the different scenarios:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var targetObject = property.serializedObject.targetObject;
var field = targetObject.GetType().GetField(property.name, FieldBindingFlags)!;
if (field.GetValue(targetObject) == null)
field.SetValue(targetObject, new OperaSinger());
else
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndProperty();
}
}
And those are the test classes:
interface ISinger
{
void Sing();
}
[System.Serializable]
class OperaSinger : ISinger
{
[SerializeField] private string name;
void Sing(){}
}
class StreetPerformer : MonoBehaviour, ISinger
{
[SerializeField] private string streetName;
void Sing(){}
}
The above code seems to work fine, it initializes the property to a new instance of the OperaSinger and shows the editor.
But, when I try to do the same with the MonoBehaviour implementation, I get an error:
Attempt #1:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var targetObject = property.serializedObject.targetObject;
var field = targetObject.GetType().GetField(property.name, FieldBindingFlags)!;
if (field.GetValue(targetObject) == null)
{
var x = ((Component)targetObject).gameObject.AddComponent<StreetPerformer>();
field.SetValue(targetObject, x);
}
else
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndProperty();
}
}
Error: [SerializeReference] cannot serialize objects that derive from Unity.Object.
Attempt #2:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var targetObject = property.serializedObject.targetObject;
var field = targetObject.GetType().GetField(property.name, FieldBindingFlags)!;
if (field.GetValue(targetObject) == null)
{
var x = ((Component)targetObject).gameObject.AddComponent<StreetPerformer>();
property.objectReferenceValue = x;
}
else
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndProperty();
}
}
Error: type is not a supported pptr value
Attempt #3:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var targetObject = property.serializedObject.targetObject;
var field = targetObject.GetType().GetField(property.name, FieldBindingFlags)!;
if (field.GetValue(targetObject) == null)
{
var x = ((Component)targetObject).gameObject.AddComponent<StreetPerformer>();
property.objectReferenceInstanceIDValue = x.GetInstanceID();
}
else
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.PropertyField(position, property, label, true);
EditorGUI.EndProperty();
}
}
Error: type is not a supported pptr value
What am I doing wrong, and how can I fix it?
As far as I understand, the error from attempts 2 and 3 is because the field is defined as the interface type ISinger.