ResourceSaver returns a non critical error on save method

Godot Version

4.2.2

Question

Hello everyone!

I am trying to save the data of my player’s profile into a specific file.
Maybe the approch is not great, but I felt like having a save file for each profile was good.

The drawback is that I cannot preload the profile saves as they might be created/deleted/renamed at run time.

When I am saving the progression of the player via:
‘ResourceSaver.save(current_profile)’, the following message occurs:
“Resource was not pre cached for the resource section, bug?”

It is to be noted that, the save is done correctly and the method returns OK.

Thanks for the help.

You should provide a path, if you haven’t specified one already for the resource.

1 Like

Hey, thanks for your time
I indeed give a path I omitted it in the question as a path is not needed if your resource.resource_path is set
Sorry if the question is not clear, I’ll update it as soon as I get more insight

This is what I have done and have no issue.

var player_config : PlayerConfig # extends resource
const player_config_data_path : String = "user://player_config.tres"

# saving
ResourceSaver.save(player_config, player_config_data_path)

# loading
player_config = ResourceLoader.load(player_config_data_path,"PlayerConfig", ResourceLoader.CACHE_MODE_REPLACE)

I have a very similar setup:

var current_profile: String = ""
var profile: ProfileData # extends Resource

func save_profile():
	assert(profile != null, "Cannot save profile, profile is null")

	var save_return: int

	save_return = ResourceSaver.save(profile, current_profile)
	if save_return != OK:
		print("Error saving profile")
		assert(false)


func load_profile():
	var loaded_profile: ProfileData = ResourceLoader.load(current_profile, "ProfileData", ResourceLoader.CACHE_MODE_IGNORE)

	if loaded_profile == null:
		print("Error loading profile")
		assert(false)

	profile = loaded_profile

It really confuses me that everything works correctly but the engine still print the error which can be tracked down here :

But I have to stop fidelling around and start reading the source code to deeply understand this case

Thanks again though!

There is an if statement in the code that check if the resource is built in. How was the profile first created and does it have a tres file associated with it?

Maybe it could be that you provided an empty path to the saver and it will try to go to the resource next. But before it does it fails on this test.

The creation of the profile.tres is done by the first call of ResourceSaver.save(profile)

with profile.resource_path being: user://saves/profile.tres

Noteworthy:
saving a .res and not a .tres does not create the warning line.

Maybe I should not saves tres and uses .dat or .ini but it feels more like a workaround than a real solution now

Is that the whole script? It’s really weird, I can’t replicate

The issue was larger than I thought:

The ResourceSaver is the one reporting it, but it is the saved resource that causes the bug, After some cross testing, here is what came out:

func create_profile(new_profile: String):
	profile = ProfileData.new()
    # If the next line is deleted, the bug disappears.
	profile.unlock_archetype(GameData.iunctus_archetypes[0])
	profile.take_over_path(new_profile)
	save_profile()

Well heading to unlock_archetype then:

func unlock_archetype(archetype: IunctusData):
	unlock_archetypes.append(archetype.duplicate(true))
    # If the next line is deleted, the bug disappears.
	unlock_archetypes[-1].level_system = IunctusLevelSystem.new()

From there we have two possibilities, it can be tracked down to the level_system setter:

@export var level_system: IunctusLevelSystem = null:
	set(value):
		level_system = value
		if level_system != null:
            # If the next line is deleted, the bug disappears.
			level_system.iunctus = self

And here we are at the end of the line.

Setting the field to self cause the ResourceSaver.save to write:

Resource was not pre cached for the resource section, bug?

It is to note that if level_system.iunctus is set to something else, for exemple IunctusData.new() it will not cause any issues.
It is the reference to self that seems to confuse the saver.

If we have a look at the saved profile.tres:

[sub_resource type="Resource" id="Resource_wspf8"]
script = ExtResource("2_q3w88")
iunctus = null
xp_pool = 0
level = 0
current_xp = 0
target_xp = 100

We can indeed see that the field iunctus is null and not a reference like we could hope for.

How can it be fixed

It can be fixed by not assigning to self but by giving a weak reference to it:

level_system.iunctus = weakref(self)

Thanks everyone for the help

1 Like

oh boy, wild Allow circular dependencies/references for resources in export var · Issue #7363 · godotengine/godot-proposals · GitHub on the run.

We love cross referencing things (Godot does not)

1 Like