Loading file not working

Godot Version

V4.7

Question

Hi, I’m having some trouble when it comes to saving. I tested saving and loading before in a previous game, and the saving and loading did work.

However, I’m not sure why the load function is not working on this game. I did not copy and paste the code, the file name is different, and the file does exist.

SaveData script.

class_name SaveGame
extends Resource

const FILE_PATH := "user://boardacudasave.tres"

@export var coin_amount : int

SaveLoad script. The return is just to check if the file exists. Removing it does not change anything.

extends Node

const FILE_PATH := "user://boardacudasave.tres"

var save_file_data : SaveGame = SaveGame.new()

func save_game() -> void:
	ResourceSaver.save(save_file_data, FILE_PATH)

func load_game() -> bool:
	if FileAccess.file_exists(FILE_PATH):
		save_file_data = ResourceLoader.load(FILE_PATH).duplicate(true)
		return true
	else:
		return false

func _reset_save_file() -> void:
	save_file_data = SaveGame.new()
	save_game()

There’s a few ways to save the game, so that’s why it’s a function.

func save_activate() -> void:
	SaveLoad.save_file_data.coin_amount = GlobalScore.total_coins
	print(SaveLoad.save_file_data.coin_amount)
	# If I collected 5 coins, it would print out five.

On the main menu, there’s a load button. Pressing the load button without closing the game loads with the correct amount of coins.

func _on_load_game_pressed() -> void:
	SaveLoad.load_game()
	
	GlobalScore.total_coins = SaveLoad.save_file_data.coin_amount

Edit:

Loading the game always gives back 0.

Also, I mentioned the previous game as it’s practically set up the same. Also the SaveLoad is global.

It’s hard to tell since I suspect the problem is somewhere else in your code, but two things stood out to me:

Since you are using a Resource to save, perhaps you should use ResourceLoader.exists() instead.

But the second thing, you should avoid using Resources to save your game, as it allows code execution.

Yeah, okay, after watching a tutorial, it’s now a JSON, and it loads.

However, I want to make sure that I get the correct values on my pc, or just see what it looks like. Notepad allowed me to see the variables with resource save, however, for JSON, it’s in another language.

Do I open it with a different file? What file?

This should not happen, this is most likely an issue with your notepad or the way you save the file. Can you show us your current save function?

In the SaveLoad script

extends Node

const FILE_PATH := "user://boardacudasave.json"

func save_game() -> void:
	# Write to file
	var ba_file : FileAccess = FileAccess.open(FILE_PATH, FileAccess.WRITE)
	# Store variable inside the file
	ba_file.store_var(save_data)
	ba_file.close()

In save game

extends Control

# Multiple things can save
func save_activate() -> void:
	SaveLoad.save_data.coin_amount = GlobalScore.total_coins

	SaveLoad.save_game()

What is save_data? If it’s a normal variable, you need to turn it into a json string first using stringify.

var save_data : Dictionary = {
	"coin_amount": 0,
	}

Also, if I print all values in save_data when I load the scene, it prints out the correct amount.

func _ready() -> void:
	SaveLoad.load_game()
	
	for i in SaveLoad.save_data:
		print(i)
		print(SaveLoad.save_data[i])

image

As mentioned above, you need to use the stringify function. And when you load it from the file, you need to parse it.

Okay, I’m reading through it, and I’m very confused.

What am I supposed to do after I turn it into a string? How do I send the data to the file? What am I supposed to do with the parse?

I probably missed something, but here’s the code SaveLoad code. I haven’t changed that much overall.

extends Node

const FILE_PATH := "user://asave.json"

var save_data : Dictionary = {
	"coin_amount": 0,
}

# Stringify and parse maybe. IDK
var data_send = JSON.stringify(save_data)
var data_return = JSON.parse_string(data_send)

func save_game() -> void:
	# Write to file
	var ba_file : FileAccess = FileAccess.open(FILE_PATH, FileAccess.WRITE)
	# Store variable inside the file
	ba_file.store_var(save_data)
	ba_file.close()

