How to reference a Resource without loading it?

Godot Version

v4.4.dev2

Problem

I’m playing around with Resources and trying to figure out a way to:

1. Prevent recursion errors when Resources store references to each other

I want Resources for GameStates and I would like to be able to reference other GameStates in them. For example, I want GameStates to know which other GameState to transition to when the escape button is pressed. However, this error appears when I set two GameStates to transition back and forth when the escape button is pressed:

Recursion detected, unable to assign resource to property.

Example code:

class_name GameState extends Resource

@export var escape_state: GameState

2. Store references to scenes in Resources without loading the scene automatically

It’s my understanding that having a property for a PackedScene in a Resource will automatically load the scene whenever the Resource is loaded. This is not ideal, as I would like to have a Resource for each game level and I don’t want the levels to load until the player switches to that level.

Example code:

class_name GameState extends Resource

# loads scene automatically when this GameState is loaded
@export var scene: PackedScene

Question

Is there a way to have a property reference a Resource file (GameState or scene) such that:

  • Recursion errors are not thrown when Resources store references to each other
  • Scenes are not automatically loaded when the Resource containing the property is loaded
  • The reference updates properly when the Resource file is renamed or moved

Workaround

One workaround I can think of is creating an enum for each GameState/Scene resource, having the resources store references to other resources using their enums, and creating a dictionary of enum → GameState/Scene. This works, but is not as convenient as directly referencing Resources.

If you find something please let me know because this is a pain for me as well :sweat_smile:

2 Likes

Store the reference as a string that’s your filename. Load the resource when you need it.

1 Like

Using strings makes refactoring difficult. It would be ideal to have a reference that updates if the resource is renamed or moved.

2 Likes

This isn’t as type safe, but you could try making your exports Resources instead of GameStates?

class_name GameState extends Resource

@export var escape_state: Resource

TBH, this seems like a really weird error. The Godot Docs example even has composition of resources: Resources — Godot Engine (stable) documentation in English

1 Like

Making the export a Resource still gives the same recursion detected error :frowning_face:

1 Like

WTF. I literally made this today, and had no problems with it:

@icon("res://assets/ui/icons/music-library.png")
extends Resource

class_name Song

@export var song: AudioStream
@export var title: String
@export var artist: String
@export var album: String
@export var album_link: String

AudioStream literally is a Resource.

I don’t know what your code looks like, but that’s literally my whole file. This is a shot in the dark, but try commenting out everything after your variable declarations and see if the error goes away?

Here’s a small example to reproduce the recursion error:

class_name ExampleResource extends Resource

@export var other_example_resource: ExampleResource
@export var other_resource: Resource

Create two ExampleResource files: example_resource1.tres and example_resource2.tres.
Set example_resource1.tres variables to point at example_resource2.tres:
image
Trying to set either of example_resource2.tres’ variables to point at example_resource1.tres will give the recursion error:
3ccc0f0421a3f97d9c26477e70447767

Oh that makes sense now. I think what you need is a helper object. Like the connection lines in the AnimationTree, or in the Visual Shader interface. All it does is keep a connection of where it’s going. An arrow pointing.

class_name ExampleConnection extends Resource

@export var example_resource_link: ExampleResource
class_name ExampleResource extends Resource

@export var connection_to: ExampleConnection
@export var other_resource: Resource

func get_connection_to() -> ExampleResource:
  return connection.example_resource_link

You’re constructing a linked list. If you want a doubly-linked list so you know where you came from, you can add a second variable: @export var connection_from: ExampleConnection

That should solve your problem.

Using those classes gives the same error, unfortunately:
image
8bb14a256902d172b70d43dabc10d594

That’s really odd. I’ll think on it.

I don’t think there are any direct, built-in ways to do this in Godot currently, so I created a discussion in Proposals for it:

1 Like