xiandie/manager/archive_manager/archive_manager.gd

195 lines
6.1 KiB
GDScript

@tool
extends Node
signal archive_loaded
@export var user_root_dir := "user://data/" # must end with "/"
@export var archive_dir := "user://data/archives/"
@export var archive_prefix := "save"
@export var archive: AssembledArchive # current archive
var archives: Array[int] # archive id list in ascending order
var autosave_timer := Timer.new()
func _ready() -> void:
# 禁用默认退出行为,在 _notification 处理 NOTIFICATION_WM_CLOSE_REQUEST 时保存数据
get_tree().set_auto_accept_quit(false)
if not _check_dirs_and_archives():
_handle_load_error("存档目录", "读写")
return
autosave_timer.timeout.connect(_try_auto_save)
autosave_timer.stop()
add_child(autosave_timer)
# config should be loaded first
load_config()
# 在 debug or editor 模式下,直接保证有 archive
if GlobalConfig.DEBUG or Engine.is_editor_hint():
if archives.size() == 0:
create_and_use_new_archive()
else:
GlobalConfigManager.config.current_selected_archive_id = archives[0]
func _notification(what):
# handle window close request
if what == NOTIFICATION_WM_CLOSE_REQUEST:
save_all()
if has_node("/root/Main"):
print("Saved all success before Quit")
SceneManager.pop_notification("已保存所有数据")
var tree = get_tree()
tree.create_timer(1.5).timeout.connect(tree.quit)
else:
get_tree().quit()
func _on_archive_id_changed():
var selected_id = GlobalConfigManager.config.current_selected_archive_id
if archive:
if selected_id != archive.archive_id:
ResourceSaver.save(archive)
archive = null
else:
return
if selected_id < 0:
return
var path = archive_dir + archive_prefix + str(selected_id) + GlobalConfig.RES_FILE_FORMAT
archive = ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_REPLACE_DEEP)
if !archive:
create_and_use_new_archive(selected_id)
SceneManager.pop_notification("已创建新存档")
else:
load_archive()
# emit signal
archive_loaded.emit()
func check_autosave_options():
if not GlobalConfigManager.config.auto_save_enabled:
autosave_timer.stop()
elif archive and GlobalConfigManager.config.auto_save_seconds > 1:
# reset left time
autosave_timer.stop()
autosave_timer.one_shot = false
autosave_timer.wait_time = GlobalConfigManager.config.auto_save_seconds
autosave_timer.start()
if GlobalConfig.DEBUG:
print(
"check_autosave_options:",
GlobalConfigManager.config.auto_save_enabled,
autosave_timer.wait_time
)
func _try_auto_save():
if GlobalConfig.DEBUG:
print("Auto save")
if archive and GlobalConfigManager.config.auto_save_seconds > 1:
save_all()
SceneManager.pop_notification("自动保存成功")
func _check_dirs_and_archives() -> bool:
if !DirAccess.dir_exists_absolute(user_root_dir):
DirAccess.make_dir_recursive_absolute(user_root_dir)
print("Create user_root_dir:", user_root_dir)
# Check if the archive directory is accessible
if !DirAccess.dir_exists_absolute(archive_dir):
DirAccess.make_dir_recursive_absolute(archive_dir)
print("Create archive_dir:", archive_dir)
var archive_dir_access = DirAccess.open(archive_dir)
if !archive_dir_access:
_handle_load_error("存档目录", "读取")
# TODO pop up a dialog to inform the user
return false
archives.clear()
var files = archive_dir_access.get_files()
# get archive number
for file in files:
if file.begins_with(archive_prefix):
var id_str = file.substr(archive_prefix.length())
var id = int(id_str)
archives.append(id)
archives.sort()
return true
# id = -1 means create a new archive, otherwise create an archive with the given id
func create_and_use_new_archive(id := -1) -> void:
_check_dirs_and_archives()
archive = AssembledArchive.new()
var archive_path = archive_dir + archive_prefix + str(id) + GlobalConfig.RES_FILE_FORMAT
if id < 0:
id = 0
# find a new id
archive_path = (archive_dir + archive_prefix + str(id) + GlobalConfig.RES_FILE_FORMAT)
while FileAccess.file_exists(archive_path):
id += 1
archive_path = (archive_dir + archive_prefix + str(id) + GlobalConfig.RES_FILE_FORMAT)
archive.resource_path = archive_path
archive.archive_id = id
archive.created_time = Time.get_datetime_string_from_system(false, true)
ResourceSaver.save(archive, archive_path)
archives.append(id)
# this will auto trigger signal and load the new archive
GlobalConfigManager.config.current_selected_archive_id = id
func save_all() -> void:
# save config
var config = GlobalConfigManager.config
if config:
ResourceSaver.save(config)
# player_global_position
var player = SceneManager.get_player() as MainPlayer
if archive and player:
archive.player_global_position = player.global_position
archive.player_direction = player.facing_direction
if archive:
ResourceSaver.save(archive)
# reset autosave timer
check_autosave_options()
func load_config() -> void:
if GlobalConfigManager.config:
return
var path = user_root_dir + "config" + GlobalConfig.RES_FILE_FORMAT
if FileAccess.file_exists(path):
var config = ResourceLoader.load(path)
GlobalConfigManager.config = config
else:
var config = GlobalConfig.new()
GlobalConfigManager.config = config
ResourceSaver.save(config, path)
GlobalConfigManager.config.resource_path = path
# connect signals
GlobalConfigManager.config.current_selected_archive_id_changed.connect(_on_archive_id_changed)
GlobalConfigManager.config.auto_save_seconds_changed.connect(check_autosave_options)
GlobalConfigManager.config.auto_save_enabled_changed.connect(check_autosave_options)
func load_archive() -> void:
_check_dirs_and_archives()
var selected_id = GlobalConfigManager.config.current_selected_archive_id
if not archives.has(selected_id):
_handle_load_error(str(selected_id) + " 号存档", "查找")
return
var path = archive_dir + archive_prefix + str(selected_id) + GlobalConfig.RES_FILE_FORMAT
archive = ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_REPLACE_DEEP)
if !archive:
_handle_load_error(str(selected_id) + " 号存档", "加载")
return
archive.resource_path = path
check_autosave_options()
func _handle_load_error(target, action) -> void:
var msg = str(target) + " " + str(action) + " 失败,请检查文件访问权限"
SceneManager.pop_notification(msg)
printerr(msg)
# TODO handle error