From 57b81c3604590349d3106a738a604aed27bde6a7 Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Wed, 26 Mar 2025 10:55:07 -0400 Subject: [PATCH] Moving saving/loading management into SaveGameManager --- save_load/autoloads/save_game_manager.gd | 115 ++++++++++++++++-- .../components/save_level_data_component.gd | 86 +------------ 2 files changed, 111 insertions(+), 90 deletions(-) diff --git a/save_load/autoloads/save_game_manager.gd b/save_load/autoloads/save_game_manager.gd index f2fa944..9c25816 100644 --- a/save_load/autoloads/save_game_manager.gd +++ b/save_load/autoloads/save_game_manager.gd @@ -18,9 +18,18 @@ signal quick_save signal quick_load +var _game_data_resource: SaveGameDataResource +var _save_level_data_component: SaveLevelDataComponent ## Contains the save paths and filenames + + func _ready() -> void: quick_load.connect(quick_load_game) quick_save.connect(quick_load_game) + create_save_file.connect(_save_game_as_resource) + load_save_file.connect(_load_game_resource) + + _load_save_level_data_component() + func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("quick_save"): @@ -29,22 +38,108 @@ func _unhandled_input(event: InputEvent) -> void: quick_load_game() +func list_saves() -> Array[SaveFileDetailsResource]: + var save_files: Array[SaveFileDetailsResource] = [] + if not _load_save_level_data_component(): + return save_files + + var save_game_data_path: String = _save_level_data_component.save_game_data_path + 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() + + # TODO: Reconsider loading the save to get the name + # This could be a large save making opening each one slow + # Should work out a better method for getting the save name (filename != save name) + var _save_file: SaveGameDataResource = ResourceLoader.load(_save_path) + _save_resource.save_name = _save_file.save_name + + _save_resource.filename = filename + _save_resource.date_created = Time.get_datetime_string_from_unix_time(FileAccess.get_modified_time(_save_path)) + + ## In 4.5, this can probably be replaced with FileAccess.get_size(_save_path) + ## This should reduce the need for opening the file here + var _loaded_file: FileAccess = FileAccess.open(_save_path, FileAccess.READ) + _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 quick_save_game() -> void: - var save_level_data_component: SaveLevelDataComponent = get_tree().get_first_node_in_group("save_level_data_component") - if save_level_data_component == null: - push_error("Could not find SaveLevelDataComponent node in level") - return + if not _load_save_level_data_component(): return - save_level_data_component.quick_save_game() + _save_game_as_resource(_save_level_data_component.quicksave_file_name) game_saved.emit() func quick_load_game() -> void: - var save_level_data_component: SaveLevelDataComponent = get_tree().get_first_node_in_group("save_level_data_component") - if save_level_data_component == null: - push_error("Could not find SaveLevelDataComponent node in level") - return + if not _load_save_level_data_component(): return # TODO: Don't reset world if quicksave not found EntityManager.reset_world.emit() - save_level_data_component.quick_load_game() + _load_game_resource(_save_level_data_component.quicksave_file_name) game_loaded.emit() + + +## Find the SaveLevelDataComponent within the level which stores the save paths and filenames +func _load_save_level_data_component() -> bool: + _save_level_data_component = get_tree().get_first_node_in_group("save_level_data_component") + if _save_level_data_component == null: + push_error("Could not find SaveLevelDataComponent node in level") + return false + + return true + +func _load_game_resource(resource_filename: String) -> void: + if not _load_save_level_data_component(): return + var save_game_file_path: String = _save_level_data_component.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 _save_game_as_resource(resource_filename: String) -> void: + if not _load_save_level_data_component(): return + + if !DirAccess.dir_exists_absolute(_save_level_data_component.save_game_data_path): + DirAccess.make_dir_absolute(_save_level_data_component.save_game_data_path) + + var save_game_file_path: String = _save_level_data_component.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) + +## Save the properties defined on the SaveDataComponents attached to various nodes (such as Block) +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) diff --git a/save_load/components/save_level_data_component.gd b/save_load/components/save_level_data_component.gd index 48075f7..550e504 100644 --- a/save_load/components/save_level_data_component.gd +++ b/save_load/components/save_level_data_component.gd @@ -27,94 +27,20 @@ func _ready() -> void: 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() - - # TODO: Reconsider loading the save to get the name - # This could be a large save making opening each one slow - # Should work out a better method for getting the save name (filename != save name) - var _save_file: SaveGameDataResource = ResourceLoader.load(_save_path) - _save_resource.save_name = _save_file.save_name - - _save_resource.filename = filename - _save_resource.date_created = Time.get_datetime_string_from_unix_time(FileAccess.get_modified_time(_save_path)) - - ## In 4.5, this can probably be replaced with FileAccess.get_size(_save_path) - ## This should reduce the need for opening the file here - var _loaded_file: FileAccess = FileAccess.open(_save_path, FileAccess.READ) - _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) + SaveGameManager.load_save_file.emit(save_file_name % level_scene_name) func quick_load_game() -> void: - _load_game_resource(quicksave_file_name) + SaveGameManager.quick_load.emit() func quick_save_game() -> void: - _save_game_as_resource(quicksave_file_name) + SaveGameManager.quick_save.emit() 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) + SaveGameManager.create_save_file.emit(save_file_name % level_scene_name) 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") + #_save_game_as_resource(autosave_file_name % "01") + pass