extends Node # Lightweight replacement for the godot_db_manager plugin (incompatible with # Godot 4). Keeps the ahog.json format used by the rest of the project and # exposes the same surface API the M* model classes expect: # # Global.database.get_table_by_name(name) -> Table # Global.database.save_db() # table.get_data_at_row_idx(row_id) -> [Cell, Cell, ...] # table.edit_data(prop_id, row_id, value) # table.m_rows_count # table.get_data_by_prop_name_and_data(prop_name, value) -> Array # table.get_dictionary_by_prop_name_and_data(prop_name, value) -> Array[Dict] # cell.get_data() -> String class Cell: var _value func _init(value): _value = value func get_data(): return _value class Table: var name: String var props: Array var data: Array var m_rows_count: int func _init(table_dict: Dictionary): name = table_dict["table_name"] props = table_dict["props"] data = table_dict["data"] m_rows_count = data.size() / max(1, props.size()) func _col_count() -> int: return props.size() func _find_prop_idx(prop_name: String) -> int: for i in range(props.size()): if props[i]["name"] == prop_name: return i return -1 func get_data_at_row_idx(row_idx: int) -> Array: var start = row_idx * _col_count() var cells = [] for i in range(_col_count()): cells.append(Cell.new(data[start + i])) return cells func edit_data(prop_id: int, row_id: int, value) -> void: data[row_id * _col_count() + prop_id] = str(value) func get_data_by_prop_name_and_data(prop_name: String, value) -> Array: var prop_idx = _find_prop_idx(prop_name) var matches = [] if prop_idx == -1: return matches for row in range(m_rows_count): if data[row * _col_count() + prop_idx] == str(value): matches.append(row) return matches func get_dictionary_by_prop_name_and_data(prop_name: String, value) -> Array: var prop_idx = _find_prop_idx(prop_name) var results = [] if prop_idx == -1: return results for row in range(m_rows_count): if data[row * _col_count() + prop_idx] == str(value): var d = {} for i in range(_col_count()): d[props[i]["name"]] = data[row * _col_count() + i] results.append(d) return results func to_dict() -> Dictionary: return { "table_name": name, "props": props, "data": data, } class DB: var version: String var db_name: String var tables: Dictionary = {} var _path: String func _init(path: String): _path = path var f = FileAccess.open(path, FileAccess.READ) if f == null: push_error("[Database] Cannot open " + path) return var raw = f.get_as_text() f.close() var doc = JSON.parse_string(raw) if doc == null: push_error("[Database] Invalid JSON in " + path) return version = doc.get("GDDB_ver", "") db_name = doc.get("db_name", "") for t in doc.get("tables", []): var table = Table.new(t) tables[table.name] = table func get_table_by_name(name: String): return tables.get(name) func save_db() -> void: var doc = { "GDDB_ver": version, "db_name": db_name, "tables": [], } for tname in tables: doc["tables"].append(tables[tname].to_dict()) 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 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()