Resources being set to null in game?

Godot Version

Godot 4.2

Question

I’m building a maze game.
I have a mazecell resource class that looks like this:

@tool
extends Resource

class_name MazeCell

@export var cell_name: String = "Cell name"
@export var cell_description: String = "Cell room"
@export var cell_pic: String
@export var is_instance := false
@export var enemy:Resource = null

@export var exits: Dictionary = {}

var visited:=false

The most important part is the exits dict, which has int (enum) keys and MazeCell (resource/object) values.
I use this class to represent a maze. The issue is that when I’m currently in a cell, and look at the exits of the adjacent cells, their value for the exit leading to the current cell is always null, even though I manually set it via the inspector.

For example, if I’m in a cell, and I look at the exits of the cell to the north, it should have a dictionary entry with the key being south, and the value being the current cell. Instead, it contains a key for the south, and a null value. The same is true for a cell to the west: it (correctly) contains a key for the east, but instead of the value being the current cell, it’s a null. This occurs for every adjacent cell, for every start cell. This is breaking my game.

Does anyone know why this is happening? Or if there’s anything I should be looking for?

how do you reference this resource and used it? also do you saved a .tres for it? after assigning the exits manually at inspector dock

If you are storing a MazeCell at runtime, it should be fine, but upon a restart/reload those refs will be invalid and are probably being set to null.

Just a guess. You need to help us understand how you use that Resource.

If my understanding is right, it’s not being stored at runtime, but before, since I’m setting the value from the inspector.

All the maze cells are .tres files.

The maze has an initial cell, and from there I access the other cells by looking at the exits of the current cell, and seeing where I can move from there.

It’s also not all the mazecells, but only the current mazecell that’s being set to null in the exits variable of the other cells.

I figured out the solution, and it was annoying.

The problem was the exits lead to a circular dependency: if I have an exit leading to a cell to the north, and that cell has an exit that goes back to me, it creates a circular dependency.

This should have been an easy fix, except

  1. Godot didn’t say anything about this being an issue, just silently setting circular dependencies to null
    2: This worked fine when I was using nodes, but it doesn’t work when using resources
    3: Whenever I relaunched the project, godot gave me a totally useless parse error
    " Failed loading resource: Make sure resources have been imported by opening the project in the editor at least once"
    4: This sort of thing is totally permissible in other languages: here’s an example in Java:
        class Example {
          public String name;
          public Example ex;
        }
        Example e=new Example();
        Example e2=new Example();
        e.ex=e2;
        e2.ex=e;

      
      
        e.name="Alice";
        e2.name="Bob";

        System.out.println(e.ex.name);
        System.out.println(e2.ex.name);

This totally works, but doing something similar with exits in gdscript failed, silently.

I’ll try to refactor the project so exits are stored separately from their rooms, probably with one big exit dict for each maze.

I have to say, this felt pretty disappointing. A series of connected rooms isn’t some rare thing, and trying to create a circular dependency isn’t some exotic, weird error (and probably shouldn’t even be one in this case) but I found pretty much no useful resources, and the error messages were confusing and probably more trouble than they were worth.

Obviously, this is whining about free software, but it still feels annoying, since godot is so highly recommended.

I hope this helps someone.

This may be because you are using a resource directly as a value instead of using the RID to figure out which instance it is. The navigation system has a similar kind of cyclical graph, so the connections are not stored as direct references to the objects, but as RIDs, internally. That it let you run that at all means the script parser worked, but you are right it should warn you.