@ -7,38 +7,43 @@
extends Node
signal game_saved
signal game_loaded
signal create_auto_save_file
signal create_save_file ( save_name : String )
signal delete_save_file ( filename : String )
signal load_save_file ( filename : String )
signal apply_complete
signal apply_save ## Apply the loaded data to the tree. Note: This should happen AFTER load_save()
signal create_auto_save
signal create_save ( save_name : String )
signal delete_save ( filename : String )
signal delete_error ( error_message : String )
signal load_complete
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 quick_save
signal quick_load
signal open_save_list_ui
signal close_save_list_ui
signal toggle_save_icon_generation ( toggled : bool ) ## Enable/Disable the generation of a screenshot during save for the save icon.
var _enable_save_icon_generation : bool = true
var _game_data _resource : SaveGameDataResource = SaveGameDataResource . new ( )
var _loaded_save _resource : SaveGameDataResource = SaveGameDataResource . new ( )
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 :
quick_load . connect ( quick_load_game )
quick_save . connect ( quick_load_game )
create_save_file . connect ( _on_save_game_as_resource )
load_save_file . connect ( load_game_save )
delete_save_file . connect ( _on_delete_save_file )
apply_save . connect ( _on_apply_save )
create_save . connect ( _on_save_game_as_resource )
delete_save . connect ( _on_delete_save )
load_save . connect ( _on_load_game_save )
quick_load . connect ( _on_quick_load )
quick_save . connect ( _on_quick_save )
toggle_save_icon_generation . connect ( _on_toggle_save_icon_generation )
func _unhandled_input ( event : InputEvent ) - > void :
if event . is_action_pressed ( " quick_save " ) :
quick_save_gam e ( )
_on_ quick_save( )
if event . is_action_pressed ( " quick_load " ) :
quick_load_game ( )
_on_ quick_load( )
func list_saves ( include_quick_saves : bool = true , include_auto_saves : bool = true ) - > Array [ SaveFileDetailsResource ] :
@ -81,27 +86,26 @@ func list_saves(include_quick_saves: bool = true, include_auto_saves: bool = tru
save_files . sort_custom ( _custom_save_file_sort )
return save_files
func load_game_save ( resource_filename : String ) - > void :
_load_game_resource ( resource_filename )
game_loaded . emit ( )
func quick_save_game ( ) - > void :
if not _load_save_level_data_component ( ) : return
_game_data_resource . save_name = " Quick Save "
_save_game_as_resource ( _save_level_data_component . settings . quicksave_file_name )
game_saved . 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
func quick_load_game ( ) - > void :
if not _load_save_level_data_component ( ) : return
## Save the properties defined on the SaveDataComponents attached to various nodes (such as Block)
func _generate_save_game_resource ( ) - > SaveGameDataResource :
var nodes : Array = get_tree ( ) . get_nodes_in_group ( " save_data_component " )
_load_game_resource ( _save_level_data_component . settings . quicksave_file_name )
game_loaded . emit ( )
if nodes == null : return
var _resource : SaveGameDataResource = 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 ( )
_resource . save_data_nodes . append ( save_final_resource )
## 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 _resource
## Generate the texture for use in the save file listing
func _generate_save_icon_texture ( save_icon : String ) - > Texture2D :
@ -133,48 +137,34 @@ func _load_game_resource(resource_filename: String) -> void:
var save_game_file_path : String = _save_level_data_component . settings . 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 )
load_error . emit ( " Failed to load save. File does not exist: %s " % 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 )
_loaded_save _resource = ResourceLoader . load ( save_game_file_path )
if _loaded_save _resource == null :
load_error . emit ( " Failed to load save. Unknown format? %s " % save_game_file_path )
return
EntityManager . reset_world . emit ( )
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 )
load_complete . emit ( )
func _save_game_as_resource ( resource_filename : String ) - > void :
func _save_game_as_resource ( save_name , resource_filename : String ) - > void :
if not _load_save_level_data_component ( ) : 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 )
var save_game_file_path : String = _save_level_data_component . settings . save_game_data_path + resource_filename
_save_node_data ( )
var result : int = ResourceSaver . save ( _game_data_resource , save_game_file_path )
var _save_resource : SaveGameDataResource = _generate_save_game_resource ( )
_save_resource . save_name = save_name
var result : int = ResourceSaver . save ( _save_resource , save_game_file_path )
if result != OK :
printerr ( " Failed to save game ( " , result , " ): " , save_game_file_path )
save_error . emit ( " Failed to save game ( " , result , " ): " + save_game_file_path )
return
_take_save_screenshot ( save_game_file_path )
## 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
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 )
save_complete . emit ( )
## Takes a screenshot and saves next to the save file[br]
## The icon utilizes the same filename as the save file, replacing `.tres` with `.png`
@ -190,26 +180,49 @@ func _take_save_screenshot(save_game_file_path: String) -> void:
_icon . save_png ( _icon_filepath )
## Save the game, with a filename of `<save_prepend><current_date>.tres
func _on_save_game_as_resource ( save_name : String ) - > void :
if not _load_save_level_data_component ( ) : return
## Apply the loaded save. Should be performed after load_save
func _on_apply_save ( ) - > void :
if _loaded_save_resource == null : return
var current_date : String = Time . get_datetime_string_from_system ( ) . replace ( " : " , " " )
var _filename : String = " save_ " + current_date + " .tres "
var root_node : Window = get_tree ( ) . root
for resource : Resource in _loaded_save_resource . save_data_nodes :
if resource is Node3DDataResource :
( resource as Node3DDataResource ) . _load_data ( root_node )
_game_data_resource . save_name = save_name
_save_game_as_resource ( _filename )
game_saved . emit ( )
apply_complete . emit ( )
## Delete both the save file and the related screenshot
func _on_delete_save_file ( filename : String ) - > void :
func _on_delete_save ( filename : String ) - > void :
if filename . length ( ) < 1 :
printerr ( " _on_delete_save_file(): Empty filename provided" )
delete_error . emit ( " Empty filename provided " )
return
var save_file_path : String = _save_level_data_component . settings . save_game_data_path + filename
DirAccess . remove_absolute ( save_file_path )
DirAccess . remove_absolute ( save_file_path . replace ( " .tres " , " .png " ) ) # Delete icon
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 )
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 the game, with a filename of `<save_prepend><current_date>.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 "
_loaded_save_resource . save_name = save_name
_save_game_as_resource ( save_name , _filename )
save_complete . emit ( )
func _on_toggle_save_icon_generation ( toggled : bool ) - > void :
_enable_save_icon_generation = toggled