7var base_save_path :=
""
8var current_profile :=
""
10var pending_state:Dictionary = {}
11var pending_save:bool = false
12var pending_save_timer:float = 0.0
15func _init(path:String):
21func set_path(path:String) -> void:
27func use_profile(profile_id:String) -> void:
28 current_profile = profile_id
29 save_path = get_profile_path(profile_id)
33func get_profile_path(profile_id:String) -> String:
36 var extension_index = base_save_path.rfind(
".")
37 if extension_index < 0:
38 return "%s_%s" % [base_save_path, profile_id]
40 base_save_path.substr(0, extension_index),
42 base_save_path.substr(extension_index)
46func load_state() -> Dictionary:
47 var save_file = ConfigFile.new()
48 var error = save_file.load(save_path)
53 for section
in save_file.get_sections():
55 for key
in save_file.get_section_keys(section):
56 state[section][key] = save_file.get_value(section, key)
57 return migrate_state(state)
60func save_state(state:Dictionary) -> void:
62 pending_save_timer = 0.0
64 var save_file = ConfigFile.new()
65 if not state.has(
"meta"):
67 state[
"meta"][
"save_version"] = int(state[
"meta"].get(
"save_version", get_latest_migration_version()))
68 if current_profile !=
"":
69 state[
"meta"][
"profile"] = current_profile
70 for section
in state.keys():
71 var section_values = state[section]
72 if not section_values
is Dictionary:
74 for key
in section_values.keys():
75 save_file.set_value(str(section), str(key), section_values[key])
76 save_file.save(save_path)
80func queue_save_state(state:Dictionary, delay:float = 2.0) -> void:
81 pending_state = state.duplicate(true)
83 pending_save_timer = max(0.0, delay)
87func step_pending_save(delta:float) -> bool:
90 pending_save_timer = max(0.0, pending_save_timer - delta)
91 if pending_save_timer > 0.0:
98func flush_pending_save() -> bool:
101 save_state(pending_state.duplicate(true))
106func has_pending_save() -> bool:
111func save_section(section:String, values:Dictionary) -> void:
112 var state = load_state()
113 state[section] = values
118func load_section(section:String, default_value:Dictionary = {}) -> Dictionary:
119 return load_state().get(section, default_value)
123func collect_manager_state(managers:Dictionary) -> Dictionary:
125 for section
in managers.keys():
126 var manager = managers[section]
127 if manager != null
and manager.has_method(
"get_state"):
128 state[str(section)] = manager.get_state()
133func apply_manager_state(managers:Dictionary, state:Dictionary) -> void:
134 for section
in managers.keys():
135 var manager = managers[section]
136 if manager != null
and manager.has_method(
"apply_state"):
137 manager.apply_state(state.get(str(section), {}))
141func delete_save() -> void:
142 if FileAccess.file_exists(save_path):
143 DirAccess.remove_absolute(ProjectSettings.globalize_path(save_path))
147func has_save() -> bool:
148 return FileAccess.file_exists(save_path)
153func register_migration(version:int, migration:Callable) -> void:
154 migrations[version] = migration
158func get_latest_migration_version() -> int:
160 for version
in migrations.keys():
161 latest = max(latest, int(version))
166func migrate_state(state:Dictionary) -> Dictionary:
169 var migrated = state.duplicate(true)
170 if not migrated.has(
"meta"):
171 migrated[
"meta"] = {}
172 var current_version = int(migrated[
"meta"].get(
"save_version", 0))
173 var versions = migrations.keys()
175 for version
in versions:
176 var target_version = int(version)
177 if target_version <= current_version:
179 var migration = migrations[version]
180 if migration.is_valid():
181 migrated = migration.call(migrated)
182 migrated[
"meta"][
"save_version"] = target_version
187func get_profile_summary(profile_id:String) -> Dictionary:
188 var previous_path = save_path
189 var previous_profile = current_profile
190 use_profile(profile_id)
191 var state = load_state()
192 save_path = previous_path
193 current_profile = previous_profile
194 return state.get(
"meta", {})
if not state.is_empty()
else {}
197func get_value(state:Dictionary, section:String, key:String, default_value = null):
198 if not state.has(section):
200 return state[section].get(key, default_value)