diff --git a/project.godot b/project.godot index 4115fdb..4ee847e 100644 --- a/project.godot +++ b/project.godot @@ -25,6 +25,7 @@ config/icon="res://icon.svg" Referencer="*res://scripts/globals/referencer.gd" Inputer="*res://scripts/globals/inputer.gd" Debugger="*res://scenes/debugger.tscn" +Settings="*res://scripts/globals/settings.gd" [debug] @@ -63,6 +64,12 @@ toggle_debug={ "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":96,"key_label":0,"unicode":96,"location":0,"echo":false,"script":null) ] } +toggle_fullscreen={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194342,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194309,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} move_up={ "deadzone": 0.5, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) diff --git a/scripts/globals/settings.gd b/scripts/globals/settings.gd new file mode 100644 index 0000000..0250906 --- /dev/null +++ b/scripts/globals/settings.gd @@ -0,0 +1,161 @@ +extends Node + +const SETTING_USAGE_FLAG := PROPERTY_USAGE_SCRIPT_VARIABLE | PROPERTY_USAGE_EDITOR +const CONFIG_PATH := "user://settings.cfg" + +@export_group("Gameplay") +@export_subgroup("Camera") +@export var camera_fov: float = 75: + set(value): + camera_fov = value + +@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