Null Reference exception in list with at least one member

In my dungeon generation code I create one seed room at the center of the dungeon for the rest of it to crystallize around. Every room created after this room is created adjacent to an already existing room. To place this room near another room that already exists I use the function below. One of the functions that depends on this was giving me a nullreference exception which I’ve managed to track back to my GetAdjacentRooms function, when I try to print out one of the object names from my list I get a Null Reference Exception. Thank you for your help! If I left out important information let me know!

    //Returns all rooms adjacent on the X/Y axis to this room. It shouldn't return rooms in the corners.
    //DEBUG: Currently causing problems and giving NullReferenceException: Object reference not set to an instance of an object.
    public List<Room> GetAdjacentRooms(Room room)
    {
        List<Room> adjacentRooms = new List<Room>();

        //Check the tiles above and below our given room
        for(int x = 0; x < room.width; x++)
        {
            //Check to see if the index exists above
            if(room.height + room.z + 1 < worldHeight)
            {
                //Check to see if the room hasn't been added to our list.
                if(!adjacentRooms.Contains(WorldTiles[x,room.height + room.z + 1].room))
                {
                    Debug.Log("Room Added");
                    adjacentRooms.Add(WorldTiles[x,room.height + room.z + 1].room);
                }
            }
            if(room.z - 1 > 0)
            {
                //Check to see if the room hasn't been added to our list.
                if (!adjacentRooms.Contains(WorldTiles[x,room.z - 1].room))
                {
                    Debug.Log("Room Added");
                    adjacentRooms.Add(WorldTiles[x,room.z - 1].room);
                }
            }
            Debug.Log("Adjacent Rooms: " + adjacentRooms.Count);
            if(adjacentRooms.Count != 0)
                Debug.Log(adjacentRooms[0].gameObject.name); //Null Reference exception in this test code.
        }

Edit: I forgot to mention. It always throws this error the first time it’s called. It places the seed room, prints out the “Room Added” debug code, prints out that we have “Adjacent Rooms: 1” and then gives me the null reference exception “NullReferenceException: Object reference not set to an instance of an object”.

Just a shot in the dark since I don’t know what WorldTiles looks like and the code itself looks fine to me.
If there’s a Room in the List a line before the exception, can it be that you’re just adding a ‘Room’ object to the list without actually attaching it to a GameObject? Because then of course Room.gameObject would be null.

Have you tried calling Debug.Log(adjacentRooms[0]) yet? What does it say?

WorldGrid is a 2d array full “WorldSegment” objects that point to a null room because one hasn’t been created yet. Checking the name of the game object was my way of checking Debug.Log(adjacentRooms[0]), it’s coming up null. You were right, I forgot to check to see if I was adding null references to the list, that was clearly part of the problem. I updated my code to fix that, I’m still getting null references on the list though.

//Returns all rooms adjacent on the X/Y axis to this room. It shouldn't return rooms in the corners.
    //DEBUG: Currently causing problems and giving NullReferenceException: Object reference not set to an instance of an object.
    public List<Room> GetAdjacentRooms(Room room)
    {
        List<Room> adjacentRooms = new List<Room>();

        //Check the tiles above and below our given room
        for(int x = 0; x < room.width; x++)
        {
            //Check to see if the index exists above 
            if(room.height + room.z + 1 < worldHeight)
            {
                //Check to see if the room hasn't been added to our list and make sure we're not adding a null room to our list.
                if(!adjacentRooms.Contains(WorldTiles[x,room.height + room.z + 1].room) && WorldTiles[x, room.height + room.z + 1].room != null)
                {
                    adjacentRooms.Add(WorldTiles[x,room.height + room.z + 1].room);
                }
            }
            if(room.z - 1 > 0)
            {
                //Check to see if the room hasn't been added to our list and make sure we're not adding a null room to our list.
                if (!adjacentRooms.Contains(WorldTiles[x,room.z - 1].room) && WorldTiles[x, room.z - 1].room != null)
                {
                    adjacentRooms.Add(WorldTiles[x,room.z - 1].room);
                }
            }
            if (WorldTiles[x, room.z - 1].room != null)
                Debug.Log(adjacentRooms[0]);
            Debug.Log("Adjacent Rooms: " + adjacentRooms.Count);
            if(adjacentRooms.Count != 0)
                Debug.Log(adjacentRooms[0].gameObject.name); //Null Reference exception in this test code.
        }

        //Check the tiles to our right and left to find adjacent rooms.
        for(int z = 0; z < room.height; z++)
        {
            //Check to see if the index exists
            if(room.width + room.x + 1 < worldWidth)
            {
                //Check to see if the room hasn't been added to our list.
                if(!adjacentRooms.Contains(WorldTiles[room.width + room.x + 1,z].room))
                {
                    Debug.Log("Room Added");
                    adjacentRooms.Add(WorldTiles[room.width + room.x + 1,z].room);
                }
            }
            if(room.x - 1 > 0)
            {
                if(!adjacentRooms.Contains(WorldTiles[room.x - 1,z].room))
                {
                    Debug.Log("Room Added");
                    adjacentRooms.Add(WorldTiles[room.x - 1,z].room);
                }
            }
        }

        return adjacentRooms;
    }

As @Zephus said

//If you change this line

Debug.Log(adjacentRooms[0].gameObject.name);

//to this
Debug.Log(adjacentRooms[0]);

Does that line still give you a null error?

Since you are creating the list in the same method and you do initialize it, it’s not going to be null. Which means there isn’t an issue with the list itself but with the value of what you are accessing, which means most likely there is no gameobject attached to that “room” which would probably give you null.

And I do see you have the line up a few where you’re checking if something else is null and then trying to print Debug.Log(adjacentRooms[0]); out, but you didn’t mention if that printed out or not.

I would say also check if adjacentRooms[0].gameObject == null and see if it prints true or false for you.

Okay, from earlier it seemed like I needed to spend some more time trying to isloate exactly what was happening and I think I’ve narrowed it down. It seems like it’s creating the list of rooms just fine, but each rooms list of connections is getting mangled.

When I go to place a new Room I start with it’s prefab. Each prefab has the “Room” class attached to it with a list of connections. I assign this list of connections in the inspector before making the whole thing a prefab so each room has to have a list of connections, however somehow when I create a new instance of my Room from the blueprint and get it’s room class I must be losing the list of connections. I’ll post the code I think is causing trouble below and in the next post down I’ll post all of the code that’s related in any manner.

I think this is the problematic code

    //TODO: FIXME! GetAdjacentRooms returning a list containing null references
    //Returns all rooms adjacent on the X/Y axis to this room. It shouldn't return rooms in the corners.
    //DEBUG: Currently causing problems and giving NullReferenceException: Object reference not set to an instance of an object.
    //DEBUG2: Seems like the rooms connection list is getting mangled somehow
    public List<Room> GetAdjacentRooms(Room room)
    {
        List<Room> adjacentRooms = new List<Room>();

        //Check the tiles above and below our given room
        for(int x = 0; x < room.width; x++)
        {
            //Check to see if the index exists above
            if(room.height + room.z + 1 < worldHeight)
            {
                //Check to see if the room hasn't been added to our list and make sure we're not adding a null room to our list.
                if(!adjacentRooms.Contains(WorldTiles[x,room.height + room.z + 1].room) && WorldTiles[x, room.height + room.z + 1].room != null)
                {
                    adjacentRooms.Add(WorldTiles[x,room.height + room.z + 1].room);
                }
            }
            if(room.z - 1 > 0)
            {
                //Check to see if the room hasn't been added to our list and make sure we're not adding a null room to our list.
                if (!adjacentRooms.Contains(WorldTiles[x,room.z - 1].room) && WorldTiles[x, room.z - 1].room != null)
                {
                    adjacentRooms.Add(WorldTiles[x,room.z - 1].room);
                }
            }
            Debug.Log("Adjacent Rooms: " + adjacentRooms.Count);
            if(adjacentRooms.Count != 0)
          
                Debug.Log(adjacentRooms[0]); //Null Reference exception in this test code.
        }

        //Check the tiles to our right and left to find adjacent rooms.
        for(int z = 0; z < room.height; z++)
        {
            //Check to see if the index exists
            if(room.width + room.x + 1 < worldWidth)
            {
                //Check to see if the room hasn't been added to our list.
                if (!adjacentRooms.Contains(WorldTiles[room.width + room.x + 1, z].room) && WorldTiles[room.width + room.x + 1, z].room != null) ;
                {
                    adjacentRooms.Add(WorldTiles[room.width + room.x + 1,z].room);
                }
            }
            if(room.x - 1 > 0)
            {
                if(!adjacentRooms.Contains(WorldTiles[room.x - 1,z].room) && WorldTiles[room.x - 1, z].room != null)
                {
                    adjacentRooms.Add(WorldTiles[room.x - 1,z].room);
                }
            }
        }

        //TODO: DELETE ME. THIS CODE IS JUST FOR TESTING.
        foreach (Room testRoom in adjacentRooms)
        {
            Debug.Log("Room:" + testRoom); //This is fine and happily prints "Room:"
            Debug.Log("Room" + testRoom.connections.Count); //This also gives a null reference exception
            foreach (Connection connection in testRoom.connections)
            {
                Debug.Log("Connection:" + connection); //This gives a null reference exception if the other problematic code is removed
            }
        }

        return adjacentRooms;
    }

And here’s all of the code. If you happen to dig around in here criticism would be appreciated. It’s a bit of a mess. I’m pretty sure I made the mistake in the code above but this might help give a bit of context.

This is the script that manages the whole thing.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// This is the base class of our world generator. It holds all of the critical information and functions about our world generation.
/// </summary>
public class WorldGrid : MonoBehaviour
{
    [Header("World Settings")]
    //How many UnityUnitys wide and tall a segment is. This is set in the editor
    [Tooltip("How many unity units our WorldSegments are. Each tile should be 1 unity unit")]
    public int segmentSize;

    //Word width in segments. This is set in the editor
    [Tooltip("The width of the world in WorldSegments")]
    public int worldWidth;

    //World height in world segments. This is set in the editor.
    [Tooltip("The height of the world in WorldSegments")]
    public int worldHeight;

    //Total number of rooms. Set in editor.
    [Tooltip("How many rooms to generate.")]
    public int roomCount;

    //2d array of WorldSegment objects. This represents the world. This is generated through code.
    WorldSegment[,] WorldTiles;

    [Space(1)]
    [Header("Room Controls")]
    //Array of our rooms we want to build the dungeon from. This is set in the editor,
    [Tooltip("A list of rooms used in creating the dungeon. Each room needs to be a gameobject with a Room script attached.")]
    public Room[] BlueprintList;



    //The connections that are on the outside of a room. Used in placing room
    private List<Connection> exteriorConnections = new List<Connection>();


    // Use this for initialization
    void Start ()
    {
        //Set up the 2d array for the world and populate it with
        WorldTiles = new WorldSegment[worldWidth, worldHeight];
        for(int x = 0; x < worldWidth; x++)
        {
            for(int y = 0; y < worldHeight; y++)
            {
                WorldTiles[x,y] = new WorldSegment();
            }
        }

        //Generate the dungeon
        GenerateDungeon();
    }
      

    void GenerateDungeon()
    {
        //Place the seed room.
        //TODO: MAKE THIS SPAWN A SPECIFIC "ENTRANCE" ROOM
        PlaceRoom(BlueprintList[0], worldWidth/2, worldHeight/2);


        //Fill dungeon. Subtract 1 because of the seed room.
        FillDungeon(roomCount -1);

        //Connect the dungeon
    }

    void FillDungeon(int roomNumber)
    {
        int roomCounter = 0;
        for(int x = 0; x <= roomNumber; x++)
        {  
            Room newRoom;
            int placeX;
            int placeZ;

            //Get the rooms position.
            //Find one connection.
            Connection placementConnection = exteriorConnections[Random.Range(0,exteriorConnections.Count)];
            Room newRoomBlueprint = BlueprintList[Random.Range(0, BlueprintList.Length)];

            //Pick a random room

            //TODO: This only respects the connection we're building off and doesn't make sure there's a connection on the object we're placing that will match up.
            //Check to see if we're on the leftside of a segment. The subtraction is for a buffer zone.
            if ((placementConnection.gameObject.transform.position.x % segmentSize < (segmentSize/2)-(segmentSize*0.10)))
            {
                placeX = (int)placementConnection.gameObject.transform.position.x/segmentSize - 1 /* - newRoomBlueprint.width*/;
                placeX = placeX - newRoomBlueprint.width;
                placeZ = (int)placementConnection.gameObject.transform.position.z/segmentSize;
            }
            //Check if we're off the right side.
            if((placementConnection.gameObject.transform.position.x % segmentSize > (segmentSize/2)+(segmentSize*0.10)))
            {
                placeX = (int)placementConnection.gameObject.transform.position.x / segmentSize + 1;             
                placeZ = (int)placementConnection.gameObject.transform.position.z/segmentSize;
            }
            //Check if we're off the bottom side.
            if((placementConnection.gameObject.transform.position.z % segmentSize < (segmentSize/2)-(segmentSize*0.10)))
            {
                placeX = (int)placementConnection.gameObject.transform.position.x/segmentSize;
                placeZ = (int)placementConnection.gameObject.transform.position.z/segmentSize - 1;
                placeZ = placeZ - newRoomBlueprint.height;
            }
            //we're off the top side.
            {
                placeX = (int)placementConnection.gameObject.transform.position.x/segmentSize;
                //Take the objects z depth, turn it into a segment position, move the position up by one and then move it up by the room height
                placeZ = (int)placementConnection.gameObject.transform.position.z/segmentSize + 1;

            }

            //place the room
            newRoom = PlaceRoom(newRoomBlueprint, placeX,placeZ);
            if(newRoom == null) //Our placement didn't work, don't increment the counter.
            {
                x--;
            }
            else
            roomCounter++;

            if(newRoom != null)
            {
               newRoom.UpdateConnections(GetAdjacentRooms(newRoom));
            }

            //Call the new room check connections here. We'll need to sort through the tiles to find adjacent rooms.
        }
        Debug.Log("We have " + roomCounter + " rooms.");
      
    }

    //This function will place a room on the worldgrid adjacent to one of our attachment points
    Room PlaceRoom(Room room, int xPos, int zPos)
    {
        //We can't place a room, the spot is occupied.
        if (CheckPlacement(room, xPos, zPos) != true)
        {
            return null;
        }

        //Place the room. Take it's x position on the grid and multiply it by the size of a segment to get it's world position, then add half the room size so it places relative to the lower left corner.
        GameObject roomObject = Object.Instantiate(room.gameObject, new Vector3(xPos*segmentSize + (0.5f*room.gameObject.transform.position.x),0,zPos* segmentSize + (0.5f * room.gameObject.transform.position.z)), room.gameObject.transform.rotation);
        roomObject.transform.parent = this.gameObject.transform;
        Room newRoom = roomObject.GetComponent<Room>();
        newRoom.x = xPos;
        newRoom.z = zPos;

        //Fill in the grid where we want to place ourselves.
        for(int x = 0; x < room.width; x++)
        {
            for(int z= 0; z < room.height; z++)
            {      
                WorldTiles[(xPos + x), (zPos + z)].room = newRoom;
                WorldTiles[xPos + x, zPos + z].full = true;
            }
        }

        //Add all of the connections from our new room to the exterior connections list.
        //We'll remove the ones that are adjacent to another room when we update our connections.
        foreach(Connection connection in newRoom.connections)
        {
            exteriorConnections.Add(connection);
        }

        //Break from the function. We're done.
        return newRoom.GetComponent<Room>();
      
      
    }

    //TODO: FIXME! GetAdjacentRooms returning a list containing null references
    //Returns all rooms adjacent on the X/Y axis to this room. It shouldn't return rooms in the corners.
    //DEBUG: Currently causing problems and giving NullReferenceException: Object reference not set to an instance of an object.
    //DEBUG2: Seems like the rooms connection list is getting mangled somehow
    public List<Room> GetAdjacentRooms(Room room)
    {
        List<Room> adjacentRooms = new List<Room>();

        //Check the tiles above and below our given room
        for(int x = 0; x < room.width; x++)
        {
            //Check to see if the index exists above
            if(room.height + room.z + 1 < worldHeight)
            {
                //Check to see if the room hasn't been added to our list and make sure we're not adding a null room to our list.
                if(!adjacentRooms.Contains(WorldTiles[x,room.height + room.z + 1].room) && WorldTiles[x, room.height + room.z + 1].room != null)
                {
                    adjacentRooms.Add(WorldTiles[x,room.height + room.z + 1].room);
                }
            }
            if(room.z - 1 > 0)
            {
                //Check to see if the room hasn't been added to our list and make sure we're not adding a null room to our list.
                if (!adjacentRooms.Contains(WorldTiles[x,room.z - 1].room) && WorldTiles[x, room.z - 1].room != null)
                {
                    adjacentRooms.Add(WorldTiles[x,room.z - 1].room);
                }
            }
            Debug.Log("Adjacent Rooms: " + adjacentRooms.Count);
            if(adjacentRooms.Count != 0)
          
                Debug.Log(adjacentRooms[0]); //Null Reference exception in this test code.
        }

        //Check the tiles to our right and left to find adjacent rooms.
        for(int z = 0; z < room.height; z++)
        {
            //Check to see if the index exists
            if(room.width + room.x + 1 < worldWidth)
            {
                //Check to see if the room hasn't been added to our list.
                if (!adjacentRooms.Contains(WorldTiles[room.width + room.x + 1, z].room) && WorldTiles[room.width + room.x + 1, z].room != null) ;
                {
                    adjacentRooms.Add(WorldTiles[room.width + room.x + 1,z].room);
                }
            }
            if(room.x - 1 > 0)
            {
                if(!adjacentRooms.Contains(WorldTiles[room.x - 1,z].room) && WorldTiles[room.x - 1, z].room != null)
                {
                    adjacentRooms.Add(WorldTiles[room.x - 1,z].room);
                }
            }
        }

        //TODO: DELETE ME. THIS CODE IS JUST FOR TESTING.
        foreach (Room testRoom in adjacentRooms)
        {
            Debug.Log("Room:" + testRoom); //This is fine and happily prints "Room:"
            Debug.Log("Room" + testRoom.connections.Count); //This also gives a null reference exception
            foreach (Connection connection in testRoom.connections)
            {
                Debug.Log("Connection:" + connection); //This gives a null reference exception if the other problematic code is removed
            }
        }

        return adjacentRooms;
    }

    //Check to see if the placement of a room is clear.
    //xPos/yPos should correspond to the lower left corner of the room.
    //TODO: Rooms are sometimes being spawned on eachother. I suspect the problem is in check placement.
    bool CheckPlacement(Room room, int xPos, int zPos)
    {
        for(int x = 0; x < room.width; x++)
        {
            for(int z = 0; z < room.height; z++)
            {
                //Check to see if any of the position is filled or sits outside our desired dungeon. If so we know we can't place a room here
                if(xPos + x > worldWidth ||   zPos + z > worldHeight ||xPos + x < 0 || zPos + z < 0  )
                {
                    //Room placement is bad.
                    return false;
                }
                else //Check to see if the spot is full
                if(WorldTiles[xPos + x, zPos + z].full == true)
                {
                    return false;
                }
            }
        }

        //None of the spots were filled so the spot must be clear.
        return true;
    }


    public void removeExteriorConnection(Connection connection)
    {
        exteriorConnections.Remove(connection);
    }
}

Here’s the room code, it’s the next most important piece of code.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//Lets us use Concat for our lists.
using System.Linq;

/// <summary>
/// The Room Data model holds basic information about rooms and is used to differentiate between different rooms when they've been placed onto the grid.
/// </summary>
public class Room : MonoBehaviour
{
    [Tooltip("The width of the room in the X direction measured in WorldSegments")]
    public int width; //In WorldSegments. This is set in the editor.
    [Tooltip("The height of the room in the Z direction measured in WorldSegments")]
    public int height; //In WorldSegments. This is set in the editor.

    //List of connections to other rooms. This is set in the editor.
    [Tooltip("Connection GameObjects with a Connection script attached. Used to toggle walls on and off.")]
    public List<Connection> connections = new List<Connection>();

    //Position on the
    public int x; //X position of the lower left segment on the grid
    public int z; //Y position of the lower left segment on the grid
  
    //Update the connections
    public void UpdateConnections(List<Room> adjacentRooms)
    {
        if(adjacentRooms.Count != 0 )
        {
            Debug.Log("Adjacent Rooms:" + adjacentRooms.Count);
            foreach (Room room in adjacentRooms)
            {
                Debug.Log("Room:" + room); //Returns a value. This statement prints out "Room:"

                //It looks to me like the rooms connections are being lost.
                Debug.Log("Room Connections" + room.connections); //This is giving me a null reference exception. If I remove it the next line gives me a null reference exception.
                //Iterate through every connection in every adjacent room
                foreach(Connection connection in room.connections)
                {
                    //Iterate through every one of the connections on this object
                    foreach (Connection myConnection in connections)
                    {
                        //If we're within 1 unit in the X/Y direction we want to connect our objects.
                        //IF possible make this value non hardcoded.
                        if(Mathf.Abs(myConnection.gameObject.transform.position.x - connection.gameObject.transform.position.x) < 1)
                        {
                            if(Mathf.Abs(myConnection.gameObject.transform.position.x - connection.gameObject.transform.position.x) < 1)
                            {
                                Connection oldConnection = connection;
                                //Connect the two game objects and then discard them.
                                Connect(myConnection,ref oldConnection);
                            }
                        }
                    }
                }
            }
        }
    }


    //Merge the objects the connections represent so we can turn on off both sets of connections just by toggling this one connection.
    //Then when we're finished delete one of the connections and set the saved connection as the other connection.
    void Connect(Connection savedConnection,ref Connection destroyedConnection)
    {
        //Merge the object lists so we know what to turn on/off when we open or close our connection.
        savedConnection.openObjects = savedConnection.openObjects.Concat(destroyedConnection.openObjects).ToArray();
        savedConnection.closeObjects = savedConnection.closeObjects.Concat(destroyedConnection.closeObjects).ToArray();

        //Our connections have found eachother. We need to remove both the connected and destroyed connection from the exterior connections list.
        GameObject[] controllerObjects = GameObject.FindGameObjectsWithTag("GameController");
        foreach(GameObject gameObject in controllerObjects)
        {
            if(gameObject.name == "WorldController")
            {
                gameObject.GetComponent<WorldGrid>().removeExteriorConnection(savedConnection);
                gameObject.GetComponent<WorldGrid>().removeExteriorConnection(destroyedConnection);
            }
        }

        //overwrite the old connection
        Destroy(destroyedConnection.gameObject);
        destroyedConnection = savedConnection;
    }
}

Here we have the humble Connection object code. This is attached to an empty object in Unity and placed in the center of spots where rooms could possibly connect to eachother. It also holds information about what objects to turn on/off if I want to make to rooms connect.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Connection classes are used to hold information about where rooms can connect to other rooms
/// Connection classes also hold a list of objects used in opening/closing those connections.
/// </summary>
public class Connection : MonoBehaviour
{
    public bool canOpen = true;
    bool isOpen = false;

    public GameObject[] openObjects;
    public GameObject[] closeObjects;

    void Start()
    {
        //Every connection should start closed.
        CloseConnection();
    }

    void OpenConnection()
    {
        if(canOpen == true)
        {
            isOpen = true;
            foreach(GameObject activatedObject in openObjects)
            {
                activatedObject.SetActive(true);
            }
            foreach(GameObject deactivatedObject in closeObjects)
            {
                deactivatedObject.SetActive(false);
            }
        }
    }

    void CloseConnection()
    {
        isOpen = false;
        foreach(GameObject activatedObject in openObjects)
        {
            activatedObject.SetActive(false);
        }
        foreach(GameObject deactivatedObject in closeObjects)
        {
            deactivatedObject.SetActive(true);
        }
    }
}

Here’s the WorldSegment code. Not a lot magical happening in here and I’m considering axing the entire class after I get everything working.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// World segment.
/// This is a datamodel.
/// </summary>

public class WorldSegment
{
    public bool full = false;
    public Room room;

}

Thank you for bearing with my everyone. I’ve been struggling with this world generator for a while now.

Set a breakpoint on the line, and check which variable is null?

reading this paragraph and I’m pretty sure its not the code but how you are setting up the prefab.
Prefabs can only save references of project assets and of objects inside its own prefab hierarchy ( own components and child transforms). After saving/applying the prefab are those connections in the inspector still bold? are they scene objects? if so then it means those values are NOT getting saved to the prefab (because they can’t be saved to the prefab). if you pulled a new instance of a room prefab back into the scene you should see that the list is empty.

If you want to make the connections savable in the prefab you’re going to have to redesign them. make them ScriptableObject assets or make them custom, serializable .NET classes. from the sounds of things probably their own prefabs/scriptableobjects and then have the room prefabs reference the connection prefabs (not the in-scene instances).

The Connection objects are children of the Object the Room class is attached to. When I instantiate a copy the GameObject that Room is attached to it has the connections still there, complete with references. Double clicking on one of the elements takes me to that rooms GameObject with connection attached so I think I have it all hooked up correctly. Did I miss something?

If the connections are locally stored as children within the prefab then you’re fine in that sense.

my only guess then would be to take a closer look at the functions in question. the first thing you can look at is cleaning up and simplifying the implementation within the GetAdjacentRooms. theres a number of flaws within the function, most of which wouldn’t get hit due to how its currently being called, that can definitely surface because the function is public

public List<Room> GetAdjacentRooms(Room room)
    {
        if(WorldTiles == null) return null;
        if(!room) return null;

        int minX = Mathf.Max(0,room.x-1);
        int maxX = Mathf.Min(WorldTiles.GetLength(0),room.x + room.width + 1);
        int minZ = Mathf.Max(0,room.z-1);
        int maxZ = Mathf.Min(WorldTiles.GetLength(1),room.z + room.height + 1);

        List<Room> adjacentRooms = new List<Room>();

        for(int x=minX;x<maxX;x++)
        {
            for(int z=minZ;z<maxZ;z++)
            {
                var targetRoom = WorldTiles[x,z].room;

                if(!targetRoom) continue;

                var leftRoom = WorldTiles[Mathf.Min(x,maxX-1),z].room;
                var downRoom = WorldTiles[x,Mathf.Min(z,maxZ-1)].room;

                if(ReferenceEquals(room,targetRoom))
                {
                    if(leftRoom && !adjacentRooms.Contains(leftRoom) && !ReferenceEquals(room,leftRoom))
                        adjacentRooms.Add(leftRoom);

                    if(downRoom && !adjacentRooms.Contains(downRoom) && !ReferenceEquals(room,downRoom))
                        adjacentRooms.Add(downRoom);
                }
                else if(ReferenceEquals(room,leftRoom) || ReferenceEquals(room,downRoom))
                {
                    if(adjacentRooms.Contains(targetRoom))
                    {
                        adjacentRooms.Add(targetRoom);
                    }
                }
            }
        }

        return adjacentRooms;
    }

I would also check with PlaceRoom function and see if that newRoom is not null before entering them into the world tiles. having the Debug.Log print out “Room:” doesn’t mean its not null (its a monobehaviour and can refenence a fakenull). check WorldGrid.cs: line 151 and actually check if GetComponent is returning null similar to how I check if targetRoom is null in the code I posted (if(!targetRoom)).

Alright, your implementation was a lot simpler, I feel a little silly for not thinking . This whole system is a bit of a mess, I’m still not sure what was causing it in the old code but yours fixed it first try. Thank you Joshua, I spent several days playing with that code and I feel a little silly now. You really helped me out!

For anyone reading in the future looking to use my dungeon generator, it still has a couple of issues. I’ll edit the finished code into this post when I fix them.

just noticed theres a typo in my code. the following should be

var leftRoom = WorldTiles[Mathf.Min(x+1,maxX-1),z].room;
var downRoom = WorldTiles[x,Mathf.Min(z+1,maxZ-1)].room;