From a6d4c290d3910a00c4e993b7ba9e24db79ac28a5 Mon Sep 17 00:00:00 2001 From: Eric Smith <5d@fifthdread.com> Date: Wed, 20 May 2026 22:32:17 -0400 Subject: [PATCH] =?UTF-8?q?refactor:=20JSON=20=E2=86=92=20INI=20config=20v?= =?UTF-8?q?ia=20Godot=20ConfigFile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- autoload/config_manager.gd | 82 +++++++++++++++++++++++--------------- config/default.cfg | 14 +++++++ config/default.json | 9 ----- 4 files changed, 64 insertions(+), 43 deletions(-) create mode 100644 config/default.cfg delete mode 100644 config/default.json diff --git a/.gitignore b/.gitignore index 03ba703..668ba9b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ godot_temp_* *~ # Config — user overrides, not committed -config/config.json +config/config.cfg # OS .DS_Store diff --git a/autoload/config_manager.gd b/autoload/config_manager.gd index 1d9bc8d..f6f321a 100644 --- a/autoload/config_manager.gd +++ b/autoload/config_manager.gd @@ -10,10 +10,12 @@ func _ready() -> void: _load_config() +## Read a flat setting by key (e.g. "background_color", "show_cpu"). func get_setting(key: String, default_value: Variant = null) -> Variant: return _settings.get(key, default_value) +## Persist a setting and emit the change signal. func set_setting(key: String, value: Variant) -> void: if _settings.has(key) and _settings[key] != value: _settings[key] = value @@ -21,7 +23,7 @@ func set_setting(key: String, value: Variant) -> void: config_changed.emit(key, value) -## Parse a "r, g, b" string from config into a Color with alpha 1.0. +## Parse a "r, g, b" string setting into a Color (alpha = 1.0). func get_color(key: String, default_color: Color = Color.WHITE) -> Color: var raw: Variant = _settings.get(key) if raw == null or typeof(raw) != TYPE_STRING: @@ -35,45 +37,59 @@ func get_color(key: String, default_color: Color = Color.WHITE) -> Color: return Color(r, g, b, 1.0) +# -------------------------------------------------------------------------- +# INI loading via Godot's ConfigFile +# Keys are flattened as "{section}_{key}" for simple lookup. +# User config.cfg overrides default.cfg on a per-key basis. +# -------------------------------------------------------------------------- + func _load_config() -> void: - # Load defaults, then overlay user config. - var defaults := _read_json_file("res://config/default.json") - var user := _read_json_file("res://config/config.json") - _settings.clear() - if defaults != null and defaults is Dictionary: - _merge_dict(_settings, defaults as Dictionary) - if user != null and user is Dictionary: - _merge_dict(_settings, user as Dictionary) + _load_cfg("res://config/default.cfg") + _load_cfg("res://config/config.cfg") # silently ignored if absent -static func _read_json_file(path: String) -> Variant: - var file := FileAccess.open(path, FileAccess.READ) - if file == null: - return null - var content: String = file.get_as_text() - var parsed: Variant = JSON.parse_string(content) - return parsed - - -static func _merge_dict(dst: Dictionary, src: Dictionary) -> void: - for key in src: - dst[key] = src[key] +func _load_cfg(path: String) -> void: + var cfg := ConfigFile.new() + if cfg.load(path) != OK: + return + for section in cfg.get_sections(): + for key in cfg.get_section_keys(section): + _settings[section + "_" + key] = cfg.get_value(section, key) func _save_user_config() -> void: - # Only persists settings that differ from defaults. - var defaults := _read_json_file("res://config/default.json") - if not (defaults is Dictionary): + # Load defaults to compare against. + var defaults := ConfigFile.new() + if defaults.load("res://config/default.cfg") != OK: return - var diff: Dictionary = {} - for key in _settings: - if not defaults.has(key) or defaults[key] != _settings[key]: - diff[key] = _settings[key] + # Collect default keys for reference. + var default_keys: Dictionary = {} + for section in defaults.get_sections(): + for key in defaults.get_section_keys(section): + default_keys[section + "_" + key] = { "section": section, "key": key } - var path: String = "res://config/config.json" - var json_str: String = JSON.stringify(diff, "\t") - var file := FileAccess.open(path, FileAccess.WRITE) - if file != null: - file.store_string(json_str) + var user_cfg := ConfigFile.new() + var has_diff: bool = false + + for flat_key in _settings: + var entry: Variant = default_keys.get(flat_key) + var section: String + var cfg_key: String + if entry != null: + section = entry.section + cfg_key = entry.key + else: + # Not in defaults — derive section from flat key (before first "_"). + var parts: PackedStringArray = flat_key.split("_", true, 1) + section = parts[0] if parts.size() > 1 else "general" + cfg_key = parts[-1] + + var default_val: Variant = defaults.get_value(section, cfg_key, null) + if _settings[flat_key] != default_val: + user_cfg.set_value(section, cfg_key, _settings[flat_key]) + has_diff = true + + if has_diff: + user_cfg.save("res://config/config.cfg") diff --git a/config/default.cfg b/config/default.cfg new file mode 100644 index 0000000..5dbc23d --- /dev/null +++ b/config/default.cfg @@ -0,0 +1,14 @@ +[background] +color=0.08, 0.08, 0.12 + +[modules] +show_cpu=true +show_memory=true +show_network=true +show_disk=true + +[performance] +refresh_interval=1.0 + +[general] +theme=default diff --git a/config/default.json b/config/default.json deleted file mode 100644 index 4f99234..0000000 --- a/config/default.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "background_color": "0.08, 0.08, 0.12", - "refresh_interval": 1.0, - "show_cpu": true, - "show_memory": true, - "show_network": true, - "show_disk": true, - "theme": "default" -}