[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.