extends Node signal config_changed(key: String, value: Variant) var _settings: Dictionary = {} 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 _save_user_config() config_changed.emit(key, value) ## 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: return default_color var parts: PackedStringArray = (raw as String).split(",", false) if parts.size() < 3: return default_color var r: float = parts[0].strip_edges().to_float() var g: float = parts[1].strip_edges().to_float() var b: float = parts[2].strip_edges().to_float() 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: _settings.clear() _load_cfg("res://config/default.cfg") _load_cfg("res://config/config.cfg") # silently ignored if absent 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: # Load defaults to compare against. var defaults := ConfigFile.new() if defaults.load("res://config/default.cfg") != OK: return # 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 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")