Trouble with saving user files

Godot Version

v4.1.2.stable.official [399c9dc39]

Question

I have this code for saving data, which works fine for everything including saving and loading the textures that I have in res://, but when the path is from the user file system it doesn’t work. At least I think that’s the problem, I’m not sure. I asked an AI for help and that did not work. When I print button_data[“texture”], I don’t get anything. Again, this works when the texture is from res:// but not when it’s from the file system.

I can provide more info if needed. Thanks for the help.

extends Button

func save_game(): 
	var save_file = "user://savegame.json"
	
	var file = FileAccess.open(save_file, FileAccess.WRITE) 
	var image_objects = get_tree().get_nodes_in_group("ImageObjects")
	var text_objects = get_tree().get_nodes_in_group("TextObjects")
	var saved_data = {}
	saved_data["buttons"] = []
	saved_data["texts"] = []

	for child in image_objects:
		if child is TextureButton:
			var button_data = {}
			button_data["positionX"] = child.global_position.x
			button_data["positionY"] = child.global_position.y
			button_data["sizeX"] = child.size.x
			button_data["sizeY"] = child.size.y
			button_data["name"] = child.name
			button_data["texture"] = child.texture_normal.get_path() #Trying to save the texture here.
			saved_data["buttons"].append(button_data)
			
	for child in text_objects:
		if child is Button:
			var text_data = {}
			text_data["positionX"] = child.global_position.x
			text_data["positionY"] = child.global_position.y
			text_data["sizeX"] = child.size.x
			text_data["sizeY"] = child.size.y
			text_data["name"] = child.name
			text_data["text"] = child.text
			saved_data["texts"].append(text_data)
			
	var json = JSON.stringify(saved_data)
	file.store_string(json)
	file.close()

	print("Saved project to ", save_file, " successfully.")
	
func load_data(): 
	var CopyImage = $"../../../../Copys/CopyImage"
	var CopyText = $"../../../../Copys/CopyText"
	
	var save_file = "user://savegame.json"
	
	var file = FileAccess.open(save_file, FileAccess.READ) 
	var image_objects = get_tree().get_nodes_in_group("ImageObjects")
	var text_objects = get_tree().get_nodes_in_group("TextObjects")
	var json = file.get_as_text()
	var saved_data = JSON.parse_string(json)
	var new_parent = $"../../../../OnSceneItems"
	
	for child in image_objects:
		if child is TextureButton:
			child.queue_free()

	for button_data in saved_data["buttons"]:
		var button = CopyImage.duplicate()
		button.visible = true
		button.add_to_group("ImageObjects")
		add_child(button)
		button.reparent(new_parent)
		button.global_position.x = button_data["positionX"]
		button.global_position.y = button_data["positionY"]
		button.size.x = button_data["sizeX"]
		button.size.y = button_data["sizeY"]
		button.set_name(button_data["name"]) 
		print("Texture: ", button_data["texture"])
		
		button.texture_normal.set_path(button_data["texture"])


	for child in text_objects:
		child.queue_free()
		
	for text_data in saved_data["texts"]:
		var textobject = CopyText.duplicate()
		textobject.visible = true
		textobject.add_to_group("TextObjects")
		add_child(textobject)
		textobject.reparent(new_parent)
		textobject.global_position.x = text_data["positionX"]
		textobject.global_position.y = text_data["positionY"]
		textobject.size.x = text_data["sizeX"]
		textobject.size.y = text_data["sizeY"]
		textobject.set_name(text_data["name"])
		textobject.text = text_data["text"]
	
	print("Loaded: ", save_file, " successfully.")
	file.close()
	
func _on_load_pressed(): 
	load_data()

func _on_pressed(): 
	save_game()

Do this:

const path_start = "user://folder_name/"
const path_end = ".save"
func save(path, content):
	var f = File.new()
	f.open(path_start+path+path_end, File.WRITE)
	f.store_var(content)
	f.close()
func l(path, content):
	var f = File.new()
	if f.file_exists(path_start+path+path_end):
		var error = f.open(path_start+path+path_end, File.READ)
		if error == OK:
			content = f.get_var()
			f.close()
	return content

This simply stores what you put in content under the vile with the name

Good Luck :wink:

In your load_data function, you write:

button.texture_normal.set_path(button_data["texture"])

My understanding is that this should be used to modify the save path of an existing resource, not to directly load things, which might explain why it works when your texture is in res://.

Try this instead:

var img: Image = Image.load_from_file(button_data["texture"])
var tex: Texture2D = ImageTexture.create_from_image(img)
if img == null or tex == null:
    # handle error here
else:
    button.texture_normal = tex

Don’t use the load("...") function, because to use it, the resource has to already be imported by the editor, and so it won’t work with paths outside of res://.
You can find more information at the godot docs page for load.

Also see Image.load_from_file and ImageTexture.create_from_image

When I run this, I get the error “Error opening file '<Image#-9223371995582823157>”, and then subsequent errors caused by this.

I think this is going down the right path though.