xiandie/manager/archive_manager/archive_manager.gd

263 lines
7.7 KiB
GDScript3
Raw Normal View History

@tool
2024-12-23 01:29:31 +00:00
extends Node
signal archive_loaded
2025-05-14 20:43:55 +00:00
static var archive: AssembledArchive:
set(val):
archive = val
if archive:
print("use archive ", archive.resource_path)
# current archive
static var user_root_dir := "user://data/" # must end with "/"
static var archive_dir := "user://data/archives/"
static var archive_prefix := "save"
2024-12-23 01:29:31 +00:00
var archives := {}
2024-12-23 01:29:31 +00:00
var autosave_timer := Timer.new()
2024-12-24 01:16:06 +00:00
func _ready() -> void:
# 禁用默认退出行为,在 _notification 处理 NOTIFICATION_WM_CLOSE_REQUEST 时保存数据
get_tree().set_auto_accept_quit(false)
2025-04-01 08:16:29 +00:00
process_mode = Node.PROCESS_MODE_ALWAYS
2024-12-24 11:24:55 +00:00
if not _check_dirs_and_archives():
2024-12-24 11:54:30 +00:00
_handle_load_error("存档目录", "读写")
2024-12-23 01:29:31 +00:00
return
autosave_timer.timeout.connect(_try_auto_save)
autosave_timer.stop()
2024-12-24 11:24:55 +00:00
add_child(autosave_timer)
# config should be loaded first
load_config()
# 在 debug or editor 模式下,直接保证有 archive
if GlobalConfig.DEBUG or Engine.is_editor_hint():
2024-12-24 11:24:55 +00:00
if archives.size() == 0:
create_and_use_new_archive()
else:
# debug 模式下默认使用 0 号存档
GlobalConfigManager.config.current_selected_archive_id = 0
2024-12-24 11:24:55 +00:00
func _notification(what):
# handle window close request
if what == NOTIFICATION_WM_CLOSE_REQUEST:
2025-01-07 10:54:50 +00:00
save_all()
if has_node("/root/Main"):
print("Saved all success before Quit")
# 已保存所有数据 [ID:ui_saved_all]
SceneManager.pop_notification(tr("ui_saved_all"))
var tree = get_tree()
tree.create_timer(1.5).timeout.connect(tree.quit)
else:
get_tree().quit()
func _on_archive_id_changed():
2024-12-24 11:24:55 +00:00
var selected_id = GlobalConfigManager.config.current_selected_archive_id
if selected_id < 0:
return
2025-05-14 20:43:55 +00:00
# if archive and selected_id == archive.archive_id:
# print("_on_archive_id_changed same id=", selected_id)
# return
print("_on_archive_id_changed id=", selected_id)
if not archives.has(selected_id):
2025-05-14 20:43:55 +00:00
print("新建存档 ", selected_id)
2024-12-24 11:24:55 +00:00
create_and_use_new_archive(selected_id)
# 已创建新存档 [ID:ui_new_archive]
SceneManager.pop_notification(tr("ui_new_archive"))
2024-12-24 11:24:55 +00:00
else:
load_archive()
2024-12-23 01:29:31 +00:00
func check_autosave_options():
if (
GlobalConfigManager.config.auto_save_enabled
and archive
and GlobalConfigManager.config.auto_save_seconds > 1
):
2024-12-24 11:24:55 +00:00
# reset left time
autosave_timer.stop()
autosave_timer.one_shot = false
autosave_timer.wait_time = GlobalConfigManager.config.auto_save_seconds
2024-12-23 01:29:31 +00:00
autosave_timer.start()
else:
autosave_timer.stop()
if GlobalConfig.DEBUG:
print(
"check_autosave_option: ",
GlobalConfigManager.config.auto_save_enabled,
" wait_time=",
autosave_timer.wait_time
)
2024-12-23 01:29:31 +00:00
func _try_auto_save():
2024-12-25 06:27:47 +00:00
if GlobalConfig.DEBUG:
print("Auto save")
2024-12-24 11:24:55 +00:00
if archive and GlobalConfigManager.config.auto_save_seconds > 1:
2024-12-23 01:29:31 +00:00
save_all()
# 自动保存成功 [ID:ui_auto_saved]
SceneManager.pop_notification(tr("ui_auto_saved"))
2024-12-23 01:29:31 +00:00
2024-12-24 11:24:55 +00:00
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)
2024-12-23 01:29:31 +00:00
# Check if the archive directory is accessible
2024-12-24 11:24:55 +00:00
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)
2024-12-23 01:29:31 +00:00
if !archive_dir_access:
2024-12-24 11:24:55 +00:00
_handle_load_error("存档目录", "读取")
2024-12-23 01:29:31 +00:00
# TODO pop up a dialog to inform the user
return false
var files = archive_dir_access.get_files()
files.sort()
2024-12-23 01:29:31 +00:00
# get archive number
for file in files:
if file.begins_with(archive_prefix) and file.ends_with(GlobalConfig.RES_FILE_FORMAT):
2025-05-14 20:43:55 +00:00
var id_str = file.get_basename().substr(archive_prefix.length()).strip_escapes()
# 非三位数的 id 会被忽略
if id_str.length() != 3:
continue
2024-12-23 01:29:31 +00:00
var id = int(id_str)
# 读取范围是 0-99
if id < 0 or id > 99:
continue
var path = archive_dir + file
if not archives.has(id):
archives[id] = ResourceLoader.load(
path, "AssembledArchive", ResourceLoader.CACHE_MODE_REPLACE_DEEP
)
2024-12-23 01:29:31 +00:00
return true
2024-12-24 11:24:55 +00:00
# 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()
var archive_path = _get_archive_path(id)
2024-12-24 11:24:55 +00:00
if id < 0:
# 如果 id 小于 0找到一个新的 id创建新存档
2024-12-24 11:24:55 +00:00
id = 0
# find a new id
archive_path = _get_archive_path(id)
2024-12-24 11:24:55 +00:00
while FileAccess.file_exists(archive_path):
id += 1
archive_path = _get_archive_path(id)
_create_and_save_new_archive_resoure(id)
else:
# 如果 id 大于等于 0创建指定 id 的存档
if FileAccess.file_exists(archive_path):
_create_and_save_new_archive_resoure(id, true)
else:
_create_and_save_new_archive_resoure(id)
archives[id] = archive
2024-12-24 11:24:55 +00:00
# this will auto trigger signal and load the new archive
GlobalConfigManager.config.current_selected_archive_id = id
func _create_and_save_new_archive_resoure(id, take_over_path = false) -> void:
var archive_path = _get_archive_path(id)
archive = AssembledArchive.new() as Resource
if take_over_path:
archive.take_over_path(archive_path)
else:
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)
# 超过 999 个存档会出问题;不过这个游戏不会有这么多存档
func _get_archive_path(id: int) -> String:
var id_str := ""
if id < 10:
id_str = "00" + str(id)
elif id < 100:
id_str = "0" + str(id)
else:
id_str = str(id)
return archive_dir + archive_prefix + id_str + GlobalConfig.RES_FILE_FORMAT
2024-12-23 01:29:31 +00:00
func save_all() -> void:
# save config
var config = GlobalConfigManager.config
2024-12-24 11:24:55 +00:00
if config:
ResourceSaver.save(config)
# player_global_position
var player = SceneManager.get_player() as MainPlayer
# 在此处保存 player 的位置信息
if archive and player:
archive.player_global_position_x = player.global_position.x
archive.player_direction = player.facing_direction
2024-12-24 11:24:55 +00:00
if archive:
ResourceSaver.save(archive)
# reset autosave timer
check_autosave_options()
2024-12-24 11:24:55 +00:00
func load_config() -> void:
if GlobalConfigManager.config:
2024-12-23 01:29:31 +00:00
return
2024-12-24 11:24:55 +00:00
var path = user_root_dir + "config" + GlobalConfig.RES_FILE_FORMAT
2024-12-23 01:29:31 +00:00
if FileAccess.file_exists(path):
2024-12-24 11:24:55 +00:00
var config = ResourceLoader.load(path)
GlobalConfigManager.config = config
2024-12-23 01:29:31 +00:00
else:
2024-12-24 11:24:55 +00:00
var config = GlobalConfig.new()
GlobalConfigManager.config = config
2024-12-23 01:29:31 +00:00
ResourceSaver.save(config, path)
2024-12-24 11:24:55 +00:00
GlobalConfigManager.config.resource_path = path
2025-01-17 10:45:40 +00:00
if Engine.is_editor_hint():
return
2024-12-24 11:24:55 +00:00
# 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)
2024-12-24 11:24:55 +00:00
func load_archive() -> void:
_check_dirs_and_archives()
var selected_id = GlobalConfigManager.config.current_selected_archive_id
2025-05-14 20:43:55 +00:00
# if archive and selected_id == archive.archive_id:
# return
print("load_archive ", selected_id)
2024-12-24 11:24:55 +00:00
if not archives.has(selected_id):
_handle_load_error(str(selected_id) + " 号存档", "查找")
return
archive = archives[selected_id]
# emit signal
archive_loaded.emit()
check_autosave_options()
2024-12-24 11:24:55 +00:00
func _handle_load_error(target, action) -> void:
2024-12-24 11:54:30 +00:00
var msg = str(target) + " " + str(action) + " 失败,请检查文件访问权限"
2024-12-24 11:24:55 +00:00
SceneManager.pop_notification(msg)
printerr(msg)
# TODO handle error
func set_global_entry(property: StringName, value) -> void:
if not archive:
printerr("Archive is null, cannot set global entry")
return
archive.global_data_dict[property] = value
func get_global_value(property: StringName, default = null) -> Variant:
if not archive:
printerr("Archive is null, cannot get global value")
return default
var val = archive.global_data_dict.get(property)
if val == null:
return default
return val