From e2075ec3808cd87ca3642a1f12d146a6eb03f360 Mon Sep 17 00:00:00 2001 From: teatov Date: Mon, 10 Feb 2025 21:00:02 +1000 Subject: [PATCH] add `Settings` --- project.godot | 8 +- scripts/globals/settings.gd | 157 ++++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 scripts/globals/settings.gd diff --git a/project.godot b/project.godot index b285a90..9771255 100644 --- a/project.godot +++ b/project.godot @@ -14,15 +14,21 @@ config/name="cadastery" config/version="0.0.1" run/main_scene="res://scenes/main.tscn" config/use_custom_user_dir=true -config/custom_user_dir_name="cadastery" +config/custom_user_dir_name="Cadastery" config/features=PackedStringArray("4.3", "Forward Plus") boot_splash/bg_color=Color(0, 0, 0, 1) boot_splash/show_image=false config/icon="res://icon.svg" +[autoload] + +Settings="*res://scripts/globals/settings.gd" + [debug] gdscript/warnings/untyped_declaration=2 +gdscript/warnings/unsafe_property_access=2 +gdscript/warnings/unsafe_method_access=2 gdscript/warnings/unsafe_call_argument=2 gdscript/warnings/integer_division=0 diff --git a/scripts/globals/settings.gd b/scripts/globals/settings.gd new file mode 100644 index 0000000..9a30f72 --- /dev/null +++ b/scripts/globals/settings.gd @@ -0,0 +1,157 @@ +extends Node + +const SETTING_USAGE_FLAG := PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_EDITOR +const CONFIG_PATH := "user://settings.cfg" + +@export_group("Gameplay") + +@export_group("Video") +@export_subgroup("Display") +@export var fullscreen: bool = false: + set(value): + DisplayServer.window_set_mode( + ( + DisplayServer.WINDOW_MODE_EXCLUSIVE_FULLSCREEN + if value + else DisplayServer.WINDOW_MODE_WINDOWED + ) + ) + fullscreen = value + +@export var vsync: DisplayServer.VSyncMode = DisplayServer.VSYNC_DISABLED: + set(value): + DisplayServer.window_set_vsync_mode(value) + vsync = value + +@export var limit_max_fps: bool = false: + set(value): + if value: + Engine.max_fps = max_fps + else: + Engine.max_fps = 0 + limit_max_fps = value + +@export var max_fps: int = 60: + set(value): + if limit_max_fps: + Engine.max_fps = value + else: + Engine.max_fps = 0 + max_fps = value + +@export_subgroup("Quality") +@export var resolution_scale: float = 1: + set(value): + get_viewport().scaling_3d_scale = value + resolution_scale = value + +@export var filtering: Viewport.Scaling3DMode = Viewport.SCALING_3D_MODE_BILINEAR: + set(value): + get_viewport().scaling_3d_mode = value + filtering = value + +@export_group("UI") +@export var ui_scale: float = 1: + set(value): + get_tree().root.content_scale_factor = value + ui_scale = value + +@export_group("Audio") + +@export_group("Controls") +@export_subgroup("KB & Mouse") +## rotation speed in degrees per pixel +@export var mouse_sensitivity: float = 0.5 +@export var invert_mouse_horizontal: bool = false +@export var invert_mouse_vertical: bool = false + +@export_subgroup("Controller") +## horizontal rotation speed in degrees per second +@export var controller_sensitivity_horizontal: float = 270 +## vertical rotation speed in degrees per second +@export var controller_sensitivity_vertical: float = 120 +@export var invert_controller_horizontal: bool = false +@export var invert_controller_vertical: bool = false + +var _default_values: Dictionary = {} + + +func _init() -> void: + for property in get_property_list(): + if _property_is_setting(property): + var property_name := StringName(property["name"] as String) + _default_values[property_name] = get(property_name) + + +func _ready() -> void: + process_mode = Node.PROCESS_MODE_ALWAYS + load_config() + + +func _input(event: InputEvent) -> void: + if event.is_action_pressed("toggle_fullscreen"): + fullscreen = not fullscreen + + +func set_defaults() -> void: + for property_name: StringName in _default_values.keys(): + set(property_name, _default_values[property_name]) + + var refresh_rate := DisplayServer.screen_get_refresh_rate() + if refresh_rate != -1: + max_fps = refresh_rate as int + + +func save_config() -> void: + var config := ConfigFile.new() + var section: String = "" + for property in get_property_list(): + if _property_is_section(property): + section = property["name"] as String + + if _property_is_setting(property): + var property_name := StringName(property["name"] as String) + config.set_value(section, property_name, get(property_name)) + + var err := config.save(CONFIG_PATH) + + if err != OK: + printerr("failed to save config file: %s" % err) + + +func load_config() -> void: + var config := ConfigFile.new() + var err := config.load(CONFIG_PATH) + + if err == ERR_FILE_NOT_FOUND: + set_defaults() + save_config() + return + + if err != OK: + printerr("failed to load config file: %s" % err) + return + + var section: String = "" + for property in get_property_list(): + if _property_is_section(property): + section = property["name"] as String + + if _property_is_setting(property): + var property_name := StringName(property["name"] as String) + + if not config.has_section_key(section, property_name): + print("%s not found in config, setting default" % property_name) + set(property_name, _default_values[property_name]) + continue + + var value: Variant = config.get_value(section, property_name) + set(property_name, value) + + +func _property_is_setting(property: Dictionary) -> bool: + return (property["usage"] as int & SETTING_USAGE_FLAG) == SETTING_USAGE_FLAG + + +func _property_is_section(property: Dictionary) -> bool: + return property["usage"] == PROPERTY_USAGE_GROUP