Last active
September 25, 2024 20:02
-
-
Save floere/82abea6d79201911979196b002ed9d76 to your computer and use it in GitHub Desktop.
Godot Config global for loading/storing user settings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extends Node | |
# This is the "global class" Config. | |
## Emitted once when the Config is loaded for the first time (after the game is loaded). | |
signal loaded | |
## Emitted when an audio volume was set. | |
signal audio_volume_set(bus_name: String, value_in_db: float) | |
## Emitted when the mouse cursor size was set. | |
signal visual_cursor_size_set(size: Vector2) | |
## Emitted when display fullscreen was set. | |
signal display_fullscreen_set(value: bool) | |
## Emitted when the display size was set. | |
signal display_size_set(size: Vector2i) | |
# Use as follows: | |
# | |
# Example 1: A volume slider. | |
# NOTE: the node is named like the Audio Bus | |
# | |
# extends HSlider | |
# | |
# func _enter_tree() -> void: | |
# self.value_changed.connect(func(_changed): | |
# Config.save_linear_volume(self.name, self.value / self.max_value)) | |
# Config.loaded.connect(func(): | |
# self.value = Config.get_linear_volume(self.name) * max_value) | |
# | |
# | |
# Example 2: A fullscreen checkbox. | |
# | |
# extends CheckBox | |
# | |
# func _enter_tree() -> void: | |
# Config.loaded.connect(func(): | |
# self.button_pressed = Config.display_fullscreen) | |
# self.pressed.connect(func(): | |
# Config.save_display_fullscreen(self.button_pressed)) | |
## The filename of the user settings. | |
const settings_filename = "user://settings.cfg" | |
# Configuration variables. | |
# These are the variables which always hold the latest settings. | |
# Use these (or the convenience `get_` methods) to access the current settings. | |
# Some emit events. Listen to these to actually update something in the Game, | |
# such as the volume. | |
# Structure: <section>_<variable_name> | |
# They will be stored under <section> with the name <variable_name>. | |
## Display | |
var display_fullscreen: bool = false: | |
set(value): | |
display_fullscreen = value | |
display_fullscreen_set.emit(value) | |
var display_size: Vector2 = Vector2i(1024, 768): | |
set(value): | |
display_size = value | |
display_size_set.emit(value) | |
## Visual | |
var visual_cursor_size: float = 1.0: | |
set(value): | |
visual_cursor_size = value | |
visual_cursor_size_set.emit(Vector2(value, value)) | |
var visual_font_name: String = "Pixel" | |
## Audio | |
## Use setters that emit signals when you want to set values elsewhere in the game. | |
## For example, when the volume of an audio bus needs to be set, the | |
## AudioManager should listen to the signal and update the actual volume | |
## on the bus. | |
var audio_master_enabled = true | |
var audio_master_volume = 1.0: | |
set(value): | |
audio_master_volume = value | |
audio_volume_set.emit("Master", value) | |
var audio_music_enabled = true | |
var audio_music_volume = 1.0: | |
set(value): | |
audio_music_volume = value | |
audio_volume_set.emit("Music", value) | |
var audio_sound_enabled = true | |
var audio_sound_volume = 1.0: | |
set(value): | |
audio_sound_volume = value | |
audio_volume_set.emit("Sound", value) | |
## The configuration variables. | |
var configuration_variables: Array = [] | |
func _ready(): | |
# Load variables into a list for dynamic handling. | |
load_configuration_variables() | |
# Load parameters from the config file when the game has finished loading. | |
Events.game_loaded.connect(load_config) | |
func load_configuration_variables() -> void: | |
var temporary_configuration_variables = get_script().get_script_property_list() | |
# Pop the script name itself. | |
temporary_configuration_variables.pop_front() | |
# Map to only the variable names. | |
configuration_variables = temporary_configuration_variables \ | |
.map(func(variable): return variable.get("name")) \ | |
# Remove the variable that holds the configuration variables itself. | |
.filter(func(variable_name): return variable_name != "configuration_variables") | |
func load_config(): | |
setup() | |
# React this this signal to initialize values on sliders/checkboxes etc. | |
loaded.emit() | |
# Convenience methods - use these to have fixed method names | |
# (instead of checkboxes and sliders having to use eg. `save("visual_cursor_size", value)`). | |
func get_linear_volume(bus_name) -> float: | |
var value = get("audio_%s_volume" % bus_name.to_lower()) | |
return db_to_linear(value) | |
func save_linear_volume(bus_name, value) -> void: | |
var value_in_db = linear_to_db(value) | |
save("audio_%s_volume" % bus_name.to_lower(), value_in_db) | |
func save_font_name(value) -> void: | |
save("visual_font_name", value) | |
func save_cursor_size(value) -> void: | |
save("visual_cursor_size", value) | |
func save_display_size(value: Vector2i) -> void: | |
save("display_size", value) | |
func save_display_fullscreen(value: bool) -> void: | |
save("display_fullscreen", value) | |
# Helper methods. | |
## This creates a config file if needed and fills it with default values. | |
## If a config file exists, will load the values into the variables. | |
func setup() -> void: | |
var config = ConfigFile.new() | |
var err = config.load(settings_filename) | |
for configuration_variable in configuration_variables: | |
# Splits up the var name into section_some_name -> section and some_name. | |
var section_and_key = split(configuration_variable) | |
var section = section_and_key[0] | |
var key = section_and_key[1] | |
# Initialize value in variable from file if possible / in file if necessary. | |
if not err == ERR_FILE_NOT_FOUND: | |
# If there is an entry in the file. | |
if config.has_section_key(section, key): | |
# Set variable from config file. | |
set("%s_%s" % [section, key], config.get_value(section, key)) | |
else: | |
# Otherwise store it in the file. | |
config.set_value(section, key, get(configuration_variable)) | |
config.save(settings_filename) | |
## Helper function to store a variable in the config file. | |
func save(variable_name, value): | |
# Store in variable. | |
set(variable_name, value) | |
# Store in config file. | |
var section_and_key = split(variable_name) | |
var section = section_and_key[0] | |
var key = section_and_key[1] | |
# Load the file before saving into it. | |
var config = ConfigFile.new() | |
var err = config.load(settings_filename) | |
if err: | |
print("Error when loading config file: ", err) | |
else: | |
config.set_value(section, key, value) | |
config.save(settings_filename) | |
## Helper function to split a configuration variable name into section and variable name. | |
func split(variable_name) -> Array: | |
return variable_name.split("_", true, 1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment