Issue with lists now

Hey some might have seen my issue with arrays earlier, however Im now having issues with lists, that again, not sure whats going on. Ive posted the code below. Error is on line "116, with a null Reference Exception, however it seems to loop through, according to debugs fine, the first time, its only the second time that it fails.

For easiness sake, I’ve also included the code from the TileContainer class.

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Tilemaps;

public class WaveFunctionCollapse : MonoBehaviour
{

    [SerializeField] Tilemap InputMap; //The input tilemap to take
    [SerializeField] Tilemap outputMap; //Where the output will be going
   public  TileBase[] allTiles; //This is needed to take a 1D array of tiles form the inputTilemap.
    public BoundsInt bounds; //The area of the tilemap. needed to lopop through the 1D array, allTiles, to put into our 2D array.
    public TileBase[,] inputTiles; //A 2D array that we create to take the info from each of our tiles before transfering it to your 2D araay of containers. A later update could likely remove this.
    public TileContainer[,] inputMapContainer; //Our 2D array that we will be using to go through each tile, adding neighbours, before recombining into a list.
    public List<TileContainer> AllPossibleTiles; //Our list that we will be using for WFC itself. this will have the info of each tile, and what each possible neighbour can be.


    //will need n editor button to run the script
    // Start is called before the first frame update
    void Start()
    {
        Run();
    }

    // Update is called once per frame
    void Update()
    {
      
    }

    void Run()
    {
        InputMap.CompressBounds(); //Sets the array to the area of the tiles, in case something went wrong.
        bounds = InputMap.cellBounds;
        TileBase[] allTiles = InputMap.GetTilesBlock(bounds); //the bounds above is used to get the tiles in this area.
        inputTiles = new TileBase[bounds.size.x,bounds.size.y]; // creates our array of tiles in the right size.
        inputMapContainer = new TileContainer[bounds.size.x, bounds.size.y]; //creating the size of the array so we can start intrializing the lists, and putting the info in

        // nested for loop. We get a 1D array of elements when we call get the tiles, and to simplify the information we should have a 2d array.
        for (int x = 0; x < bounds.size.x; x++)
            for (int y = 0; y < bounds.size.y; y++)
            {
                if (allTiles[x + y * bounds.size.x] == null)
                {
                    //The array should have no holes in it, but just in case.
                    Debug.Log("Null tile, will not work, location: " + x + " and " + y);
                }
                //This take the 2D array, and turns it into a 2D array.
                inputTiles[x, y] = allTiles[x + y * bounds.size.x];
                //   Debug.Log(inputTiles[x, y].name + " this is a 2D array" + x + " " + y);
                //All of these need to be initialized now, or they return errors later on. This is the easiest place for the input array.
                //These are the tile itself, and each of its possible neighbours, plus all the tiles that can be in there, though this isnt used as of now.
                inputMapContainer[x, y] = new TileContainer(inputTiles[x, y]);
                inputMapContainer[x, y].possibleUpTiles = new List<TileBase>();
                inputMapContainer[x, y].possibleDownTiles = new List<TileBase>();
                inputMapContainer[x, y].possibleLeftTiles = new List<TileBase>();
                inputMapContainer[x, y].possibleRightTiles = new List<TileBase>();
                inputMapContainer[x, y].possibleTilesForThis = new List<TileBase>();



                // Debug.Log(allTiles[x + y * bounds.size.x].name);
                //  inputMapContainer[x, y].SingleTile = inputTiles[x, y];
                Debug.Log(inputMapContainer[x, y].SingleTile.name + " " + x + " " + y);
            }

        for (int x = 0; x < bounds.size.x; x++)
            for (int y = 0; y < bounds.size.y; y++)
            {
                //This loop sets all the possible neighbours for each tile.
                //In each iteration it checks the neighnbour next to it, to see if it is ourside the bounding box,
                //and if it isnt, it gets that info from the array in that spot.
                //This step is done after the last step is fully finished as, while it may have seemed like it would work in the last one,
                //it simply doesnt due to the first tiles never being able to find what their neighbours have.
                if (x + 1 < bounds.size.x)
                {
                    inputMapContainer[x, y].possibleUpTiles.Add(inputMapContainer[x + 1, y].SingleTile);
                    Debug.Log("Added Up" + x + " " + y);
                }

                if (x - 1 >= 0)
                {
                    inputMapContainer[x, y].possibleDownTiles.Add(inputMapContainer[x - 1, y].SingleTile);
                    Debug.Log("Added Down" + x + " " + y);
                }

                if (y - 1 >= 0)
                {
                    inputMapContainer[x, y].possibleLeftTiles.Add(inputMapContainer[x, y - 1].SingleTile);
                    Debug.Log("Added Left" + x + " " + y);
                }
                if (y + 1 < bounds.size.y)
                {
                    inputMapContainer[x, y].possibleRightTiles.Add(inputMapContainer[x, y + 1].SingleTile);
                    Debug.Log("Added Right" + x + " " + y);

                }

            }

        //This step now needs to take each element of the array, and combine them into the list.
        //To do this, we will check if a list contains elements from each part of the array, and if they are the same, we will add each neightbour to  a list of each for that, checking again if any neihbours are the same
        //
        AllPossibleTiles = new List<TileContainer>();
        foreach (TileContainer TileToCheckfrominput in inputMapContainer)
        {
            if (AllPossibleTiles == null)
            {
                Debug.Log("Not initialized");
                AllPossibleTiles.Add(TileToCheckfrominput);
            }
            else
            {
                Debug.Log("NO Error before null");
                var contains = AllPossibleTiles.Find(ListTiles => ListTiles.name == TileToCheckfrominput.name);
                Debug.Log("NO Error after var null");
                if (contains != null)
                {
                    //if contains is true we need to add the
                    Debug.Log("Concat elements");
                    contains.possibleUpTiles.Union<TileBase>(TileToCheckfrominput.possibleUpTiles);
                }
                else
                {
                    Debug.Log("Adding new element");
                    AllPossibleTiles.Add(TileToCheckfrominput);
                    Debug.Log("Error on add");
                }
            }
            Debug.Log("Looped through fine");

                }
            }
        }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;

public class TileContainer: MonoBehaviour
{

public TileBase SingleTile;
public List<TileBase> possibleUpTiles;
public  List<TileBase> possibleDownTiles;
public  List<TileBase> possibleLeftTiles;
public  List<TileBase> possibleRightTiles;
public List<TileBase> possibleTilesForThis;


  
public  bool hasBeenCollapsed = false;
public bool hasCollision = false;
public int collisionX;
public int collisionY;

    public TileContainer(TileBase newTile)
    {
        SingleTile = newTile;
    }

    public TileContainer()
    {
        // This is needed for the output tiles so I can create them with no issues.
    }
}

Hypothetically, line 116 could throw a NullReferenceException if AllPossibleTiles is null OR if TileToCheckfrominput is null OR if ListTiles is null. Since this “else” branch shouldn’t be running in the first place if AllPossibleTiles is null, I’d guess that’s not the problem. But if either AllPossibleTiles or inputMapContainer contain an entry that is null, then you’ll eventually get an exception on line 116 when you try to get the name of a null TileContainer.

(Incidentally, if you are trying to test whether the two TileContainers are the same object, then comparing their names is probably not a good way to do that. You should be able to just compare the two TileContainers directly; i.e. ListTiles == TileToCheckfrominput. And if all you really care about is whether the item is in the list at all, you could use List.Contains() instead of List.Find().)

I don’t see anywhere in your code that I would expect null entries to slip into those lists, but I suggest you add some checks for them and see what turns up.

By the way, notice that if the “if” on line 108 is ever true, then line 111 will throw a NullReferenceException, because you’re trying to call the .Add() function on a variable that you just confirmed was null. (Note that an empty list is not the same as a null list. An empty list exists, but doesn’t have anything inside it; a null list doesn’t exist.)

I found the error, just as you posted it. The issue is I should have been calling

 TileContainer contains = AllPossibleTiles.Find(ListTiles => ListTiles.SingleTile.name == TileToCheckfrominput.SingleTile.name);

and it was always returning null from the lack of a name in the items.
The reason im iffy with not checking string names from the tiles, is, a tile at say 0,0, and 0,1 should be different, even if they are showing the same image. correct me if i’m wrong of course, but thats why im checking name strings directly.

Thanks for the help and goign through.

That’s not how it works. The expression TileToCheckfrominput.name will throw an exception if “TileToCheckfrominput” is null, but NOT if “name” is null. (And testing whether 2 things are equal shouldn’t throw a null reference exception either, unless you are using a poorly-implemented override for operator==)

Your new code is dereferencing all the variables that your old code dereferenced, so if it fixed your null reference exception it must have done so indirectly by changing the path that your program took.

I don’t know what TileBase is or how you are assigning the names, but if it is a class and there is no custom equality operator defined, then the default comparison is reference equality, which is basically the strictest kind of equality you can test for. If a reference equality test passes, then you have 2 variables pointing to literally the same object, so everything else about the objects is also guaranteed to be equal. However, if you only test their names, then it’s possible you could have two different objects that coincidentally happen to have the same name, and so it would look like they’re equal even if other stuff about them is different.

It looks like you’ve also made it so that your TileContainers will now count as the same if they have the same SingleTile (or SingleTiles with the same name), whereas before you were checking whether the containers themselves were the same.

TileBase is taken from unitys tilemap assets. Its the base class that tiles inherit from.

I had used a breakpoint to verify that TileToCheckfrominput.name was null, and after fixing this, ive got it at least somewhat working (though now it doesn’t return anything even if both of them are the same which is strange. Id prefer not to have to check each tile using name, however tiles should be different game objects, and I simply want to verify if they are displaying the same thing, in different positions.