App Settings¶
A flexible settings management system with support for staged values, readonly mode, validation, and per-frame batched signals.
It is built around three core classes: a Registry that owns and organizes Setting objects by hierarchical keys, and an AppSettings node that wraps the registry and adds convenient per-frame batched signals for change detection. Settings support staged mode (queue changes before committing them all at once), readonly mode, custom validation and apply callbacks, and metadata. Configuration can be serialized to and loaded from Godot's built-in ConfigFile format, making save/load workflows straightforward.
The best is to create an autoload AppSettings or GameSettings that extends the provided AppSettings node. This allows you to easily access your settings from anywhere in your code and ensures that the per-frame signals are emitted correctly.
AppSettings: App settings manager class
Registry: App settings manager class.
Setting: Class representing an individual setting.
A short incomplete overview:
# create an autoload extending AppSettings
AppSettings.add_setting(Setting.new(&"graphics/fullscreen", false)
.set_description("Enable fullscreen mode").
.set_apply_fn(func(s): DisplayServer.window_set_mode(...))
.set_validate_fn(func(_s, v): return v is bool)
)
# [...] more settings
# load & apply on startup
AppSettings.from_config(config)
AppSettings.apply_all()
# staged mode: queue changes until user confirms
AppSettings.get_setting(&"audio/volume").set_staged(true)
AppSettings.set_value(&"audio/volume", 0.8)
# or discard_staged_values()
AppSettings.apply_staged_values()
# save
AppSettings.to_config().save("user://settings.cfg")
Compatibility¶
| Godot | Version |
|---|---|
| 4.7 | all |
| 4.6 | all |
| 4.5 | all |
| 4.4 | all |
Example¶
For this example to work you have to create an autoload named GameSettings with the script res://addons/app_settings/game_settings.gd.
Interface¶
AppSettings¶
extendsNode
res://addons/kenyoni/app_settings/app_settings.gd
Node that wraps a Registry and adds per-frame batched signals.
Signals¶
| Name | Description |
|---|---|
| settings_applied | Emitted once per frame when one or more settings were applied during that frame. Inspect get_changed_applied_settings() for the affected keys. |
| settings_changed | Emitted once per frame when one or more effective setting values changed during that frame. Inspect get_changed_settings() for the affected keys. |
| settings_staged_changed | Emitted once per frame when one or more staged values were set or cleared during that frame. Inspect get_changed_staged_settings() for the affected keys. |
| applied | Emitted immediately after a setting is applied. key is the key of the applied setting. |
| changed | Emitted immediately when a setting's effective value changes. key is the key of the changed setting. |
| staged_changed | Emitted immediately when a staged value is set or cleared. key is the key of the affected setting. |
Methods¶
- void add_setting(setting: Setting)
- Add a new setting. The setting's key must be unique.
- void apply_all()
- Call
apply()on every registered setting unconditionally. - void apply_staged_values()
- Call
apply()only on settings that have a pending staged value. - void discard_staged_values()
- Discard all pending staged values across every registered setting.
- void from_config(config: ConfigFile)
- Load values from
configinto matching settings. SeeRegistry.from_config()for full details. - PackedStringArray get_changed_applied_settings() const
- Return the keys of settings that were applied at least once since the previous
_process()call. The array is cleared after each frame, so it only contains settings applied during the current frame. - PackedStringArray get_changed_settings() const
- Return the keys of settings whose effective values changed at least once since the previous
_process()call. The array is cleared after each frame, so it only contains settings changed during the current frame. - PackedStringArray get_changed_staged_settings() const
- Return the keys of settings whose staged values were set or cleared at least once since the previous
_process()call. The array is cleared after each frame, so it only contains settings changed during the current frame. - Array[Setting] get_section(section: String, depth: int = -1, filter: Callable = Registry._exclude_internal) const
- Return all
Settingobjects whose keys begin withsection.depthlimits the number of/-separated levels belowsectionthat are included;-1means unlimited.filterdefaults toRegistry._exclude_internal. SeeRegistry.get_section()for full details. - PackedStringArray get_section_keys(section: String, depth: int = -1, filter: Callable = Registry._exclude_internal) const
- Return the keys of all settings whose keys begin with
section.depthlimits the number of/-separated levels belowsectionthat are included;-1means unlimited.filterdefaults toRegistry._exclude_internal. SeeRegistry.get_section_keys()for full details. - Setting get_setting(key: StringName) const
- Return the
Settingforkey, ornullif it does not exist. - PackedStringArray get_sub_sections(parent_section: String = "", filter: Callable = Registry._exclude_internal) const
- Return the names of the immediate child sections under
parent_section. The names order is not guaranteed to be stable. Pass an empty string to get the top-level section names.filterdefaults toRegistry._exclude_internal. SeeRegistry.get_sub_sections()for full details. - Variant get_value(key: StringName) const
- Return the effective value of the setting identified by
key. SeeSetting.value()for details on how values are determined. - bool has_setting(key: StringName) const
- Return
trueif a setting withkeyexists. - bool has_staged_values() const
- Return
trueif at least one registered setting has a pending staged value. - void remove_setting(key: StringName)
- Remove the setting identified by
key. Does nothing if the key does not exist. - void set_value(key: StringName, value: Variant)
- Set the value of the setting identified by
key. SeeSetting.set_value()for details on how values are assigned and validated. - ConfigFile to_config(filter: Callable = Registry._include_exported) const
- Serialize settings to a
ConfigFileand return it.filtercontrols which settings are included; defaults to exported settings only. SeeRegistry.to_config()for full details.
Registry¶
extendsRefCounted
res://addons/kenyoni/app_settings/registry.gd
Container that owns and manages a collection of Setting objects.
Signals¶
| Name | Description |
|---|---|
| applied(key: StringName) | Emitted immediately after a setting's apply() completes. key is the key of the applied setting. |
| changed(key: StringName) | Emitted when a setting's effective value changes, either by direct assignment or when a staged value is committed. key is the key of the changed setting. |
| staged_changed(key: StringName) | Emitted when a setting's staged value is set or cleared. key is the key of the affected setting. |
Methods¶
- void add_setting(setting: Setting)
- Register
settingwith this registry and set its internal registry reference toself. Fails with a push_error if the key ends with/or contains//, if the setting already belongs to a different registry or if a setting with the same key already exists. - void apply_all()
- Call
apply()on every registered setting unconditionally. - void apply_staged_values()
- Call
apply()only on settings that have a pending staged value. - void discard_staged_values()
- Discard all pending staged values.
staged_changedis emitted for each setting that had a staged value. - void from_config(config: ConfigFile)
- Load values from
configinto matching settings. For eachsection/keypair, the setting key is constructed as"section/key". Only settings that exist, are exported, and are not readonly are updated. Unknown keys emit a warning. - Array[Setting] get_section(section: String, depth: int = -1, filter: Callable = _exclude_internal) const
- Return all
Settingobjects whose keys begin withsection. Pass an empty string to match all settings.depthlimits how many additional/-separated levels belowsectionare included;-1means unlimited.filterreturns only settings for which it returnstrue. - PackedStringArray get_section_keys(section: String, depth: int = -1, filter: Callable = _exclude_internal) const
- Return the keys of all settings whose keys begin with
section. Pass an empty string to match all settings.depthlimits how many additional/-separated levels belowsectionare included;-1means unlimited. - Setting get_setting(key: StringName) const
- Return the
Settingforkey, ornullif no such setting exists. - PackedStringArray get_sub_sections(parent_section: String = "", filter: Callable = _exclude_internal) const
- Return the names of the immediate child sections under
parent_section. The names order is not guaranteed to be stable. A child section name is the single path component that followsparent_sectionin a matching key. For example, given a key"graphics/display/vsync"andparent_section = "graphics", this returns["display"]. Pass an empty string forparent_sectionto get the top-level section names.filteris aCallablewith signaturefunc(setting: Setting) -> bool. - Variant get_value(key: StringName) const
- Return the current effective value of the setting identified by
key. Emits a warning and returnsnullifkeydoes not exist. - bool has_setting(key: StringName) const
- Return
trueif a setting withkeyexists in this registry. - bool has_staged_values() const
- Return
trueif at least one registered setting has a pending staged value. - void remove_setting(key: StringName)
- Remove the setting identified by
key. Does nothing if the key does not exist. - void set_value(key: StringName, value: Variant)
- Set the value of the setting identified by
key. Emits a warning ifkeydoes not exist. Staged mode, readonly mode, and validation all apply. - ConfigFile to_config(filter: Callable = _include_exported) const
- Serialize settings to a
ConfigFile. Each setting's key is split on the last/: the left part becomes the section, the right part becomes the config key. Settings without a/are placed in the empty-string section.filteris aCallablewith signaturefunc(setting: Setting) -> boolthat controls which settings are included. Defaults to_include_exported. - bool _exclude_internal(setting: Setting) static
- Return
truefor non-internal settings. - bool _include_exported(setting: Setting) static
- Return
truefor exported settings.
Setting¶
extendsRefCounted
res://addons/kenyoni/app_settings/setting.gd
A single configurable value identified by a hierarchical key. Each setting holds a current effective value, a default value, optional validation and apply callables, and metadata. Settings are owned by a Registry, which must be assigned before apply() is called.
Staged mode — when enabled, set_value() stores a pending value rather than applying it immediately. The pending value becomes the effective value only when apply() is called.
Readonly mode — when enabled, all writes via set_value() and reset() are silently ignored.
Methods¶
- Setting add_meta(meta_key: StringName, val: Variant)
- Store an arbitrary metadata value under
meta_key. Fluent wrapper aroundObject.set_meta(). Returnsselffor method chaining. - void apply()
- Commit the current state and trigger side-effects. If a staged value is pending, it replaces the effective value,
staged_changedis emitted, andchangedis emitted if the value differed. Regardless of staged state, the apply callable is invoked(if set) andappliedis emitted. - Variant default_value() const
- Return the default value supplied at construction time.
- String description() const
- Return the description string, or an empty string if none is set.
- void discard_staged_value()
- Discard any pending staged value. Emits
staged_changedon the registry if a value was actually cleared. - bool has_staged_value() const
- Return
truewhen a staged value is pending and has not yet been applied. - bool is_exported() const
- Return
truewhen the setting is exported to config files.trueby default. - bool is_internal() const
- Return
truewhen the setting is marked as internal. - bool is_readonly() const
- Return
truewhen the setting is readonly. - bool is_staged_mode() const
- Return
truewhen staged mode is active. - StringName key() const
- Return the hierarchical key that uniquely identifies this setting.
- void reset()
- Reset the setting to its default value. Has no effect when readonly.
- Setting set_apply_fn(fn: Callable)
- Set the apply callable. Signature:
func(setting: Setting) -> void. Returnsselffor method chaining. - Setting set_description(text: String)
- Set a human-readable description string. Returns
selffor method chaining. - Setting set_exported(exported: bool = true)
- Set whether the setting should be exported when generating configuration files. Returns
selffor method chaining. - Setting set_internal(internal: bool = true)
- Mark or unmark the setting as internal. Internal settings should be excluded from auto-generated UIs. Returns
selffor method chaining. - Setting set_readonly(readonly: bool = true)
- Enable or disable readonly mode. While readonly,
set_value()andreset()are silently ignored. Returnsselffor method chaining. - Setting set_staged(staged: bool = true)
- Enable or disable staged mode. When
stagedisfalse, any pending staged value is discarded. Returnsselffor method chaining. - Setting set_validate_fn(fn: Callable)
- Set the validate callable. Signature:
func(setting: Setting, value: Variant) -> bool. Returnsselffor method chaining. - void set_value(new_value: Variant)
- Assign
new_valueafter passing it through the validator. Ignored if readonly. Ifnew_valueequals the current effective value and a staged value is pending, the staged value is cleared. In staged mode, storesnew_valueas pending and emitsstaged_changed. In normal mode, sets the value immediately, emitschanged, and callsapply(). - Variant staged_or_value() const
- Return the staged value if one is pending, otherwise return the current effective value.
- Variant staged_value() const
- Return the pending staged value, or
nullif none exists. Usehas_staged_value()to distinguish a storednullfrom the absence of a staged value. - bool validate(value: Variant) const
- Return true if the value is valid according to the validate callable or if no validate callable is set.
- Variant value() const
- Return the current effective value. Does not reflect any pending staged value.
Changelog¶
1.0.1¶
- Fix
apply_staged_values()not working due to a typo in the staged value check.
1.0.0¶
- Initial release for Godot 4.4