Custom PropertyDrawer fails because my ScriptableObject property is not initialized in time

Hi! I try to made a custom property drawer to have a 2D grid in the inspector (I need a 3D grid actually, like a voxel buffer).

I have 3 ScriptableObjects :

  • Level,
  • TileGrid,
  • Tile,

Each level has a reference to a tilegrid. I want the grid displaying in the inspector on level ‘.asset’ file selection, so I made a custom PropertyDrawer related to TileGrid class.

My issue is that, when my OnGUI method is executed, an error raises when the program trying to access to a serialized property of tilegrid instance: the error say that there is no tilegrid instance. In my opinion, this is because my level instance has no correct default tilegrid value (null).

I noticed that, when I select a ‘.asset’ level file in Unity Editor, the OnGUI function is executed before the OnEnable method of TileGrid (this is where I initialize the default tilegrid value and I don’t see how to do it differently). Is someone has a solution about this?

EDIT: Confusion of mine, OnEnable is called only on object load. So how to define default ScriptableObject properties values inside an other ScriptableObject ? Is it even possible ?

Tile :

 [System.Serializable]
[CreateAssetMenu (menuName ="Gamedata/Tile")]
public class Tile : ScriptableObject 
{
    public string meshFile;
    public string textureFile;
}

TileGrid :

 [System.Serializable]
    public class TileGrid : ScriptableObject
    {
    public int dimX = 4;
    public int dimY = 4;
    private int dimZ = 1;

    public Tile[,,] tiles;

    void OnEnable()
    {
        if(tiles == null)
        {
            tiles= new Tile[dimX, dimY, dimZ];
            for(int z =0; z<dimZ; z++) {
                for(int y = 0; y<dimY; y++) {
                    for(int x = 0; x<dimX; x++) {
                        tiles[x, y, z] = ScriptableObject.CreateInstance<Tile>();
                    }
                }
            }
        }
    }
}

Level:

 [CreateAssetMenu(menuName = "Gamedata/Level")]
    public class Level : ScriptableObject {
    
        public TileGrid grid;

void OnEnable()
{
        if (grid == null)
            grid = ScriptableObject.CreateInstance<TileGrid>();
}

Custom PropertyDrawer:

[CustomPropertyDrawer(typeof(TileGrid))]
public class TileGridProperty : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.PrefixLabel(position, label);

        int dimX = property.FindPropertyRelative("dimX").intValue; // ERROR occurs
        int dimY = property.FindPropertyRelative("dimY").intValue;
        int dimZ = property.FindPropertyRelative("dimZ").intValue;

        position.y += 18f;
        position.width /= dimX;
        position.height /= dimY;

        SerializedProperty tileGrid = property.FindPropertyRelative("tileGrid");
        for(int z=0; z < dimZ; z++) {
            SerializedProperty arrayZ = tileGrid.GetArrayElementAtIndex(z);
            for(int y=0; y < dimY; y++)  {
                SerializedProperty arrayY = arrayZ.GetArrayElementAtIndex(y);
                for(int x=0; x < dimX; x++) {
                    SerializedProperty arrayX = arrayY.GetArrayElementAtIndex(x);

                    SerializedProperty tile = arrayX.GetArrayElementAtIndex(0);
                    EditorGUI.PropertyField(position, tile, GUIContent.none);
                }
            }
        }
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return 18f;
    }
}

For anyone else who finds this issue

SerializedObject obj = new SerializedObject(property.objectReferenceValue);
var prop= obj.FindProperty(“propName”);