func load_game() -> bool:
	# Check if file exists
	if FileAccess.file_exists(FILE_PATH):
		# Read from file
		var ba_file : FileAccess = FileAccess.open(FILE_PATH, FileAccess.READ)
		# Hold variable inside of the file
		var data : Dictionary = ba_file.get_var()
		for i in data:
			if save_data.has(i):
				save_data[i] = data[i]
		ba_file.close()
		return true
	else:
		return false

func new_game() -> void:
	SaveLoad.save_data.coin_amount = 0

Saving. Different scene:

func save_activate() -> void:
	SaveLoad.save_data.coin_amount = GlobalScore.total_coins
	# Call save_game() from SaveLoad

	SaveLoad.save_game()

Loading from menu.:

func _on_load_game_pressed() -> void:
	SaveLoad.load_game()
	# Calls load_game() from SaveLoad
	
	GlobalScore.total_coins = SaveLoad.save_data.coin_amount

You are supposed to turn the Variable into a string, then you store that string (text) into a file as a normal file write operation.

When you read the file back (aka load the file), you have to turn the string back into the Variable you originally started with. You do this DURING saving AND loading.

During saving, you have to use stringify to turn the CURRENT data / variable into a string that is human-readable and can easily be saved to a file, then saved it.

Then during LOADING, you have to parse that human readable text back into the variable you need, and then set it.

This by itself does nothing at all. You are supposed to do the first one before you write the data_send (the text you get back from the stringify function) to a file, since at that point, data_send is a human readable json.

Then, during loading, when you READ that human readable text back, you are supposed to do parse_string and set the result of that to be your data, whatever it is, in this case, probably save_data.

In a side note, if you stringify the entire save_data variable, you don’t need to manually go through each data of it when you load it. You can simply load the text from the file, use parse_string, and set save_data to be equal to what you get back.

I’ve linked you the page in the documentation above that explains all of this in great detail with plenty of examples:

Yeah, IDK anymore.

func save_game() -> void:
	# Write to file
	var ba_file : FileAccess = FileAccess.open(FILE_PATH, FileAccess.WRITE)
	# Store variable inside the file
	#ba_file.store_var(save_data)
	var json_string = JSON.stringify(SaveLoad.save_data)
	ba_file.store_line(json_string)
	ba_file.close()

func load_game() -> bool:
	# Check if file exists
	if FileAccess.file_exists(FILE_PATH):
		# Read from file
		
		var ba_file : FileAccess = FileAccess.open(FILE_PATH, FileAccess.READ)
		# Hold variable inside of the file
		while ba_file.get_position() < ba_file.get_length():
			var json_string = ba_file.get_line()
			# By the wav, even with json = Json.new(), I can't do parse
			var parse_result = JSON.parse_string(json_string)
			
			if not parse_result == OK:
				print("IDK any more")
				continue
			
			var node_data = JSON.data
			
			# Not going to lie, none of this feels nessccessayt whatsoever. I don't even care about spelling anymore
			var new_object = load(node_data["filename"]).instantiate()
			get_node(node_data["parent"]).add_child(new_object)
			new_object.position = Vector2(node_data["pos_x"], node_data["pos_y"])
			
			for i in node_data.keys():
				if i == "filename" or i == "parent" or i == "pos_x" or i == "pos_y":
					continue
				new_object.set(i, node_data[i])
			get_node(node_data)
		#var data : Dictionary = ba_file.get_var()
		#for i in data:
			#if save_data.has(i):
				#save_data[i] = data[i]
		ba_file.close()
		return true
	else:
		return false

Holy errors

Hmm, okay, update

Let me show you the keys/values/whatever inside of my code:

extends Node

const FILE_PATH := "user://boardacudasave.json"

