Godot Save System tutorial EOF Error

Godot Version

4.2

Question

Im using the godot 4 tutorial on a save a load system. And while a lot of the tutorial is copy pasted I have changed it to suit my needs.

My issues arises when it comes to loading the state of an item the player picks up. When the character picks up the item a bool variable changes to show it has picked up and it uses queue_free() to delete the item. I then press a button to save the game. So far that works but when I press another button to load the game the item returns and it doesnt reflect the change it supposed. The item is supposed to delete itself in the ready function if the item had been picked up which it hasnt. And I get the following error:

JSON Parse Error: Expected ‘EOF’ in {“filename”:“res://Items/key_item_1.tscn”,“isPickedUp”:false,“parent”:“/root/Hallway”,“posX”:-36,“posY”:42}{“filename”:“res://Items/key_item_1.tscn”,“isPickedUp”:false,“parent”:“/root/Hallway”,“posX”:52,“posY”:42} at line 0

Here is the code of my save system:

extends Node

const saveFile = "user://savefile.save"
var currentScene

func _process(delta):
	if Input.is_action_just_pressed("Key"):
		print("howdy folks")
		SaveGame()
	if Input.is_action_just_pressed("Key2"):
		LoadGame()

func SaveGame():
	#SAVE THE CURRENT SCENE------------------
	var data = {
		"savedCurrentScene" = get_tree().get_current_scene().scene_file_path
	}
	var file = FileAccess.open(saveFile, FileAccess.WRITE)
	file.store_var(data)
	#-----------------------------------
	
	#SAVE OBJECTS---------------------
	var saveNodes = get_tree().get_nodes_in_group("SaveObjects")
	for nodes in saveNodes:
		if nodes.scene_file_path.is_empty():
			print("Node '%s' is not instantiated and will be skipped" % nodes.name)
			continue
		if !nodes.has_method("Save"):
			print("Node '%s' doesnt have a save function and will be skipped" % nodes.name)
			continue
		var nodeData = nodes.call("Save")
	
		var jsonString = JSON.stringify(nodeData)
		file.store_string(jsonString)
	#-------------------------------------------------
	
	print("Curent Scene Saved" + get_tree().get_current_scene().name)
	print("Game was Saved")
	
func LoadGame():
	if not FileAccess.file_exists(saveFile):
		SaveGame()
	
	var file = FileAccess.open(saveFile,FileAccess.READ)
	var savedata = file.get_var()
	currentScene = savedata.savedCurrentScene
	#file = null
	get_tree().change_scene_to_file(currentScene)
	
	var saveNodes = get_tree().get_nodes_in_group("SaveObjects")
	for nodes in saveNodes:
		nodes.queue_free()
		await nodes.tree_exited
	while file.get_position() < file.get_length():
		var json_string = file.get_line()
		var json = JSON.new()
		var parse_result = json.parse(json_string)
		if not parse_result == OK:
			print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
			continue
			
		var nodeData = json.data
		var new_object = load(nodeData["filename"]).instantiate()
		get_node(nodeData["parent"]).add_child(new_object)
		new_object.position = Vector2(nodeData["posX"], nodeData["posY"])
		for i in nodeData.keys():
			if i == "filename" or i == "parent" or i == "pos_x" or i == "pos_y":
				continue
			new_object.set(i, nodeData[i])
	file = null
	print("Game was Loaded")

Heres the code of the item im picking up:

extends Node

class_name Key

@export var Picture : Resource
@export var keyName : String
@export var ItemPicture : Resource
@onready var sprite_2d = $Sprite2D
@export var isPickedUp : bool

signal ItemLabel

func _ready():
	if isPickedUp == true:
		queue_free()
	sprite_2d.texture =ItemPicture
func _on_area_2d_body_entered(body):
	if body is Player:
		var newKey = Key.new()
		newKey.keyName = keyName
		newKey.Picture = Picture
		Globalplayerstats.keyChain.insert(0,newKey)
		print("I added key")
		#print(Globalplayerstats.keyChain[0].keyName)
		ItemLabel.emit(Globalplayerstats.keyChain[0].keyName)
		isPickedUp = true
		queue_free()
func Save():
	var dict = {
		"filename" : get_scene_file_path(),
		"parent" : get_parent().get_path(),
		"posX" : self.position.x,
		"posY" : self.position.y,
		"isPickedUp" : isPickedUp
		
	}
	print("I have been picked up")
	return dict

You can install this library:

And then replace your code with this:

extends Node

const sceneFile = "user://scenefile.save"
const nodeFile = "user://nodefile.json"
var currentScene

func _process(delta):
	if Input.is_action_just_pressed("Key"):
		print("howdy folks")
		SaveGame()
	if Input.is_action_just_pressed("Key2"):
		LoadGame()

func SaveGame():
	#SAVE THE CURRENT SCENE------------------
	SLib.save_file(sceneFile, {"savedCurrentScene" = get_tree().get_current_scene().scene_file_path})
	#-----------------------------------
	
	#SAVE OBJECTS---------------------
	var saveNodes = get_tree().get_nodes_in_group("SaveObjects")

	var nodesData: Array
	for nodes in saveNodes:
		if nodes.scene_file_path.is_empty():
			print("Node '%s' is not instantiated and will be skipped" % nodes.name)
			continue
		if !nodes.has_method("Save"):
			print("Node '%s' doesnt have a save function and will be skipped" % nodes.name)
			continue
		var nodeData = nodes.call("Save")
		nodesData.append(nodeData)
	SLib.save_json_file(nodeFile, nodesData)
	#-------------------------------------------------
	
	print("Current Scene Saved: " + get_tree().get_current_scene().name)
	print("Game was Saved")
	
func LoadGame():
	if not FileAccess.file_exists(sceneFile):
		SaveGame()
	
	currentScene = SLib.load_file(sceneFile)
	get_tree().change_scene_to_file(currentScene)
	
	var saveNodes = get_tree().get_nodes_in_group("SaveObjects")
	for nodes in saveNodes:
		nodes.queue_free()
		await nodes.tree_exited
	var savedNodes = SLib.load_json_file(nodeFile)
	for nodeData in savedNodes:
		var new_object = load(nodeData["filename"]).instantiate()
		get_node(nodeData["parent"]).add_child(new_object)
		new_object.position = Vector2(nodeData["posX"], nodeData["posY"])
		for i in nodeData.keys():
			if i == "filename" or i == "parent" or i == "pos_x" or i == "pos_y":
				continue
			new_object.set(i, nodeData[i])
	print("Game was Loaded")

You use store_string to save the jsonString, but get_line to retrieve it. You can see that it’s retrieving multiple json strings, because store_string does not add a new line. Try using file.store_line(jsonString)


@Mahan Sorry to say SLib does not append to files, so your example code will overwrite nodeFile again and again, resulting in only ever writing the last json string to the file.

Yes, there was a well-established part, I fixed it, I think it works now.

Yeah this worked for me thank you so much!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.