[DEV] Add Auto Save / Load System
This Game is made on Godot,
In this engine I never made a custom Save System so I did one that is global and don't need much to add more to the save file.
I made a global Save System for Nodes and Resources files.
I choose tu use the Built in Godot Resources and made the base save file code:
extends Resource class_name SaveRes @export var saved_nodes: Dictionary[NodePath, Variant] = {} @export var time: Dictionary
For saving any resource in game I created a function using get_property_list():
static func save_obj(in_object: Object) -> Dictionary[String, Variant]: var save_data: Dictionary[String, Variant] = {} for i: int in range(0, in_object.get_property_list().size(), 1): var var_data: Dictionary = in_object.get_property_list()[i] #Skip the resource base variable if var_data["name"].is_empty(): continue #Skip the @export_group if var_data["type"] == 0: continue #Save the resources by calling the same method recurcively if var_data["type"] == 24: var sub_object: Object = in_object.get(var_data["name"]) if sub_object == null: save_data[var_data["name"]] = null elif sub_object is Resource: save_data[var_data["name"]] = save_obj(sub_object) else: # Save save_data[var_data["name"]] = in_object.get(var_data["name"]) return save_data
To load the resources:
static func load_data_obj(in_object: Object, in_data: Dictionary[String, Variant]) -> void: for i: int in range(0, in_object.get_property_list().size(), 1): var var_data: Dictionary = in_object.get_property_list()[i] if var_data["name"].is_empty(): continue if not in_data.has(var_data["name"]): continue if var_data["type"] == 24: if in_data[var_data["name"]].has("resource_path") and not in_data[var_data["name"]]["resource_path"].is_empty(): if in_object.get(var_data["name"]) != null and in_object.get(var_data["name"]).resource_path == in_data[var_data["name"]]["resource_path"]: continue print(var_data["name"], " -> load(", in_data[var_data["name"]]["resource_path"], ")") in_object.set(var_data["name"], load(in_data[var_data["name"]]["resource_path"])) elif in_object.get(var_data["name"]) != null: load_data_obj(in_object.get(var_data["name"]), in_data[var_data["name"]]) in_object.set(var_data["name"], in_data[var_data["name"]])
And then a Save System for the nodes in the scene using the get_script().get_script_property_list()
I decide to create a custom function get_all_children_whith_variable() instead of using Godot Built in groups. it's easier for me and i can use the saveable variable in my scripts if i need to customise my save calls
func call_save() -> void: var saved_nodes: Dictionary[NodePath, Variant] = {} var to_save_nodes: Array[Node] = Utils.get_all_children_whith_variable(get_tree().root, "saveable") for node: Node in to_save_nodes: print("Saved: ", node.name) var path: NodePath = node.get_path() saved_nodes[path] = {} var list: Array[Dictionary] = node.get_script().get_script_property_list() for dict: Dictionary in list: # Skip saveable var if dict["name"] == "saveable": continue # Skip the @export_group() if dict["type"] == 0: continue # Skip Node Refs if dict["type"] == 24 && (node.get(dict["name"]) == null or node.get(dict["name"]) is Node): continue if dict["type"] != 24: saved_nodes[path][dict["name"]] = node.get(dict["name"]) else: saved_nodes[path][dict["name"]] = AutoSaveRes.save_obj(node.get(dict["name"])) var save: SaveRes = SaveRes.new() save.saved_nodes = saved_nodes save.time = Time.get_datetime_dict_from_system() ResourceSaver.save(save, "user://savegame.res")
In the Node Scripts I want to save i just need to put a const or var named saveable:
const saveable: bool = true
then the Loading System use the set_deffered from godot:
func call_load() -> void: if not FileAccess.file_exists("user://savegame.res"): return var save = ResourceLoader.load("user://savegame.res") if save == null: printerr("Failed to load user://savegame.res") return for node_path: NodePath in save.saved_nodes: var node: Node = get_node(node_path) if node == null: printerr("Load Failed for ", node_path.get_name(node_path.get_name_count() - 1)) continue for var_name: String in save.saved_nodes[node_path]: if not var_name in node: printerr("Load Failed for ", node.get_name(), ": The node dosen't has a property named: ", var_name) continue node.set_deferred(var_name, save.saved_nodes[node_path][var_name])
Thanks for Reading !
Leave a comment
Log in with itch.io to leave a comment.