extends Node # Loads ahog.json once into typed Resource arrays: # Global.database.settings -> SettingsData # Global.database.levels -> Array[LevelEntry] # Global.database.scenes -> Array[SceneEntry] # # save() round-trips back to the same JSON format so game progress # (per-scene lock state) persists across runs. class DB extends RefCounted: var settings: SettingsData var levels: Array[LevelEntry] = [] var scenes: Array[SceneEntry] = [] var _path: String const _SETTINGS_PROPS := [ {"name": "langue", "type": "1", "auto_increment": "0"}, {"name": "gyroscope", "type": "0", "auto_increment": "0"}, {"name": "ambient_sound", "type": "0", "auto_increment": "0"}, {"name": "resolution", "type": "3", "auto_increment": "0"}, {"name": "fullscreen", "type": "0", "auto_increment": "0"}, {"name": "version", "type": "0", "auto_increment": "0"}, ] const _LEVELS_PROPS := [ {"name": "name", "type": "3", "auto_increment": "0"}, {"name": "thumb", "type": "4", "auto_increment": "0"}, ] const _SCENES_PROPS := [ {"name": "lock", "type": "0", "auto_increment": "0"}, {"name": "label", "type": "3", "auto_increment": "0"}, {"name": "key", "type": "3", "auto_increment": "0"}, {"name": "level", "type": "table", "table_name": "levels", "auto_increment": "0"}, {"name": "mesh", "type": "3", "auto_increment": "0"}, {"name": "label_counter", "type": "1", "auto_increment": "0"}, {"name": "counter", "type": "1", "auto_increment": "0"}, ] func _init(path: String) -> void: _path = path var f := FileAccess.open(path, FileAccess.READ) if f == null: push_error("[Database] Cannot open " + path) return var doc = JSON.parse_string(f.get_as_text()) f.close() if not (doc is Dictionary): push_error("[Database] Invalid JSON in " + path) return for table in doc.get("tables", []): match table.get("table_name", ""): "settings": settings = _load_settings(table.get("data", [])) "levels": levels = _load_levels(table.get("data", [])) "scenes": scenes = _load_scenes(table.get("data", [])) func _load_settings(data: Array) -> SettingsData: var s := SettingsData.new() if data.size() >= 6: s.langue = int(data[0]) s.gyroscope = bool(int(data[1])) s.ambient_sound = bool(int(data[2])) s.resolution = str(data[3]) s.fullscreen = bool(int(data[4])) s.version = str(data[5]) return s func _load_levels(data: Array) -> Array[LevelEntry]: var result: Array[LevelEntry] = [] const W := 2 @warning_ignore("integer_division") for i in range(data.size() / W): var l := LevelEntry.new() l.index = i l.name = str(data[i * W + 0]) l.thumb = str(data[i * W + 1]) result.append(l) return result func _load_scenes(data: Array) -> Array[SceneEntry]: var result: Array[SceneEntry] = [] const W := 7 @warning_ignore("integer_division") for i in range(data.size() / W): var s := SceneEntry.new() s.lock = bool(int(data[i * W + 0])) s.label = str(data[i * W + 1]) s.key = str(data[i * W + 2]) s.level = int(data[i * W + 3]) s.mesh = str(data[i * W + 4]) s.label_counter = str(data[i * W + 5]) s.counter = int(data[i * W + 6]) result.append(s) return result func scenes_for_level(level_idx: int) -> Array[SceneEntry]: var result: Array[SceneEntry] = [] for s in scenes: if s.level == level_idx: result.append(s) return result func level_by_index(idx: int) -> LevelEntry: for l in levels: if l.index == idx: return l return null func save() -> void: var doc := { "GDDB_ver": "2.0", "db_name": "ahog", "tables": [ {"table_name": "settings", "props": _SETTINGS_PROPS, "data": _dump_settings()}, {"table_name": "levels", "props": _LEVELS_PROPS, "data": _dump_levels()}, {"table_name": "scenes", "props": _SCENES_PROPS, "data": _dump_scenes()}, ], } var f := FileAccess.open(_path, FileAccess.WRITE) if f == null: push_error("[Database] Cannot write " + _path) return f.store_string(JSON.stringify(doc)) f.close() func _dump_settings() -> Array: return [ str(settings.langue), str(int(settings.gyroscope)), str(int(settings.ambient_sound)), settings.resolution, str(int(settings.fullscreen)), settings.version, ] func _dump_levels() -> Array: var out: Array = [] for l in levels: out.append_array([l.name, l.thumb]) return out func _dump_scenes() -> Array: var out: Array = [] for s in scenes: out.append_array([ str(int(s.lock)), s.label, s.key, str(s.level), s.mesh, s.label_counter, str(s.counter), ]) return out func initialize() -> DB: return DB.new(save_database_in()) func save_database_in() -> String: if OS.get_name() == "Android": copy_database() return android_path() return normal_path() func android_path() -> String: return "user://database.json" func normal_path() -> String: return "res://db/ahog.json" func copy_database() -> void: if FileAccess.file_exists(android_path()): return var src := FileAccess.open(normal_path(), FileAccess.READ) var dst := FileAccess.open(android_path(), FileAccess.WRITE) dst.store_string(src.get_as_text()) dst.close() src.close()