diff --git a/src/game/engine/src/core/save_manager.gd b/src/game/engine/src/core/save_manager.gd index dcad4771..f7ebc3db 100644 --- a/src/game/engine/src/core/save_manager.gd +++ b/src/game/engine/src/core/save_manager.gd @@ -105,10 +105,19 @@ static func _ensure_save_dir() -> Error: return err -static func _write_slot(slot_name: String) -> Error: - var dir_err: Error = _ensure_save_dir() - if dir_err != OK: - return dir_err +static func save_to_path(abs_path: String, indented: bool = false) -> Error: + ## Write a full GameState envelope to an arbitrary absolute path. Creates the + ## containing directory if missing. Sorted keys are always on so re-saving the + ## same state is byte-identical; `indented` toggles tab indent (true) vs + ## compact (false). Compact is intended for hot-path per-turn saves. + var dir_path: String = abs_path.get_base_dir() + if dir_path != "" and not DirAccess.dir_exists_absolute(dir_path): + var dir_err: Error = DirAccess.make_dir_recursive_absolute(dir_path) + if dir_err != OK: + push_error( + "SaveManager: cannot create '%s': %s" % [dir_path, error_string(dir_err)] + ) + return dir_err var envelope: Dictionary = { "version": SAVE_VERSION, @@ -116,14 +125,14 @@ static func _write_slot(slot_name: String) -> Error: "game_state": GameState.serialize(), } - # Sorted keys + tab indent so re-saving the same state is byte-identical. - var json_text: String = JSON.stringify(envelope, "\t", true) - var path: String = _path_for(slot_name) - var file: FileAccess = FileAccess.open(path, FileAccess.WRITE) + # Sorted keys always on so re-saving the same state is byte-identical. + var indent: String = "\t" if indented else "" + var json_text: String = JSON.stringify(envelope, indent, true) + var file: FileAccess = FileAccess.open(abs_path, FileAccess.WRITE) if file == null: var open_err: Error = FileAccess.get_open_error() push_error( - "SaveManager: cannot write '%s': %s" % [path, error_string(open_err)] + "SaveManager: cannot write '%s': %s" % [abs_path, error_string(open_err)] ) return open_err if open_err != OK else FAILED @@ -132,6 +141,10 @@ static func _write_slot(slot_name: String) -> Error: return OK +static func _write_slot(slot_name: String) -> Error: + return save_to_path(_path_for(slot_name), true) + + static func _read_slot(slot_name: String) -> Error: var envelope: Dictionary = _read_envelope(slot_name) if envelope.is_empty():