Kalia
Kalia

Reputation: 23

c# jagged array bug (elements are not always set)

I am using a jagged array to hold the map segments (Clusters) in a game I am making. The position in the array corresponds to the Cluster's position in the map. Furthermore, if the inner array (the jagged part) no longer has any Clusters loaded into it (Clusters are removed from the array after a not-used timeout) that element of the outer array is set back to null to keep the map's memory usage down.

The problem arises seemingly at random when the game tries to get a Cluster from the map:

public Cluster getCluster(int xIndex, int yIndex)
{
    lock (xAxis)
    {
        loadCluster(xIndex, yIndex);
        return xAxis[xIndex][yIndex];
    }
}

public void loadCluster(int xIndex, int yIndex)
{
    lock (xAxis)
    {
        if (xAxis[xIndex] == null)
            xAxis[xIndex] = new Cluster[(int)worldSize.Y];
        if (xAxis[xIndex][yIndex] == null)
            xAxis[xIndex][yIndex] = new Cluster(this, new Vector2(xIndex * 256, yIndex * 256), worldLoader.loadClusterData(xIndex, yIndex));
    }
}

The loadCluster(int, int) method should ensure the Cluster is loaded into the array before the getCluster(int, int) method retrieves it and almost all the time it does, but occasionally loadCluster(int, int) somehow fails to add the Cluster.

It doesn't seem to happen with any particular cluster, but always happens when the inner array has not been added (however, most of the time it creates the inner arrays with no problems at all). Also, when Visual Studio catches the ensuing null pointer exception, stepping back and re-calling loadCluster(int, int) always (at least so far) works as normal. Adding extra calls to loadCluster(int, int) in the getCluster(int, int) method also greatly decreases the frequency of this bug.

I honestly have no idea what is causing this rather straightforward function to not work, seemingly at random even. Any help would be much appreciated

EDIT: Other code that edits xAxis[][]

public override void Update(GameTime gameTime)
{
    for (int x = 0; x < worldSize.X; x++)
    {
        if (xAxis[x] == null) continue;
        int loaded = 0;
        for (int y = 0; y < worldSize.Y; y++)
        {
            if (xAxis[x][y] == null)
            {
                continue;
            }
            xAxis[x][y].Update(gameTime);

            if (xAxis[x][y].clusterLoaded)
            {
                loaded++;
            }
            else if (xAxis[x][y].clusterTimer == 0)
            {
                xAxis[x][y] = null;
            }
        }

        if(loaded == 0) xAxis[x] = null;
    }
}

Cluster.clusterLoaded is a bool showing if the Cluster is currently in use. Cluster.clusterTimer is an int which counts down once clusterLoaded becomes false. It is reset if to its maximum value if clusterLoaded becomes true again. It is decreased by 1 every time Cluster.Update(GameTime) is run while clusterLoaded is false. loaded is used to count how many Clusters in the current inner array are loaded.

Upvotes: 2

Views: 320

Answers (1)

Artak
Artak

Reputation: 2887

First thing to change here is to modify the loadCluster method to return the xAxis[xIndex][yIndex] value right from it. Then there will be no need to lock in the getCluster method. What about other sections of the code - from the description it seems to be a multi-threading issue. Although you've locked on xAxis variable, I don't know what else you do somewhere else. One more point - arrays in the language are really a core functionality, so it's really unexpected to have a bug there (I mean Microsoft).

Upvotes: 3

Related Questions