How to initialize a jagged array of Scriptable Objects

I’m trying to initialize jagged array of Scriptable Objects because I am getting the null reference error. But, I can’t figure out how to do that.

public Weapon_Overview[][] WeaponGroups = new Weapon_Overview[8][];// This is the jagged array that is null

//Seperate Script
//WeaponGroupHolder is the script containing the WeaponGroups variable
for (int group = 0; group < WeaponGroupHolder.WeaponGroups.Length; group++)
{
       for (int weapon = 0; weapon < GetWeaponGroupLength(group); weapon++)
       {
                //Unimportant code
       }
}

public int GetWeaponGroupLength(int group)
{
   WeaponGroupHolder.GroupSize = WeaponGroupHolder.WeaponGroups[group].Length;//This is that part that is returning the error when it runs
        return WeaponGroupHolder.GroupSize;
}

A jagged array is literally an array of references to arrays.

You have to initialize every single array in the primary array:

int length = 5;
int subLength = 10;
Weapon_Overview[][] jagged = new Weapon_Overview[5][];
for (int i = 0; i < jagged.Length; i++) {
    jagged[i] = new Weapon_Overview[subLength];
}

I already have.

 public Weapon_Overview[] Revolvers;
    public Weapon_Overview[] Pistols;
    public Weapon_Overview[] Smgs;
    public Weapon_Overview[] Shotguns;
    public Weapon_Overview[] Rifles;
    public Weapon_Overview[] AssaultRifles;
    public Weapon_Overview[] SubWeapons;
    void Awake()
    {
        if (instance == null)
            instance = this;
        Revolvers = new Weapon_Overview[2];
        Pistols = new Weapon_Overview[2];
        Smgs = new Weapon_Overview[2];
        Shotguns = new Weapon_Overview[2];
        Rifles = new Weapon_Overview[2];
        AssaultRifles = new Weapon_Overview[2];
        SubWeapons = new Weapon_Overview[2];
        WeaponGroups = new Weapon_Overview[][] { Revolvers, Pistols, Smgs, Shotguns, Rifles, AssaultRifles, SubWeapons };
    }

Need to see where and how this WeaponGroups array is declared. and where and how the code from the first post is running.

WeaponsGroup is declared in it’s own script with the same code as the second post.

public class WeaponStoreValues : ScriptableObject
{
    public Weapon_Overview[][] WeaponGroups = new Weapon_Overview[8][];
}

The first post is a monobehavior script.

public class LocalStoreManagerScript : MonoBehaviour
{
public WeaponStoreValues WeaponGroupHolder;
//This method is called in Update()
public void WeaponGroupHandler(int[][]weaponGroups, int currentWeaponGroup, int currentWeaponInGroup)
    {
//These local variables are irrelevant, might change it.
        this.weaponGroups = weaponGroups;
        this.currentWeaponGroup = currentWeaponGroup;
        this.currentWeaponInGroup = currentWeaponInGroup;
       
        for (int group = 0; group < WeaponGroupHolder.WeaponGroups.Length; group++)
        {
            for (int weapon = 0; weapon < GetWeaponGroupLength(group); weapon++)
//GetWeaponGroupLength is the same as the first post, where the error is returned
            {
                if(WeaponGroupHolder.WeaponGroups[group][weapon] != null)
                {
                    HDPrice = GetHPDamagePrice(group, weapon, WeaponGroupHolder.HDTier);
                    ADPrice = GetAPDamagePrice(group, weapon, WeaponGroupHolder.ADTier);
                }
            }
        }
    }

I’ll say it again: As long as you make these things public, Unity is able to overwrite the contents of those arrays when this MonoBehaviour is instantiated and deserialized.

As I wrote: https://discussions.unity.com/t/845207/4

So I’m supposed to make them private or static?

You could try marking them as [NonSerialized], or alternately making them properties, as Unity’s deserialization only works against fields, not properties.

But how would that help me

But how would that help me initialize the jagged array field?

First things first. You need to have that code execute, what you have put inside of Awake(). That’s part of your confidence that the code is initialized.

The fastest way to see if code is executing is always Debug.Log(), or if you prefer, a breakpoint.

Reading slowly back up the long chain of posts here, if this is in a ScriptableObject derived class, I am pretty sure you will NOT get called in Awake() at every play / stop cycle.

More recent versions of Unity will call OnEnable() to do this sort of thing.

You may try this code on your particular version of Unity to understand what I mean.

using UnityEngine;

// go make, clone, destroy these things, press PLAY / STOP, watch your logs.
[CreateAssetMenu]
public class KurtDekkerSO : ScriptableObject
{
    private void Awake()
    {
        Debug.Log("Awake:" + name + " --> " + System.DateTime.Now);
    }
    private void OnEnable()
    {
        Debug.Log("OnEnable:" + name + " --> " + System.DateTime.Now);
    }
    private void OnDisable()
    {
        Debug.Log("OnDisable:" + name + " --> " + System.DateTime.Now);
    }
}

From my reading, it appears that Awake() is only called ONCE at creation, and subsequently OnEnab/OnDisab gets called. This is from Unity 2021.1.0f1:

7258247--875390--Screen Shot 2021-06-21 at 1.04.54 PM.png

I only see one Awake() call there at creation (its name isn’t even filled in!), and I see ZERO Awake() calls in between multiple runs.

Is that the issue here?

For now, it seems like that has actually fixed the reference error. Unfortunatley, some parts of it still aren’t working. But, I don’t yet believe it is the scriptable objects fault. So, I might have to get back to you on that.

Yep, it was solved by that simple fix.