Save Scene Variables Showcase

I’d like to showcase a script I made to save variables to file per scene (something I could not find much on). Say you have a 15 scripts with 5-10+ variables in each, and want to implement a save system; you go to browse the save to file tutorials and find that they save variables to file manually ex. (file.store_var(variable_name) /variable_name = file.get_var()). This is fine if you’re working with a few variables, but to have to update the script every time you added a variable seemed daunting to me. So, I made this script; it reads all the variables you have in the script you paste it in, then saves the order of the names in a list, then sends the state of each variable to file. For example, var test = ‘test’, it’ll save what order the variable test came in, while sending the data, ‘test’, to file. Then when you load the data, it sets the variables back to their corresponding data. There may be more elegant solutions, but I was not able to find them, so I made my own. I’ll do code comments to walk you through the code. Add load_data() to your script’s ready function, and under load_data(), replace ‘Globals.save_data.connect(save)’ with whatever signal you want to prompt your scenes to save.
P.S. I hope my comments make sense, this is the first thing like this I’m uploading.

IMPORTANT: WHEN ADDING NEW VARIABLES, DO IT AFTER YOUR LAST TYPED ONE, AND MAKE SURE IT’S STATIC TYPED! Then, any changes afterwords will need to be changed remotely then saved, it won’t save your default values after you introduce them.

Second Edit: any variables you assign with a godot object/ script, take for example a variable that accesses a global script: “var global = Global_script”, this will break anything that tries to call it like global.save_data(), because it will be saved as that global scripts ID, not the script itself. A very easy solution to this is to put static before your variable name, (static var global = global_script), as it will get filtered out when you access your variable list, as it is not a changeable property.

func save(): #Call with a signal when you want to save all your scenes, can even split up signals to only save current scenes.
	var save_path = "user://%s.save" % str(name) #this just sets the save path to be the name of your node.
	var file = FileAccess.open(save_path, FileAccess.WRITE)
	var variable_list = get_final_variable_list(0) #calls to get variable list with ID = 0 to continue past the return.
	for variable_name in variable_list: #gets variable names from the variable list created in the function.
		file.store_var(get(variable_name)) #we do get(variable_name) here to get the variables data, ie, true/false, "string", etc.
func load_data(): #load_data() should be called whenever in your scene's _ready or via a load button.
	Globals.save_data.connect(save) #THIS IS WHERE YOU CONNECT A NEW SIGNAL!
	var save_path = "user://%s.save" % str(name)
	if FileAccess.file_exists(save_path): #checks if your save_path exists, if it does, continues.
		var file = FileAccess.open(save_path, FileAccess.READ) 
		var variable_list = get_final_variable_list(1) #calls get_variable_list with 1 to return just the names of the variables. 
		var number = 0 #this number will increment in the for loop.
		for variable_name in variable_list: #for variable_name(this calls the variable data you stored in your save function)
			variable_name = file.get_var(true) #this sets variable name to the first point of variable data.
			set(variable_list[number], variable_name) #variable_list[number] calls the name of the x variable, then set's it's corresponding data.
			number += 1 
	else: #this works to set your defaults, so whatever you have your variables set to in your script by ddefault.
		print('no data saved')
		var variable_list = get_final_variable_list(1)
		var variable_status = get_final_variable_list(0)
		var number = 0
		for variable_state in variable_status:
			set(variable_list[number], get(variable_state))
			number += 1
func get_final_variable_list(ID): #this figures out what your variable state currently is, I.E, true/false, string info, etc.
	var variable_list = []
	var final_var_list = {}
	var property_list = $".".get_property_list() #this calls the property list of your node, which returns a long string of info, we cut it down to what we need later.
	for property in property_list:
		variable_list.append(property.name)
	while variable_list[0] != get_script().get_path().reverse().split("/",0)[0].reverse(): #the long scary text gets the name of the script 100% with some fuckery lol
		variable_list.remove_at(0) #cuts the extra fluff out of the property_list function at the name of your script
	variable_list.remove_at(0) #this cut's out the actual name of the script.
	if ID == 1:
		return variable_list
	for variable in variable_list:
		final_var_list.get_or_add(variable, get(variable)) #get the variable and adds both it's name and its state into the dictionary.
	print(final_var_list) #this is only here for debugging. feel free to comment out.
	return final_var_list
2 Likes