Skip to content

Instantly share code, notes, and snippets.

@distransient
Created October 21, 2024 22:37
Show Gist options
  • Save distransient/dbb35d65f5b7027ff63f95a16084dddd to your computer and use it in GitHub Desktop.
Save distransient/dbb35d65f5b7027ff63f95a16084dddd to your computer and use it in GitHub Desktop.
Godot settings
class_name ConfigBase extends Node
## Base class for Configuration
## Types to filter on when reflecting on subclass properties.
const VALID_PROP_TYPES : Array[int] = [
Variant.Type.TYPE_BOOL,
Variant.Type.TYPE_INT,
Variant.Type.TYPE_FLOAT,
Variant.Type.TYPE_STRING,
]
## Name of the file to load and save config on.
var _file_name : String = ""
## Name of the current script, used for debugging.
var _script_name : String = ""
## Call this in subclasses after setting [field self._file_name].
func _init() -> void:
self._script_name = self._get_script_name()
if self._file_name.length() > 0:
var config_err: Error = self.read()
if config_err == Error.ERR_FILE_NOT_FOUND: self.write()
## Synchronously reads this config's file values into the singleton.
func read() -> Error:
assert(self._file_name.length() > 0, "Config _file_name must be set in subclass.")
var config := ConfigFile.new()
var config_err: Error = config.load(self._file_name)
if config_err == Error.OK:
print_debug("[", self._script_name, "]: Reading user cfg from " + self._file_name)
self._read_config(config)
elif config_err == Error.ERR_FILE_NOT_FOUND:
print("[", self._script_name, "]: Config file not yet created: " + self._file_name)
else:
printerr("[", self._script_name,
"]: Error when loading settings cfg: ",
config_err)
return config_err
## Synchronously writes this config's values into the destination file.
func write() -> Error:
assert(self._file_name.length() > 0, "Config _file_name must be set in subclass.")
print_debug("Writing user cfg to " + self._file_name)
var config := ConfigFile.new()
self._write_config(config)
var config_err: Error = config.save(self._file_name)
if config_err != Error.OK:
printerr("[", self._script_name,
"]: Error when saving settings cfg:",
config_err)
else:
print_debug("[", self._script_name,
"]: Successfully wrote cfg to path: ",
self._file_name)
return config_err
## Loops over the values in a [ConfigFile], setting the fields on the class.
func _read_config(config: ConfigFile) -> void:
# Loop over all properties on self, getting the value in the ConfigFile.
for prop in self._get_props():
var prop_section : String = prop[0]
var prop_key : String = prop[1]
var prop_name : String = prop_section + "_" + prop_key
var default_val : Variant = self[prop_name]
self[prop_name] = config.get_value(prop_section, prop_key, default_val)
print_debug("[", self._script_name, "]: Loaded ", prop_name,
" (", prop_section,
"[", prop_key,
"]) from user cfg as ", self[prop_name],
" with default ", default_val)
## Saves all valid setting names on current script to [ConfigFile].
func _write_config(config: ConfigFile) -> void:
# Loop over all properties on self, setting the value in the ConfigFile.
for prop in self._get_props():
var prop_section : String = prop[0]
var prop_key : String = prop[1]
var prop_name : String = prop[0] + "_" + prop[1]
var prop_val : Variant = self[prop_name]
config.set_value(prop_section, prop_key, prop_val)
print_debug("[", self._script_name, "]: Wrote ", prop_name,
" (", prop_section,
"[", prop_key,
"]) to user cfg with value: ", prop_val)
## Reflects on all properties of the current script, returning valid setting names.
func _get_props() -> Array[PackedStringArray]:
var result : Array[PackedStringArray] = []
var script: Script = self.get_script()
for prop in script.get_script_property_list():
var prop_type : int = prop["type"]
var prop_name : String = prop["name"]
var is_internal_prop : bool = prop_name.begins_with("_")
var is_valid_prop_type : bool = VALID_PROP_TYPES.has(prop_type)
if !is_internal_prop and is_valid_prop_type:
print_debug("[", self._script_name,
"]: Reflecting on valid public property \"", prop_name,
"\" with type: ", prop_type)
result.push_back(prop_name.split("_", false, 1))
else:
print_debug("[", self._script_name, "]: Ignoring reflected ",
"valid " if is_valid_prop_type else "invalid ",
"private " if is_internal_prop else "public ",
"property \"", prop_name, "\" with type: ", prop_type)
return result
## Reflects on script property list, fetching just the script name.
func _get_script_name() -> String:
var script: Script = self.get_script()
for prop in script.get_script_property_list():
var prop_type : int = prop["type"]
var prop_name : String = prop["name"]
if prop_type == Variant.Type.TYPE_NIL: return prop_name
return ""
extends ScConfigBase
## Configurable user settings file
## Destination file name to copy to the base class.
const FILE_NAME : String = "user://settings.cfg"
## Multiplier for mouse look sensitivity. Not used for UI.
var input_mouse_sens : float = 1.0
## Multiplier for joystick look sensitivity (lateral). Not used for UI.
var input_joy_look_x_sens : float = 0.02
## Multiplier for joystick look sensitivity (vertical). Not used for UI.
var input_joy_look_y_sens : float = 0.02
## Multiplier for joystick look deadzone (lateral). Not used for UI.
var input_joy_look_x_deadzone : float = 0.08
## Multiplier for joystick look deadzone (vertical). Not used for UI.
var input_joy_look_y_deadzone : float = 0.08
## Multiplier for joystick move deadzone (lateral). Used for movement and UI.
var input_joy_move_x_deadzone : float = 0.08
## Multiplier for joystick move deadzone (vertical). Used for movement and UI.
var input_joy_move_y_deadzone : float = 0.08
## Sets the destination file name and initializes the configuration.
func _init() -> void:
self._file_name = FILE_NAME
super._init()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment