|
## Performs the actual saving and loading of data related to this level/scene
|
|
## Utilized by the SaveGameManager
|
|
class_name SaveLevelDataComponent
|
|
extends Node
|
|
|
|
## See documentation to where this path is: https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html#accessing-persistent-user-data-user[br][br]
|
|
## Default Paths:[br]
|
|
## * Windows: %APPDATA%\Godot\app_userdata\[project_name][br]
|
|
## * macOS: ~/Library/Application Support/Godot/app_userdata/[project_name][br]
|
|
## * Linux: ~/.local/share/godot/app_userdata/[project_name][br]
|
|
@export var save_game_data_path: String = "user://game_data/"
|
|
@export var max_auto_saves: int = 5
|
|
|
|
@export_group("Save File Names")
|
|
@export var save_file_name: String = "save_%s_game_data.tres" ## %s is the level name
|
|
@export var quicksave_file_name: String = "quicksave_game_data.tres"
|
|
@export var autosave_file_name: String = "autosave_%s_game_data.tres" ## %s is the save number (probably 01)
|
|
|
|
var level_scene_name: String
|
|
var game_data_resource: SaveGameDataResource
|
|
|
|
|
|
func _ready() -> void:
|
|
add_to_group("save_level_data_component")
|
|
level_scene_name = get_parent().name
|
|
|
|
SaveGameManager.create_auto_save_file.connect(_on_create_auto_save_file)
|
|
|
|
|
|
func list_saves() -> Array[SaveFileDetailsResource]: # TODO: Update hints
|
|
var save_files: Array[SaveFileDetailsResource] = []
|
|
if !DirAccess.dir_exists_absolute(save_game_data_path):
|
|
return save_files
|
|
|
|
for filename: String in ResourceLoader.list_directory(save_game_data_path):
|
|
if !filename.begins_with("save_"): continue
|
|
if !filename.ends_with(".tres"): continue # Screenshots, etc
|
|
|
|
var _save_path: String = save_game_data_path + filename
|
|
var _save_icon: String = filename.replace(".tres", ".png")
|
|
var _save_resource: SaveFileDetailsResource = SaveFileDetailsResource.new()
|
|
var _loaded_file: FileAccess = FileAccess.open(_save_path, FileAccess.READ)
|
|
|
|
_save_resource.filename = filename
|
|
_save_resource.date_created = Time.get_datetime_string_from_unix_time(FileAccess.get_modified_time(_save_path))
|
|
_save_resource.filesize = _loaded_file.get_length()
|
|
|
|
if FileAccess.file_exists(save_game_data_path + _save_icon):
|
|
_save_resource.save_icon = _save_icon
|
|
|
|
save_files.append(_save_resource)
|
|
|
|
return save_files
|
|
|
|
func load_game() -> void:
|
|
_load_game_resource(save_file_name % level_scene_name)
|
|
|
|
func quick_load_game() -> void:
|
|
_load_game_resource(quicksave_file_name)
|
|
|
|
func quick_save_game() -> void:
|
|
_save_game_as_resource(quicksave_file_name)
|
|
|
|
func save_game() -> void:
|
|
_save_game_as_resource(save_file_name % level_scene_name)
|
|
|
|
func save_node_data() -> void:
|
|
var nodes: Array = get_tree().get_nodes_in_group("save_data_component")
|
|
|
|
if nodes == null: return
|
|
|
|
game_data_resource = SaveGameDataResource.new()
|
|
for node: Node in nodes:
|
|
if node is SaveDataComponent:
|
|
@warning_ignore("unsafe_method_access")
|
|
var save_data_resource: Node3DDataResource = node._save_data()
|
|
var save_final_resource: Node3DDataResource = save_data_resource.duplicate()
|
|
game_data_resource.save_data_nodes.append(save_final_resource)
|
|
|
|
|
|
func _save_game_as_resource(resource_filename: String) -> void:
|
|
if !DirAccess.dir_exists_absolute(save_game_data_path):
|
|
DirAccess.make_dir_absolute(save_game_data_path)
|
|
|
|
var save_game_file_path: String = save_game_data_path + resource_filename
|
|
save_node_data()
|
|
|
|
var result: int = ResourceSaver.save(game_data_resource, save_game_file_path)
|
|
if result != OK:
|
|
printerr("Failed to save game: ", result)
|
|
|
|
func _load_game_resource(resource_filename: String) -> void:
|
|
var save_game_file_path: String = save_game_data_path + resource_filename
|
|
if !FileAccess.file_exists(save_game_file_path):
|
|
printerr("Failed to load save. File does not exist: ", save_game_file_path)
|
|
return
|
|
|
|
game_data_resource = ResourceLoader.load(save_game_file_path)
|
|
if game_data_resource == null:
|
|
printerr("Failed to load save. Unknown format? ", save_game_file_path)
|
|
return
|
|
|
|
var root_node: Window = get_tree().root
|
|
for resource: Resource in game_data_resource.save_data_nodes:
|
|
if resource is Node3DDataResource:
|
|
(resource as Node3DDataResource)._load_data(root_node)
|
|
|
|
|
|
func _on_create_auto_save_file() -> void:
|
|
# TODO: Check max number of autosaves, increment existing autosaves, etc
|
|
_save_game_as_resource(autosave_file_name % "01")
|