Help with SerializedProperty.ObjectReferenceValue

I having an issue with setting the object reference value of a serialized property inside a property drawer. My idea is to have a scriptable object representing an event with a list of “Blocks”. These “Blocks” derive from an abstracts class named EventBlockBase that inherits from Scriptable Object. I can assign them manually without issue, but trying to set them by code with:

serializedProperty.objectReferenceValue = someObject;

simply doesn’t work for some reason. My idea is to have a dropdown where you can select the type of block and change the corresponding element type.

alt text

Again, setting it manually works fine, but the objective of the script is to automate and facilitate the process. After debugging the whole thing from start to end, my conclusion is that everything is working as it should, except when I try to set the objectReferenceValue of the property. No matter what I try to set the reference to, it always become null in the end for reasons beyond my knowledge. The only thing that seems to work (and does not result in a null value in the end) is something idiotic like:

property.objectReferenceValue = property.objectReferenceValue;

I’ve tried multiple tests like temporarily removing the abstraction of the EventBlockBase class, creating a new field of GameObject type in it and attempting to set this property, instantiating a new ScriptableObject in the code and trying to assign it to the serialized property, and others tests which I don’t recall now. Nothing seems to work as the property becomes null after being assigned anything.

Here’s the snippet for the problematic code:

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
    //This checks serve to avoid repaint issues while dragging the reorderable list
    if(Event.current.type == EventType.MouseDrag)
    {
        _reordering = true;
    }
    else if(Event.current.type == EventType.Layout)
    {
        _reordering = false;
    }

    if (!_reordering)
    {
        EditorGUILayout.BeginVertical();
        {
            position = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);

            List<string> options = new List<string>();

            for (int i = 0; i < _blockTypes.Count; i++)
            {
                options.Add(_blockTypes*.Script.name);*

}

int _selectedBlockType = 0;
if (property.objectReferenceValue != null)
{
for (int i = 0; i < _blockTypes.Count; i++)
{
if (property.objectReferenceValue.GetType().ToString().Equals(options*))*
{
_selectedBlockType = i;
}
}
}

int newSelection = EditorGUI.Popup(position, “Block Type”, _selectedBlockType, options.ToArray());

if (_selectedBlockType != newSelection && newSelection != 0)
{
System.Type blockType = _blockTypes[newSelection].Script.GetClass(); //Working OK

ConstructorInfo constructor = blockType.GetConstructor(System.Type.EmptyTypes);
Object new_block = (Object) constructor.Invoke(null); //Creates Object Without Issue

property.objectReferenceValue = new_block; //Despite the Object | new Object | new ScriptableObject | new GameObject not being null. The property.objectReferenceValue always becomes null!
}

position = new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight, position.width, EditorGUIUtility.singleLineHeight);
EditorGUI.PropertyField(position, property);
}
EditorGUILayout.EndVertical();
}
else
{
EditorGUI.PropertyField(position, property);
}
}
Does anyone have any idea why setting the serialized property makes it become null?

You use reflection to manually invoke the constructor of your class. However scriptable objects can not be created with “new” since they are wrapper objects for native C++ objects like all classes derived from UnityEngine.Object. If you want to create an instance of a ScriptableObject you have to use ScriptableObject.CreateInstance.

Apart from that keep in mind that scriptable objects are standalone assets. You can create them in memory but if you want them to persist you have to actually create an asset and store it in your project using the AssetDatabase. Creating them in memory and trying to store a reference to such an instance on disk won’t work. That reference will be lost since the object you try to reference is not serialized at all.

Hi @Bunny83. Curiously I’m using your Logic Parser on this project. It is working wonders!

I’ve tried using the ScriptableObject.CreateInstance, but again when I try to set the property it becomes null. If I understand correctly, the problem is that I’m trying to assign the property with an asset I created on memory?

Indeed the issue was that the objects being assigned to the property were memory only. I changed the code to use temporary files that are saved to the disc and now everything is working fine.

System.Type blockType = _blockTypes[newSelection].GetClass();

ScriptableObject temporaryObject = ScriptableObject.CreateInstance(blockType);
AssetDatabase.CreateAsset(temporaryObject, pathToTemporaryFile);

serializedProperty.objectReferenceValue = temporaryObject;