From 0bab8edb659e5e882c69bf34bf775be70120cb9f Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Thu, 27 Mar 2025 20:38:59 -0400 Subject: [PATCH 01/14] Replacing filenames in save game settings with prepends --- .../autoloads/save_game_manager.gd | 15 +++++++++------ .../resources/save_game_settings_resource.gd | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index 2bb8e09..37602f1 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -57,9 +57,12 @@ func list_saves(include_quick_saves: bool = true, include_auto_saves: bool = tru for filename: String in ResourceLoader.list_directory(save_game_data_path): # TODO: Rework so the settings determine the file_name using prepends - if filename.begins_with("quicksave_") and not include_quick_saves: continue - elif filename.begins_with("autosave_") and not include_auto_saves: continue - elif !filename.begins_with("save_") and !filename.begins_with("quicksave_") and !filename.begins_with("autosave_"): continue + if filename.begins_with(_save_level_data_component.settings.quicksave_file_name_prepend) and not include_quick_saves: + continue + elif filename.begins_with(_save_level_data_component.settings.autosave_file_name_prepend) and not include_auto_saves: + continue + elif !filename.begins_with(_save_level_data_component.settings.save_file_name_prepend) and !filename.begins_with(_save_level_data_component.settings.quicksave_file_name_prepend) and !filename.begins_with(_save_level_data_component.settings.autosave_file_name_prepend): + continue var _save_path: String = save_game_data_path + filename var _save_icon: String = filename.replace(".tres", ".png") @@ -206,19 +209,19 @@ func _on_load_game_save(resource_filename: String) -> void: func _on_quick_load() -> void: if not _load_save_level_data_component(): return - _load_game_resource(_save_level_data_component.settings.quicksave_file_name) + _load_game_resource(_save_level_data_component.settings.quicksave_file_name_prepend + "game_data.tres") func _on_quick_save() -> void: if not _load_save_level_data_component(): return - _save_game_as_resource("Quick Save", _save_level_data_component.settings.quicksave_file_name) + _save_game_as_resource("Quick Save", _save_level_data_component.settings.quicksave_file_name_prepend + "game_data.tres") ## Save the game, with a filename of `.tres func _on_save_game_as_resource(save_name: String) -> void: if not _load_save_level_data_component(): return var current_date: String = Time.get_datetime_string_from_system().replace(":", "") - var _filename: String = "save_" + current_date + ".tres" + var _filename: String = _save_level_data_component.settings.save_file_name_prepend + current_date + ".tres" _loaded_save_resource.save_name = save_name _save_game_as_resource(save_name, _filename) diff --git a/addons/save_load_system/resources/save_game_settings_resource.gd b/addons/save_load_system/resources/save_game_settings_resource.gd index 4aca6b5..2621f37 100644 --- a/addons/save_load_system/resources/save_game_settings_resource.gd +++ b/addons/save_load_system/resources/save_game_settings_resource.gd @@ -10,6 +10,6 @@ extends Resource @export var save_game_data_path: String = "user://game_data/" @export var max_auto_saves: int = 5 -@export var save_file_name: String = "save_game_data.tres" -@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) +@export var save_file_name_prepend: String = "save_" +@export var quicksave_file_name_prepend: String = "quicksave_" +@export var autosave_file_name_prepend: String = "autosave_" From 4f56398134f435dce70702a407cd5d1c8318f35b Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Thu, 27 Mar 2025 20:49:53 -0400 Subject: [PATCH 02/14] Moving default_save_icon_resource from SaveLevelDataComponent to SaveGameSettings --- addons/save_load_system/autoloads/save_game_manager.gd | 4 ++-- .../components/save_level_data_component.gd | 1 - .../components/save_level_data_component.tscn | 4 +--- .../resources/save_game_settings_resource.gd | 2 ++ .../resources/save_game_settings_resource.tres | 10 ++++++---- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index 37602f1..6514985 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -114,9 +114,9 @@ func _generate_save_game_resource() -> SaveGameDataResource: func _generate_save_icon_texture(save_icon: String) -> Texture2D: var _icon_texture: Texture2D = ImageTexture.new() if save_icon != null and !FileAccess.file_exists(save_icon): - _icon_texture = _save_level_data_component.default_save_icon_resource + _icon_texture = _save_level_data_component.settings.default_save_icon_resource elif save_icon == null: - _icon_texture = _save_level_data_component.default_save_icon_resource + _icon_texture = _save_level_data_component.settings.default_save_icon_resource else: var _icon_image: Image = Image.new() _icon_image.load(save_icon) diff --git a/addons/save_load_system/components/save_level_data_component.gd b/addons/save_load_system/components/save_level_data_component.gd index d5fbc1b..f4f8e78 100644 --- a/addons/save_load_system/components/save_level_data_component.gd +++ b/addons/save_load_system/components/save_level_data_component.gd @@ -4,7 +4,6 @@ class_name SaveLevelDataComponent extends Node -@export var default_save_icon_resource: CompressedTexture2D @export var settings: SaveGameSettings ## The SaveGameSettings resource @export var ui_node: CanvasLayer ## The UI to Show/Hide when taking screenshot (e.g. save icon generation) diff --git a/addons/save_load_system/components/save_level_data_component.tscn b/addons/save_load_system/components/save_level_data_component.tscn index dc4237b..09d3906 100644 --- a/addons/save_load_system/components/save_level_data_component.tscn +++ b/addons/save_load_system/components/save_level_data_component.tscn @@ -1,10 +1,8 @@ -[gd_scene load_steps=4 format=3 uid="uid://c3pqilb6yh5kc"] +[gd_scene load_steps=3 format=3 uid="uid://c3pqilb6yh5kc"] [ext_resource type="Script" uid="uid://c7x2qvyu62230" path="res://addons/save_load_system/components/save_level_data_component.gd" id="1_exguq"] -[ext_resource type="Texture2D" uid="uid://b4lam0dwtv8fq" path="res://addons/save_load_system/default_icon.svg" id="2_hd7aa"] [ext_resource type="Resource" uid="uid://o32fooj1lxg7" path="res://addons/save_load_system/resources/save_game_settings_resource.tres" id="2_rkr1f"] [node name="SaveLevelDataComponent" type="Node"] script = ExtResource("1_exguq") -default_save_icon_resource = ExtResource("2_hd7aa") settings = ExtResource("2_rkr1f") diff --git a/addons/save_load_system/resources/save_game_settings_resource.gd b/addons/save_load_system/resources/save_game_settings_resource.gd index 2621f37..c08344a 100644 --- a/addons/save_load_system/resources/save_game_settings_resource.gd +++ b/addons/save_load_system/resources/save_game_settings_resource.gd @@ -13,3 +13,5 @@ extends Resource @export var save_file_name_prepend: String = "save_" @export var quicksave_file_name_prepend: String = "quicksave_" @export var autosave_file_name_prepend: String = "autosave_" + +@export var default_save_icon_resource: CompressedTexture2D diff --git a/addons/save_load_system/resources/save_game_settings_resource.tres b/addons/save_load_system/resources/save_game_settings_resource.tres index 74ca31e..e0b8b51 100644 --- a/addons/save_load_system/resources/save_game_settings_resource.tres +++ b/addons/save_load_system/resources/save_game_settings_resource.tres @@ -1,12 +1,14 @@ -[gd_resource type="Resource" script_class="SaveGameSettings" load_steps=2 format=3 uid="uid://o32fooj1lxg7"] +[gd_resource type="Resource" script_class="SaveGameSettings" load_steps=3 format=3 uid="uid://o32fooj1lxg7"] +[ext_resource type="Texture2D" uid="uid://b4lam0dwtv8fq" path="res://addons/save_load_system/default_icon.svg" id="1_fm0fk"] [ext_resource type="Script" uid="uid://d0iptf06t7f47" path="res://addons/save_load_system/resources/save_game_settings_resource.gd" id="1_o1tpj"] [resource] script = ExtResource("1_o1tpj") save_game_data_path = "user://game_data/" max_auto_saves = 5 -save_file_name = "save_%s_game_data.tres" -quicksave_file_name = "quicksave_game_data.tres" -autosave_file_name = "autosave_%s_game_data.tres" +save_file_name_prepend = "save_" +quicksave_file_name_prepend = "quicksave_" +autosave_file_name_prepend = "autosave_" +default_save_icon_resource = ExtResource("1_fm0fk") metadata/_custom_type_script = "uid://d0iptf06t7f47" From d4df06fc4006b658393aadd00342998aa40f65c2 Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Thu, 27 Mar 2025 20:52:26 -0400 Subject: [PATCH 03/14] Moving ui_node out of SaveLevelDataComponent into SaveLoadUI --- .../components/save_level_data_component.gd | 1 - scenes/ui/menus/saves_manager/save_load_ui.gd | 11 ++++++----- scenes/ui/ui.tscn | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/addons/save_load_system/components/save_level_data_component.gd b/addons/save_load_system/components/save_level_data_component.gd index f4f8e78..77bf043 100644 --- a/addons/save_load_system/components/save_level_data_component.gd +++ b/addons/save_load_system/components/save_level_data_component.gd @@ -5,7 +5,6 @@ extends Node @export var settings: SaveGameSettings ## The SaveGameSettings resource -@export var ui_node: CanvasLayer ## The UI to Show/Hide when taking screenshot (e.g. save icon generation) func _ready() -> void: diff --git a/scenes/ui/menus/saves_manager/save_load_ui.gd b/scenes/ui/menus/saves_manager/save_load_ui.gd index 6f92972..fff905d 100644 --- a/scenes/ui/menus/saves_manager/save_load_ui.gd +++ b/scenes/ui/menus/saves_manager/save_load_ui.gd @@ -12,6 +12,8 @@ signal open_save_list @export var create_save_button: BaseButton @export var create_save_cancel_button: BaseButton +@export var ui_node: CanvasLayer ## The UI to Show/Hide when taking screenshot (e.g. save icon generation) + func _ready() -> void: show_save_ui_button.pressed.connect(_on_show_save_ui_button_pressed) @@ -26,13 +28,12 @@ func _on_create_save_button_pressed() -> void: if save_name.strip_edges() == "": save_name = Time.get_datetime_string_from_system().replace(":", "") - var _save_level_data_component: SaveLevelDataComponent = get_tree().get_first_node_in_group("save_level_data_component") - if _save_level_data_component.ui_node != null: - _save_level_data_component.ui_node.visible = false + if ui_node != null: + ui_node.visible = false await get_tree().create_timer(.150).timeout # A hack to allow time for UI to hide before taking screenshot SaveGameManager.create_save.emit(save_name) - if _save_level_data_component.ui_node != null: - _save_level_data_component.ui_node.visible = true + if ui_node != null: + ui_node.visible = true new_save_ui.hide() SignalManager.resume_game.emit() diff --git a/scenes/ui/ui.tscn b/scenes/ui/ui.tscn index d0c4768..2b77c1f 100644 --- a/scenes/ui/ui.tscn +++ b/scenes/ui/ui.tscn @@ -38,5 +38,6 @@ save_load_ui = NodePath("../SaveLoadUI") [node name="SettingsMenu" parent="." instance=ExtResource("7_7vp6q")] visible = false -[node name="SaveLoadUI" parent="." instance=ExtResource("8_jcn1r")] +[node name="SaveLoadUI" parent="." node_paths=PackedStringArray("ui_node") instance=ExtResource("8_jcn1r")] visible = false +ui_node = NodePath("..") From 926239c32f2c74311faff5858fbfedca21395133 Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Thu, 27 Mar 2025 21:03:18 -0400 Subject: [PATCH 04/14] Simplifying the game_settings loading --- .../autoloads/save_game_manager.gd | 62 ++++++++++--------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index 6514985..b0b5f15 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -26,8 +26,8 @@ signal toggle_save_icon_generation(toggled: bool) ## Enable/Disable the generati var _enable_save_icon_generation: bool = true var _loaded_save_resource: SaveGameDataResource = SaveGameDataResource.new() +var _save_game_settings: SaveGameSettings ## Contains the save paths, filename prepends, and other save settings var _save_icon_size: Vector2i = Vector2i(896, 504) ## If Vector2.ZERO, uses the user's resolution -var _save_level_data_component: SaveLevelDataComponent ## Contains the save paths and filenames func _ready() -> void: @@ -48,20 +48,20 @@ func _unhandled_input(event: InputEvent) -> void: func list_saves(include_quick_saves: bool = true, include_auto_saves: bool = true) -> Array[SaveFileDetailsResource]: var save_files: Array[SaveFileDetailsResource] = [] - if not _load_save_level_data_component(): + if not _load_save_settings(): return save_files - var save_game_data_path: String = _save_level_data_component.settings.save_game_data_path + var save_game_data_path: String = _save_game_settings.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): # TODO: Rework so the settings determine the file_name using prepends - if filename.begins_with(_save_level_data_component.settings.quicksave_file_name_prepend) and not include_quick_saves: + if filename.begins_with(_save_game_settings.quicksave_file_name_prepend) and not include_quick_saves: continue - elif filename.begins_with(_save_level_data_component.settings.autosave_file_name_prepend) and not include_auto_saves: + elif filename.begins_with(_save_game_settings.autosave_file_name_prepend) and not include_auto_saves: continue - elif !filename.begins_with(_save_level_data_component.settings.save_file_name_prepend) and !filename.begins_with(_save_level_data_component.settings.quicksave_file_name_prepend) and !filename.begins_with(_save_level_data_component.settings.autosave_file_name_prepend): + elif !filename.begins_with(_save_game_settings.save_file_name_prepend) and !filename.begins_with(_save_game_settings.quicksave_file_name_prepend) and !filename.begins_with(_save_game_settings.autosave_file_name_prepend): continue var _save_path: String = save_game_data_path + filename @@ -114,9 +114,9 @@ func _generate_save_game_resource() -> SaveGameDataResource: func _generate_save_icon_texture(save_icon: String) -> Texture2D: var _icon_texture: Texture2D = ImageTexture.new() if save_icon != null and !FileAccess.file_exists(save_icon): - _icon_texture = _save_level_data_component.settings.default_save_icon_resource + _icon_texture = _save_game_settings.default_save_icon_resource elif save_icon == null: - _icon_texture = _save_level_data_component.settings.default_save_icon_resource + _icon_texture = _save_game_settings.default_save_icon_resource else: var _icon_image: Image = Image.new() _icon_image.load(save_icon) @@ -126,19 +126,10 @@ func _generate_save_icon_texture(save_icon: String) -> Texture2D: return _icon_texture -## Find the SaveLevelDataComponent within the level which stores the save settings -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 + if not _load_save_settings(): return - var save_game_file_path: String = _save_level_data_component.settings.save_game_data_path + resource_filename + var save_game_file_path: String = _save_game_settings.save_game_data_path + resource_filename if !FileAccess.file_exists(save_game_file_path): load_error.emit("Failed to load save. File does not exist: %s" % save_game_file_path) return @@ -150,13 +141,24 @@ func _load_game_resource(resource_filename: String) -> void: load_complete.emit() +## Find the SaveLevelDataComponent within the tree which stores the save settings +func _load_save_settings() -> bool: + 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 false + + _save_game_settings = _save_level_data_component.settings + + return true + func _save_game_as_resource(save_name, resource_filename: String) -> void: - if not _load_save_level_data_component(): return + if not _load_save_settings(): return - if !DirAccess.dir_exists_absolute(_save_level_data_component.settings.save_game_data_path): - DirAccess.make_dir_absolute(_save_level_data_component.settings.save_game_data_path) + if !DirAccess.dir_exists_absolute(_save_game_settings.save_game_data_path): + DirAccess.make_dir_absolute(_save_game_settings.save_game_data_path) - var save_game_file_path: String = _save_level_data_component.settings.save_game_data_path + resource_filename + var save_game_file_path: String = _save_game_settings.save_game_data_path + resource_filename var _save_resource: SaveGameDataResource = _generate_save_game_resource() _save_resource.save_name = save_name @@ -200,7 +202,7 @@ func _on_delete_save(filename: String) -> void: delete_error.emit("Empty filename provided") return - var save_file_path: String = _save_level_data_component.settings.save_game_data_path + filename + var save_file_path: String = _save_game_settings.save_game_data_path + filename DirAccess.remove_absolute(save_file_path) DirAccess.remove_absolute(save_file_path.replace(".tres", ".png")) # Delete icon @@ -208,20 +210,20 @@ func _on_load_game_save(resource_filename: String) -> void: _load_game_resource(resource_filename) func _on_quick_load() -> void: - if not _load_save_level_data_component(): return - _load_game_resource(_save_level_data_component.settings.quicksave_file_name_prepend + "game_data.tres") + if not _load_save_settings(): return + _load_game_resource(_save_game_settings.quicksave_file_name_prepend + "game_data.tres") func _on_quick_save() -> void: - if not _load_save_level_data_component(): return + if not _load_save_settings(): return - _save_game_as_resource("Quick Save", _save_level_data_component.settings.quicksave_file_name_prepend + "game_data.tres") + _save_game_as_resource("Quick Save", _save_game_settings.quicksave_file_name_prepend + "game_data.tres") ## Save the game, with a filename of `.tres func _on_save_game_as_resource(save_name: String) -> void: - if not _load_save_level_data_component(): return + if not _load_save_settings(): return var current_date: String = Time.get_datetime_string_from_system().replace(":", "") - var _filename: String = _save_level_data_component.settings.save_file_name_prepend + current_date + ".tres" + var _filename: String = _save_game_settings.save_file_name_prepend + current_date + ".tres" _loaded_save_resource.save_name = save_name _save_game_as_resource(save_name, _filename) From aac4dbb1d9e0b38bdc0704a122f2fd8c33375264 Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Thu, 27 Mar 2025 21:42:14 -0400 Subject: [PATCH 05/14] Initial work toward autosaves --- .../autoloads/save_game_manager.gd | 27 +++++++++++++++++-- .../resources/save_game_settings_resource.gd | 2 ++ scenes/world/world.gd | 10 +++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index b0b5f15..95f2761 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -18,6 +18,8 @@ signal load_error(error_message: String) signal load_save(filename: String) ## Loads the save into memory. Does NOT apply the load as this allows for other actions (such as resetting the levle/world).[br]Don't forget to run `apply_save` after loading signal save_complete signal save_error(error_message: String) +signal start_autosave +signal stop_autosave signal quick_save signal quick_load @@ -37,13 +39,15 @@ func _ready() -> void: load_save.connect(_on_load_game_save) quick_load.connect(_on_quick_load) quick_save.connect(_on_quick_save) + start_autosave.connect(_on_start_autosave) + stop_autosave.connect(_on_stop_autosave) toggle_save_icon_generation.connect(_on_toggle_save_icon_generation) func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("quick_save"): - _on_quick_save() + quick_save.emit() if event.is_action_pressed("quick_load"): - _on_quick_load() + quick_load.emit() func list_saves(include_quick_saves: bool = true, include_auto_saves: bool = true) -> Array[SaveFileDetailsResource]: @@ -231,3 +235,22 @@ func _on_save_game_as_resource(save_name: String) -> void: func _on_toggle_save_icon_generation(toggled: bool) -> void: _enable_save_icon_generation = toggled + + +func _on_start_autosave() -> void: + if _save_game_settings == null: _load_save_settings() + + var autosave_timer: Timer = get_node_or_null("AutosaveTimer") + if autosave_timer == null: + autosave_timer = Timer.new() + autosave_timer.name = "AutosaveTimer" + autosave_timer.one_shot = false + autosave_timer.timeout.connect(_on_autosave_timer_timeout) + add_child(autosave_timer) + + autosave_timer.start(_save_game_settings.autosave_duration) + +func _on_stop_autosave() -> void: + var autosave_timer: Timer = get_node_or_null("AutosaveTimer") + if autosave_timer == null: return + autosave_timer.stop() diff --git a/addons/save_load_system/resources/save_game_settings_resource.gd b/addons/save_load_system/resources/save_game_settings_resource.gd index c08344a..8eb4ec9 100644 --- a/addons/save_load_system/resources/save_game_settings_resource.gd +++ b/addons/save_load_system/resources/save_game_settings_resource.gd @@ -10,6 +10,8 @@ extends Resource @export var save_game_data_path: String = "user://game_data/" @export var max_auto_saves: int = 5 +@export var autosave_duration: int = 60 ## How often, in seconds, should an autosave run[br]SaveGameManager will NOT autostart the autosave timer. This must be done by the world/scene. + @export var save_file_name_prepend: String = "save_" @export var quicksave_file_name_prepend: String = "quicksave_" @export var autosave_file_name_prepend: String = "autosave_" diff --git a/scenes/world/world.gd b/scenes/world/world.gd index 6009743..a2442a8 100644 --- a/scenes/world/world.gd +++ b/scenes/world/world.gd @@ -16,9 +16,12 @@ func _ready() -> void: EntityManager.reset_world.connect(clear_world) EntityManager.spawn_player.connect(spawn_player) SaveGameManager.load_complete.connect(_on_load_save_complete) + SignalManager.open_pause_menu.connect(_on_open_pause_menu) + SignalManager.resume_game.connect(_on_resume_game) clear_world() create_world() + SaveGameManager.start_autosave.emit() ## For resetting/emptying the world to allow for load_game or generating a new world func clear_world() -> void: @@ -87,3 +90,10 @@ func _on_reset_world() -> void: func _on_load_save_complete() -> void: clear_world() SaveGameManager.apply_save.emit() + SaveGameManager.start_autosave.emit() + +func _on_open_pause_menu() -> void: + SaveGameManager.stop_autosave.emit() + +func _on_resume_game() -> void: + SaveGameManager.start_autosave.emit() From 7ab2efefc7ac720894faf74b0002204f28591df1 Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Thu, 27 Mar 2025 22:58:03 -0400 Subject: [PATCH 06/14] Adding autosave functionality --- .../autoloads/save_game_manager.gd | 47 +++++++++++++++++-- .../save_game_settings_resource.tres | 1 + 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index 95f2761..cc1437b 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -9,6 +9,8 @@ extends Node signal apply_complete signal apply_save ## Apply the loaded data to the tree. Note: This should happen AFTER load_save() +signal autosave_start ## Autosave has started +signal autosave_complete ## Autosave has completed signal create_auto_save signal create_save(save_name: String) signal delete_save(filename: String) @@ -156,6 +158,32 @@ func _load_save_settings() -> bool: return true +## Increment autosave numbers and if we've reach max number of autosaves, remove the oldest one +func _move_autosaves() -> void: + var saves_dir = DirAccess.open(_save_game_settings.save_game_data_path) + if saves_dir == null: + DirAccess.make_dir_absolute(_save_game_settings.save_game_data_path) + + var autosaves: Array[String] = [] + for filename in saves_dir.get_files(): + if !filename.begins_with(_save_game_settings.autosave_file_name_prepend): continue + if !filename.ends_with(".tres"): continue + autosaves.append(filename) + + if autosaves.size() == _save_game_settings.max_auto_saves: # Delete oldest save + DirAccess.remove_absolute(_save_game_settings.save_game_data_path + autosaves.pop_back()) + + var filepath: String = _save_game_settings.save_game_data_path + _save_game_settings.autosave_file_name_prepend + for index in range(autosaves.size(), 0, -1): + var old_save_path: String = "%s%02d.tres" % [filepath, index] + var old_screenshot_path: String = "%s%02d.png" % [filepath, index] + var new_save_path: String = "%s%02d.tres" % [filepath, index + 1] + var new_screenshot_path: String = "%s%02d.png" % [filepath, index + 1] + DirAccess.copy_absolute(old_save_path, new_save_path) + + if FileAccess.file_exists(old_screenshot_path): + DirAccess.copy_absolute(old_screenshot_path, new_screenshot_path) + func _save_game_as_resource(save_name, resource_filename: String) -> void: if not _load_save_settings(): return @@ -200,6 +228,18 @@ func _on_apply_save() -> void: apply_complete.emit() +func _on_autosave_timer_timeout() -> void: + if not _load_save_settings(): return + + autosave_start.emit() + + _move_autosaves() + + var autosave_filename: String = _save_game_settings.autosave_file_name_prepend + "01.tres" + _save_game_as_resource("Auto Save", autosave_filename) + + autosave_complete.emit() + ## Delete both the save file and the related screenshot func _on_delete_save(filename: String) -> void: if filename.length() < 1: @@ -233,10 +273,6 @@ func _on_save_game_as_resource(save_name: String) -> void: _save_game_as_resource(save_name, _filename) save_complete.emit() -func _on_toggle_save_icon_generation(toggled: bool) -> void: - _enable_save_icon_generation = toggled - - func _on_start_autosave() -> void: if _save_game_settings == null: _load_save_settings() @@ -254,3 +290,6 @@ func _on_stop_autosave() -> void: var autosave_timer: Timer = get_node_or_null("AutosaveTimer") if autosave_timer == null: return autosave_timer.stop() + +func _on_toggle_save_icon_generation(toggled: bool) -> void: + _enable_save_icon_generation = toggled diff --git a/addons/save_load_system/resources/save_game_settings_resource.tres b/addons/save_load_system/resources/save_game_settings_resource.tres index e0b8b51..35a6c09 100644 --- a/addons/save_load_system/resources/save_game_settings_resource.tres +++ b/addons/save_load_system/resources/save_game_settings_resource.tres @@ -7,6 +7,7 @@ script = ExtResource("1_o1tpj") save_game_data_path = "user://game_data/" max_auto_saves = 5 +autosave_duration = 5 save_file_name_prepend = "save_" quicksave_file_name_prepend = "quicksave_" autosave_file_name_prepend = "autosave_" From c30237b2668e0f23486c3c132041fdecd47468ba Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Thu, 27 Mar 2025 23:04:44 -0400 Subject: [PATCH 07/14] Correcting default value --- .../save_load_system/resources/save_game_settings_resource.tres | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/save_load_system/resources/save_game_settings_resource.tres b/addons/save_load_system/resources/save_game_settings_resource.tres index 35a6c09..774be9c 100644 --- a/addons/save_load_system/resources/save_game_settings_resource.tres +++ b/addons/save_load_system/resources/save_game_settings_resource.tres @@ -7,7 +7,7 @@ script = ExtResource("1_o1tpj") save_game_data_path = "user://game_data/" max_auto_saves = 5 -autosave_duration = 5 +autosave_duration = 60 save_file_name_prepend = "save_" quicksave_file_name_prepend = "quicksave_" autosave_file_name_prepend = "autosave_" From 150e01f11ea12e697b1d6fa261b176b50af5d94e Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Fri, 28 Mar 2025 09:42:19 -0400 Subject: [PATCH 08/14] Create the Autosave timer on _ready() --- .../autoloads/save_game_manager.gd | 47 +++++++++---------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index cc1437b..c8da766 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -28,6 +28,7 @@ signal quick_load signal toggle_save_icon_generation(toggled: bool) ## Enable/Disable the generation of a screenshot during save for the save icon. +var _autosave_timer: Timer = Timer.new() var _enable_save_icon_generation: bool = true var _loaded_save_resource: SaveGameDataResource = SaveGameDataResource.new() var _save_game_settings: SaveGameSettings ## Contains the save paths, filename prepends, and other save settings @@ -45,6 +46,11 @@ func _ready() -> void: stop_autosave.connect(_on_stop_autosave) toggle_save_icon_generation.connect(_on_toggle_save_icon_generation) + _autosave_timer.name = "AutosaveTimer" + _autosave_timer.one_shot = false + _autosave_timer.timeout.connect(_on_autosave_timer_timeout) + add_child(_autosave_timer) + func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("quick_save"): quick_save.emit() @@ -96,6 +102,18 @@ func list_saves(include_quick_saves: bool = true, include_auto_saves: bool = tru return save_files +func _create_autosave() -> void: + if not _load_save_settings(): return + + autosave_start.emit() + + _move_autosaves() + + var autosave_filename: String = _save_game_settings.autosave_file_name_prepend + "01.tres" + _save_game_as_resource("Auto Save", autosave_filename) + + autosave_complete.emit() + ## Sort the save files list by date created, descending func _custom_save_file_sort(a: SaveFileDetailsResource, b: SaveFileDetailsResource) -> bool: return a.date_created > b.date_created @@ -229,16 +247,7 @@ func _on_apply_save() -> void: apply_complete.emit() func _on_autosave_timer_timeout() -> void: - if not _load_save_settings(): return - - autosave_start.emit() - - _move_autosaves() - - var autosave_filename: String = _save_game_settings.autosave_file_name_prepend + "01.tres" - _save_game_as_resource("Auto Save", autosave_filename) - - autosave_complete.emit() + _create_autosave() ## Delete both the save file and the related screenshot func _on_delete_save(filename: String) -> void: @@ -274,22 +283,12 @@ func _on_save_game_as_resource(save_name: String) -> void: save_complete.emit() func _on_start_autosave() -> void: - if _save_game_settings == null: _load_save_settings() - - var autosave_timer: Timer = get_node_or_null("AutosaveTimer") - if autosave_timer == null: - autosave_timer = Timer.new() - autosave_timer.name = "AutosaveTimer" - autosave_timer.one_shot = false - autosave_timer.timeout.connect(_on_autosave_timer_timeout) - add_child(autosave_timer) - - autosave_timer.start(_save_game_settings.autosave_duration) + if _save_game_settings == null: + _load_save_settings() + _autosave_timer.start(_save_game_settings.autosave_duration) func _on_stop_autosave() -> void: - var autosave_timer: Timer = get_node_or_null("AutosaveTimer") - if autosave_timer == null: return - autosave_timer.stop() + _autosave_timer.stop() func _on_toggle_save_icon_generation(toggled: bool) -> void: _enable_save_icon_generation = toggled From 858dc90b29144e10c5db8c69bcd3b7df608d3862 Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Fri, 28 Mar 2025 09:44:15 -0400 Subject: [PATCH 09/14] Standardizing autosave name --- addons/save_load_system/autoloads/save_game_manager.gd | 10 +++++----- .../resources/save_game_settings_resource.gd | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index c8da766..f41afa9 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -9,9 +9,9 @@ extends Node signal apply_complete signal apply_save ## Apply the loaded data to the tree. Note: This should happen AFTER load_save() -signal autosave_start ## Autosave has started signal autosave_complete ## Autosave has completed -signal create_auto_save +signal autosave_start ## Autosave has started +signal create_autosave signal create_save(save_name: String) signal delete_save(filename: String) signal delete_error(error_message: String) @@ -58,7 +58,7 @@ func _unhandled_input(event: InputEvent) -> void: quick_load.emit() -func list_saves(include_quick_saves: bool = true, include_auto_saves: bool = true) -> Array[SaveFileDetailsResource]: +func list_saves(include_quick_saves: bool = true, include_autosaves: bool = true) -> Array[SaveFileDetailsResource]: var save_files: Array[SaveFileDetailsResource] = [] if not _load_save_settings(): return save_files @@ -71,7 +71,7 @@ func list_saves(include_quick_saves: bool = true, include_auto_saves: bool = tru # TODO: Rework so the settings determine the file_name using prepends if filename.begins_with(_save_game_settings.quicksave_file_name_prepend) and not include_quick_saves: continue - elif filename.begins_with(_save_game_settings.autosave_file_name_prepend) and not include_auto_saves: + elif filename.begins_with(_save_game_settings.autosave_file_name_prepend) and not include_autosaves: continue elif !filename.begins_with(_save_game_settings.save_file_name_prepend) and !filename.begins_with(_save_game_settings.quicksave_file_name_prepend) and !filename.begins_with(_save_game_settings.autosave_file_name_prepend): continue @@ -188,7 +188,7 @@ func _move_autosaves() -> void: if !filename.ends_with(".tres"): continue autosaves.append(filename) - if autosaves.size() == _save_game_settings.max_auto_saves: # Delete oldest save + if autosaves.size() == _save_game_settings.max_autosaves: # Delete oldest save DirAccess.remove_absolute(_save_game_settings.save_game_data_path + autosaves.pop_back()) var filepath: String = _save_game_settings.save_game_data_path + _save_game_settings.autosave_file_name_prepend diff --git a/addons/save_load_system/resources/save_game_settings_resource.gd b/addons/save_load_system/resources/save_game_settings_resource.gd index 8eb4ec9..907aa61 100644 --- a/addons/save_load_system/resources/save_game_settings_resource.gd +++ b/addons/save_load_system/resources/save_game_settings_resource.gd @@ -8,7 +8,7 @@ extends Resource ## * 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 var max_autosaves: int = 5 @export var autosave_duration: int = 60 ## How often, in seconds, should an autosave run[br]SaveGameManager will NOT autostart the autosave timer. This must be done by the world/scene. From 15a1fd8cc67b43cce98315a8e7efce21b71056bb Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Fri, 28 Mar 2025 09:46:03 -0400 Subject: [PATCH 10/14] Renaming _move_autosaves() to _rotate_autosaves() --- addons/save_load_system/autoloads/save_game_manager.gd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index f41afa9..062cbf3 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -107,7 +107,7 @@ func _create_autosave() -> void: autosave_start.emit() - _move_autosaves() + _rotate_autosaves() var autosave_filename: String = _save_game_settings.autosave_file_name_prepend + "01.tres" _save_game_as_resource("Auto Save", autosave_filename) @@ -177,7 +177,7 @@ func _load_save_settings() -> bool: return true ## Increment autosave numbers and if we've reach max number of autosaves, remove the oldest one -func _move_autosaves() -> void: +func _rotate_autosaves() -> void: var saves_dir = DirAccess.open(_save_game_settings.save_game_data_path) if saves_dir == null: DirAccess.make_dir_absolute(_save_game_settings.save_game_data_path) From 48e52f43172f004faeb0097f0bd94b9089a56fd7 Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Fri, 28 Mar 2025 10:59:35 -0400 Subject: [PATCH 11/14] Adding autosave notification --- .../autoloads/save_game_manager.gd | 2 + .../save_game_settings_resource.tres | 2 +- assets/ui/spinner-clockwise.png | Bin 0 -> 6509 bytes assets/ui/spinner-clockwise.png.import | 34 +++++++ scenes/ui/autosave_notification.gd | 26 ++++++ scenes/ui/autosave_notification.gd.uid | 1 + scenes/ui/autosave_notification.tscn | 87 ++++++++++++++++++ scenes/ui/ui.tscn | 6 +- 8 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 assets/ui/spinner-clockwise.png create mode 100644 assets/ui/spinner-clockwise.png.import create mode 100644 scenes/ui/autosave_notification.gd create mode 100644 scenes/ui/autosave_notification.gd.uid create mode 100644 scenes/ui/autosave_notification.tscn diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index 062cbf3..51374e8 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -105,6 +105,7 @@ func list_saves(include_quick_saves: bool = true, include_autosaves: bool = true func _create_autosave() -> void: if not _load_save_settings(): return + _autosave_timer.stop() autosave_start.emit() _rotate_autosaves() @@ -113,6 +114,7 @@ func _create_autosave() -> void: _save_game_as_resource("Auto Save", autosave_filename) autosave_complete.emit() + _autosave_timer.start(_save_game_settings.autosave_duration) ## Sort the save files list by date created, descending func _custom_save_file_sort(a: SaveFileDetailsResource, b: SaveFileDetailsResource) -> bool: diff --git a/addons/save_load_system/resources/save_game_settings_resource.tres b/addons/save_load_system/resources/save_game_settings_resource.tres index 774be9c..7532c75 100644 --- a/addons/save_load_system/resources/save_game_settings_resource.tres +++ b/addons/save_load_system/resources/save_game_settings_resource.tres @@ -6,8 +6,8 @@ [resource] script = ExtResource("1_o1tpj") save_game_data_path = "user://game_data/" -max_auto_saves = 5 autosave_duration = 60 +max_autosaves = 5 save_file_name_prepend = "save_" quicksave_file_name_prepend = "quicksave_" autosave_file_name_prepend = "autosave_" diff --git a/assets/ui/spinner-clockwise.png b/assets/ui/spinner-clockwise.png new file mode 100644 index 0000000000000000000000000000000000000000..83bae9c1898bf97339e8f45633bddc1aff010eb9 GIT binary patch literal 6509 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 void: + SaveGameManager.autosave_start.connect(_on_autosave_start) + SaveGameManager.autosave_complete.connect(_on_autosave_complete) + visible = false + +func _on_autosave_start() -> void: + animation_player.play("spin") + visible = true + +func _on_autosave_complete() -> void: + # This is for testing. Saving seems to be fast making the autosave disappear immediately. + # It's not clear the cause. + # Additionally, the displaying of UI element is inconsistent. Sometimes I need to print(visible) to force it to show up, although I have no idea why that works + # TODO: Figure out what the hell is going on here + print(visible) + await get_tree().create_timer(3).timeout + + animation_player.stop() + visible = false diff --git a/scenes/ui/autosave_notification.gd.uid b/scenes/ui/autosave_notification.gd.uid new file mode 100644 index 0000000..f491611 --- /dev/null +++ b/scenes/ui/autosave_notification.gd.uid @@ -0,0 +1 @@ +uid://db0pkuhbcmfkb diff --git a/scenes/ui/autosave_notification.tscn b/scenes/ui/autosave_notification.tscn new file mode 100644 index 0000000..b8b3f3a --- /dev/null +++ b/scenes/ui/autosave_notification.tscn @@ -0,0 +1,87 @@ +[gd_scene load_steps=6 format=3 uid="uid://rfknvv8b0d4i"] + +[ext_resource type="Texture2D" uid="uid://bsfqsslfq53dn" path="res://assets/ui/spinner-clockwise.png" id="1_2tr78"] +[ext_resource type="Script" uid="uid://db0pkuhbcmfkb" path="res://scenes/ui/autosave_notification.gd" id="1_rdcu1"] + +[sub_resource type="Animation" id="Animation_y220t"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Icon/TextureRect:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [0.0] +} + +[sub_resource type="Animation" id="Animation_uegxj"] +resource_name = "spin" +loop_mode = 1 +step = 0.1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Icon/TextureRect:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.0, 6.28319] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_4kltc"] +_data = { +&"RESET": SubResource("Animation_y220t"), +&"spin": SubResource("Animation_uegxj") +} + +[node name="AutosaveNotification" type="MarginContainer" node_paths=PackedStringArray("animation_player")] +process_mode = 3 +z_index = 1 +anchors_preset = 1 +anchor_left = 1.0 +anchor_right = 1.0 +offset_left = -164.0 +offset_bottom = 60.0 +grow_horizontal = 0 +theme_override_constants/margin_left = 10 +theme_override_constants/margin_top = 10 +theme_override_constants/margin_right = 10 +theme_override_constants/margin_bottom = 10 +script = ExtResource("1_rdcu1") +animation_player = NodePath("AnimationPlayer") + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +layout_mode = 2 + +[node name="Icon" type="Control" parent="HBoxContainer"] +custom_minimum_size = Vector2(40, 40) +layout_mode = 2 + +[node name="TextureRect" type="TextureRect" parent="HBoxContainer/Icon"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +pivot_offset = Vector2(20, 20) +texture = ExtResource("1_2tr78") +expand_mode = 3 + +[node name="Label" type="Label" parent="HBoxContainer"] +layout_mode = 2 +theme_override_colors/font_color = Color(0.944248, 0.414786, 0.141556, 1) +theme_override_colors/font_outline_color = Color(1, 1, 1, 1) +text = "Autosaving..." +vertical_alignment = 1 + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +root_node = NodePath("../HBoxContainer") +libraries = { +&"": SubResource("AnimationLibrary_4kltc") +} +autoplay = "spin" diff --git a/scenes/ui/ui.tscn b/scenes/ui/ui.tscn index 2b77c1f..3db600e 100644 --- a/scenes/ui/ui.tscn +++ b/scenes/ui/ui.tscn @@ -1,10 +1,11 @@ -[gd_scene load_steps=7 format=3 uid="uid://c7fj7wla8bd70"] +[gd_scene load_steps=8 format=3 uid="uid://c7fj7wla8bd70"] [ext_resource type="Script" uid="uid://bslimr2y4lnvq" path="res://scenes/ui/ui.gd" id="1_aac20"] [ext_resource type="PackedScene" uid="uid://dvogu3djluqsn" path="res://scenes/ui/waila.tscn" id="1_u7n8c"] [ext_resource type="PackedScene" uid="uid://cbiygbgpfk220" path="res://scenes/ui/quick_slots.tscn" id="4_g5kmx"] [ext_resource type="PackedScene" uid="uid://bopvfwcgnnawg" path="res://scenes/ui/menus/pause_menu.tscn" id="6_7vp6q"] [ext_resource type="PackedScene" uid="uid://4bdgwwx27m71" path="res://scenes/ui/menus/settings_menu.tscn" id="7_7vp6q"] +[ext_resource type="PackedScene" uid="uid://rfknvv8b0d4i" path="res://scenes/ui/autosave_notification.tscn" id="7_jcn1r"] [ext_resource type="PackedScene" uid="uid://dauchkhmnyk7n" path="res://scenes/ui/menus/saves_manager/save_load_ui.tscn" id="8_jcn1r"] [node name="UI" type="CanvasLayer"] @@ -41,3 +42,6 @@ visible = false [node name="SaveLoadUI" parent="." node_paths=PackedStringArray("ui_node") instance=ExtResource("8_jcn1r")] visible = false ui_node = NodePath("..") + +[node name="AutosaveNotification" parent="." instance=ExtResource("7_jcn1r")] +visible = false From 8d5146fd09871f139d5b80a30863a107c5b81c3f Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Fri, 28 Mar 2025 14:53:32 -0400 Subject: [PATCH 12/14] Updating comments --- scenes/ui/autosave_notification.gd | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scenes/ui/autosave_notification.gd b/scenes/ui/autosave_notification.gd index f94d28f..480e23a 100644 --- a/scenes/ui/autosave_notification.gd +++ b/scenes/ui/autosave_notification.gd @@ -15,11 +15,10 @@ func _on_autosave_start() -> void: visible = true func _on_autosave_complete() -> void: - # This is for testing. Saving seems to be fast making the autosave disappear immediately. - # It's not clear the cause. - # Additionally, the displaying of UI element is inconsistent. Sometimes I need to print(visible) to force it to show up, although I have no idea why that works + # This is for testing. The displaying of UI element is inconsistent. + # Sometimes I need to print(visible) to force it to show up, although I have no idea why that works. It might not actually be doing anything and is just randomish. # TODO: Figure out what the hell is going on here - print(visible) + #print(visible) await get_tree().create_timer(3).timeout animation_player.stop() From 15efc6145d3a352c8e32ab987feb4db4e0b4ba81 Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Fri, 28 Mar 2025 15:07:22 -0400 Subject: [PATCH 13/14] Renaming date_created to save_date and adding to save file instead of using file modified date --- addons/save_load_system/autoloads/save_game_manager.gd | 5 +++-- .../save_load_system/resources/save_file_details_resource.gd | 2 +- addons/save_load_system/resources/save_game_data_resource.gd | 1 + scenes/ui/menus/saves_manager/save_file.gd | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/save_load_system/autoloads/save_game_manager.gd b/addons/save_load_system/autoloads/save_game_manager.gd index 51374e8..61e4c86 100644 --- a/addons/save_load_system/autoloads/save_game_manager.gd +++ b/addons/save_load_system/autoloads/save_game_manager.gd @@ -85,9 +85,9 @@ func list_saves(include_quick_saves: bool = true, include_autosaves: bool = true # 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.save_date = _save_file.save_date _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 @@ -118,7 +118,7 @@ func _create_autosave() -> void: ## Sort the save files list by date created, descending func _custom_save_file_sort(a: SaveFileDetailsResource, b: SaveFileDetailsResource) -> bool: - return a.date_created > b.date_created + return a.save_date > b.save_date ## Save the properties defined on the SaveDataComponents attached to various nodes (such as Block) func _generate_save_game_resource() -> SaveGameDataResource: @@ -214,6 +214,7 @@ func _save_game_as_resource(save_name, resource_filename: String) -> void: var _save_resource: SaveGameDataResource = _generate_save_game_resource() _save_resource.save_name = save_name + _save_resource.save_date = Time.get_datetime_string_from_system(false, true) var result: int = ResourceSaver.save(_save_resource, save_game_file_path) if result != OK: diff --git a/addons/save_load_system/resources/save_file_details_resource.gd b/addons/save_load_system/resources/save_file_details_resource.gd index 882ebd9..bc0b61d 100644 --- a/addons/save_load_system/resources/save_file_details_resource.gd +++ b/addons/save_load_system/resources/save_file_details_resource.gd @@ -6,6 +6,6 @@ extends Node @export var save_name: String = "My Save" @export var filename: String = "" -@export var date_created: String = "" +@export var save_date: String = "" @export var filesize: int = 0 @export var save_icon_texture: Texture2D diff --git a/addons/save_load_system/resources/save_game_data_resource.gd b/addons/save_load_system/resources/save_game_data_resource.gd index 44210ff..3da5a77 100644 --- a/addons/save_load_system/resources/save_game_data_resource.gd +++ b/addons/save_load_system/resources/save_game_data_resource.gd @@ -8,3 +8,4 @@ extends Resource @export var save_data_nodes: Array[Node3DDataResource] @export var save_name: String +@export var save_date: String diff --git a/scenes/ui/menus/saves_manager/save_file.gd b/scenes/ui/menus/saves_manager/save_file.gd index 0f9728f..1a22a55 100644 --- a/scenes/ui/menus/saves_manager/save_file.gd +++ b/scenes/ui/menus/saves_manager/save_file.gd @@ -36,7 +36,7 @@ func initialize(_resource: SaveFileDetailsResource) -> void: set_save_name() func set_save_date() -> void: - save_date_label.text = save_file_details.date_created + save_date_label.text = save_file_details.save_date func set_save_icon() -> void: save_icon.texture = save_file_details.save_icon_texture From ba7c0e2bf314d1335a5f9d85b56ed354e5a4904e Mon Sep 17 00:00:00 2001 From: Ryan Reed Date: Fri, 28 Mar 2025 15:10:10 -0400 Subject: [PATCH 14/14] Updating default save name text --- scenes/ui/menus/saves_manager/save_load_ui.gd | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scenes/ui/menus/saves_manager/save_load_ui.gd b/scenes/ui/menus/saves_manager/save_load_ui.gd index fff905d..6b718a3 100644 --- a/scenes/ui/menus/saves_manager/save_load_ui.gd +++ b/scenes/ui/menus/saves_manager/save_load_ui.gd @@ -26,7 +26,7 @@ func _ready() -> void: func _on_create_save_button_pressed() -> void: var save_name: String = save_name_input.text if save_name.strip_edges() == "": - save_name = Time.get_datetime_string_from_system().replace(":", "") + save_name = Time.get_datetime_string_from_system(false, true) if ui_node != null: ui_node.visible = false @@ -41,6 +41,5 @@ func _on_create_save_cancel_button_pressed() -> void: new_save_ui.hide() func _on_show_save_ui_button_pressed() -> void: - var current_date: String = Time.get_datetime_string_from_system() - save_name_input.text = current_date.replace(":", "") + save_name_input.text = Time.get_datetime_string_from_system(false, true) new_save_ui.show()