var save_data : Dictionary = {
	"coin_amount": 0,
	"duck_amount": 0,
	"health_upgrades": 0,
	"air_upgrades": 0.0,
	"bubble_upgrades": 0,
	"skate_upgrades": 0,
	"current_hat": "Nothing",
	"Top Hat": false,
	"Propeller": false,
	"Snorkel": false,
	"Sunglasses": false,
	"spawn_rate": 0,
}

var json_string_test = JSON.stringify(save_data)

func save_game() -> void:
	# Write to file
	var ba_file : FileAccess = FileAccess.open(FILE_PATH, FileAccess.WRITE)
	# Store variable inside the file
	json_string_test = JSON.stringify(save_data)
	ba_file.store_var(json_string_test)
	ba_file.close()

func load_game() -> bool:
	# Check if file exists
	if FileAccess.file_exists(FILE_PATH):
		# Read from file
		var ba_file : FileAccess = FileAccess.open(FILE_PATH, FileAccess.READ)
		# Hold variable inside of the file
		var parse_result = JSON.parse_string(json_string_test)

		## Printing the parse
		print(parse_result)
		var data = ba_file.get_var()
		for i in data:
			if save_data.has(i):
				save_data[i] = data[i]
		ba_file.close()
		return true
	else:
		return false

# PLEASE IGNORE
func new_game() -> void:
	# I AM BEGGING YOU, IGNORE. I WILL FIX THIS/SORT THIS!
	SaveLoad.save_data.coin_amount = 0
	SaveLoad.save_data.duck_amount = 0
	SaveLoad.save_data.health_upgrades = 0
	SaveLoad.save_data.air_upgrades = 0
	SaveLoad.save_data.bubble_upgrades = 0
	SaveLoad.save_data.skate_upgrades = 0
	SaveLoad.save_data.current_hat = "Nothing"
	SaveLoad.save_data["Top Hat"] = false
	SaveLoad.save_data.Propeller = false
	SaveLoad.save_data.Snorkel = false
	SaveLoad.save_data.Sunglasses = false
	SaveLoad.save_data.spawn_rate = 0
	
	GlobalScore.total_coins = 0
	GlobalScore.ducks = 0
	GlobalUpgrade.total_health_upgrade = 0
	GlobalUpgrade.total_air_upgrade = 0
	GlobalUpgrade.total_bubble_upgrade = 0
	GlobalUpgrade.total_skate_upgrade = 0
	GlobalUpgrade.currently_wearing = "Nothing"
	for i in GlobalUpgrade.hat_bought:
		GlobalUpgrade.hat_bought[i] = false
	GlobalUpgrade.spawn_rate_increase = 0

I have a print in the loading script

image

First 8 things skipped from save_data. Coins definitely don’t save.

You didn’t actually save the string you got back from the stringify function. Also you are overcomplicating a few things, here’s a script that does what you likely want:

extends Node

const FILE_PATH := "user://boardacudasave.json"

var save_data : Dictionary = {
	"coin_amount": 0,
	"duck_amount": 0,
	"health_upgrades": 0,
	"air_upgrades": 0.0,
	"bubble_upgrades": 0,
	"skate_upgrades": 0,
	"current_hat": "Nothing",
	"Top Hat": false,
	"Propeller": false,
	"Snorkel": false,
	"Sunglasses": false,
	"spawn_rate": 0,
}

func save_game() -> void:
	var saveFile : FileAccess = FileAccess.open(FILE_PATH, FileAccess.WRITE)
	var jsonString = JSON.stringify(save_data)
	saveFile.store_string(jsonString)

func load_game() -> bool:
	if !FileAccess.file_exists(FILE_PATH):
		print("Save file not found!")
		return false
	
	var saveFile: FileAccess = FileAccess.open(FILE_PATH, FileAccess.READ)
	var jsonText: String = saveFile.get_as_text()
	
	var parseResult: Variant = JSON.parse_string(jsonText)
	
	if parseResult == null:
		print("Something went wrong while loading the file.")
		return false
	
	save_data = parseResult
	return true

Ah, thank you! This is working now. And the notepad is readable.

I will have to test out the saving, but again, thank you!