aboutsummaryrefslogtreecommitdiff
path: root/client/system/settings.gd
diff options
context:
space:
mode:
Diffstat (limited to 'client/system/settings.gd')
-rw-r--r--client/system/settings.gd200
1 files changed, 200 insertions, 0 deletions
diff --git a/client/system/settings.gd b/client/system/settings.gd
new file mode 100644
index 00000000..1cacfce9
--- /dev/null
+++ b/client/system/settings.gd
@@ -0,0 +1,200 @@
+# Hurry Curry! - a game about cooking
+# Copyright (C) 2025 Hurry Curry! contributors
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, version 3 of the License only.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+extends Node
+class_name Settings
+
+static func get_root():
+ return SettingsRoot.new([
+ SettingsCategory.new("gameplay", [
+ ToggleSetting.new("usernames", true),
+ ToggleSetting.new("latch_boost", true),
+ ToggleSetting.new("vibration", true),
+ ToggleSetting.new("invert_camera", false),
+ ToggleSetting.new("interpolate_camera_rotation", false),
+ ButtonSetting.new("setup_completed", false, launch_setup),
+ ToggleSetting.new("tutorial_disabled", false),
+ ToggleSetting.new("hints_started", false),
+ ToggleSetting.new("accessible_movement", false),
+ ToggleSetting.new("first_person", false),
+ DropdownSetting.new("interact_target", "dirsnap", ["dir", "dirsnap"]),
+ ]),
+ SettingsCategory.new("graphics", [
+ PresetRow.new("preset", {
+ "low": {"ui_blur": true, "aa": "disabled", "ssao": false, "taa": false, "shadows": false, "glow": false, "grass_amount": 0, "lq_trees": true},
+ "medium": {"ui_blur": true, "aa": "fx", "ssao": false, "taa": false, "shadows": true, "glow": false, "grass_amount": 16, "lq_trees": false},
+ "high": {"ui_blur": true, "aa": "ms2x", "ssao": true, "taa": false, "shadows": true, "glow": true, "grass_amount": 24, "lq_trees": false}
+ }),
+ DropdownSetting.new("fullscreen", "keep", ["keep", "always", "never"]),
+ DropdownSetting.new("aa", "ms2x" if Global.on_high_end() else "disabled", ["disabled", "fx", "ms2x", "ms4x"]),
+ ToggleSetting.new("ssao", true if Global.on_high_end() else false),
+ ToggleSetting.new("taa", false),
+ DropdownSetting.new("gi", "disabled", ["disabled", "sdfgi", "voxelgi"]),
+ ToggleSetting.new("shadows", true if Global.on_high_end() else false),
+ ToggleSetting.new("glow", true if Global.on_high_end() else false),
+ RangeSetting.new("grass_amount", 24 if Global.on_high_end() else 0, 0, 32, false),
+ ToggleSetting.new("lq_trees", false if Global.on_high_end() else true),
+ ToggleSetting.new("debug_info", false),
+ ToggleSetting.new("ui_blur", true)
+ ]),
+ SettingsCategory.new("audio", [
+ RangeSetting.new("master_volume", 0, -30, 0),
+ RangeSetting.new("music_volume", 0, -30, 0),
+ RangeSetting.new("sfx_volume", 0, -30, 0),
+ ]),
+ SettingsCategory.new("ui", [
+ DropdownSetting.new("touch_controls", "automatic", ["automatic", "enabled", "disabled"]),
+ DropdownSetting.new("language", "system", Global.language_list()),
+ ToggleSetting.new("hide_overlays", false),
+ DropdownSetting.new("scale_mode", "resize", ["resize", "disabled"]),
+ RangeSetting.new("scale_factor", 1. if not Global.on_mobile() else 1.5, 0.5, 1.5, 3),
+ ]),
+ SettingsCategory.new("input", InputManager.settings()),
+ SettingsCategory.new("server", [
+ PathSetting.new("binary_path", "", FileDialog.FileMode.FILE_MODE_OPEN_FILE),
+ PathSetting.new("editor_binary_path", "", FileDialog.FileMode.FILE_MODE_OPEN_DIR),
+ PathSetting.new("data_path", "", FileDialog.FileMode.FILE_MODE_OPEN_DIR),
+ TextSetting.new("name", "A Hurry Curry! Server"),
+ ToggleSetting.new("allow_external_connections", true),
+ ToggleSetting.new("enable_ipv6", true),
+ NumberSetting.new("bind_port", 27032, 1, 65535),
+ ToggleSetting.new("upnp", false),
+ ToggleSetting.new("mdns", true),
+ ToggleSetting.new("register", false),
+ ]),
+ SettingsCategory.new("online", [
+ ToggleSetting.new("use_registry", false),
+ TextSetting.new("registry_url", "https://hurrycurry-registry.metamuffin.org/"),
+ ToggleSetting.new("use_discover", true),
+ PathSetting.new("discover_binary", "", FileDialog.FileMode.FILE_MODE_OPEN_FILE),
+ ])
+ ])
+
+static var tree: GameSetting
+static var values: Dictionary = {}
+static var loaded_path: String
+
+static func read(key: String):
+ if !values.has(key):
+ push_error("Tried to access setting \"%s\", which does not exist (missing key)" % key)
+ return null
+ return values[key]
+
+static func write_unchecked(key: String, value):
+ value = value.duplicate(true) if value is Array else value
+ if key in values and typeof(values[key]) == typeof(value) and not value is Array and values[key] == value: return
+ values[key] = value
+ trigger_hook(key, value)
+
+static func write(key: String, value):
+ if !values.has(key):
+ push_error("Tried to set setting \"%s\", which does not yet exist (missing key)" % key)
+ return
+ else: write_unchecked(key, value)
+
+static func load(path: String):
+ tree = get_root()
+ loaded_path = path
+ var changed = {}
+ if FileAccess.file_exists(path):
+ var f = FileAccess.open(path, FileAccess.READ)
+ changed = JSON.parse_string(f.get_as_text())
+ tree.load(changed)
+
+static func save():
+ var changed = {}
+ tree.save(changed)
+ var f = FileAccess.open(loaded_path, FileAccess.WRITE)
+ f.store_string(JSON.stringify(changed))
+
+static func trigger_hook(key: String, value):
+ if change_hooks_display.get(key) != null: change_hooks_display.get(key).callv([value] if value != null else [])
+ if change_hooks_apply.get(key) != null: change_hooks_apply.get(key).callv([value] if value != null else [])
+ if key.find(".") != -1: trigger_hook(key.rsplit(".", false, 1)[0], null)
+
+static func hook_changed(key: String, display: bool, callable: Callable):
+ if display: change_hooks_display[key] = callable
+ else: change_hooks_apply[key] = callable
+
+static func hook_changed_init(key: String, display: bool, callable: Callable):
+ hook_changed(key, display, callable)
+ callable.call(read(key))
+
+static func get_category_dict(prefix: String):
+ var map = {}
+ for k in values.keys():
+ var kn = k.trim_prefix(prefix + ".")
+ if kn == k: continue
+ map[kn] = read(k)
+ return map
+
+static func launch_setup():
+ Global.focused_menu.submenu("res://gui/menus/setup/setup.tscn")
+
+static var change_hooks_display = {}
+static var change_hooks_apply = {
+ "input": h_input,
+ "gameplay.hints_started": h_hints_started,
+ "graphics.aa": h_aa,
+ "graphics.taa": h_taa,
+ "graphics.fullscreen": h_fullscreen,
+ "ui.scale_mode": h_scale_mode,
+ "ui.scale_factor": h_scale_factor,
+ "ui.language": h_language,
+ "audio.master_volume": h_volume_master,
+ "audio.music_volume": h_volume_music,
+ "audio.sfx_volume": h_volume_sfx,
+}
+
+static func h_aa(_mode):
+ Global.configure_viewport_aa(Global.get_viewport())
+
+static func h_taa(enabled):
+ Global.get_viewport().use_taa = enabled
+
+static func h_scale_mode(mode: String):
+ var root = Global.get_tree().root
+ if OS.has_feature("movie"):
+ root.content_scale_mode = Window.CONTENT_SCALE_MODE_VIEWPORT
+ root.content_scale_aspect = Window.CONTENT_SCALE_ASPECT_KEEP
+ else: match mode:
+ "resize": root.content_scale_mode = Window.CONTENT_SCALE_MODE_CANVAS_ITEMS
+ "disabled": root.content_scale_mode = Window.CONTENT_SCALE_MODE_DISABLED
+
+static func h_scale_factor(value: float):
+ Global.get_tree().root.content_scale_factor = value
+
+static func h_volume_master(value: float): Sound.set_volume(0, value)
+static func h_volume_music(value: float): Sound.set_volume(1, value)
+static func h_volume_sfx(value: float): Sound.set_volume(2, value)
+
+static func h_language(language: String):
+ if language == "system": language = OS.get_locale_language()
+ TranslationServer.set_locale(language)
+
+static func h_fullscreen(mode: String):
+ match mode:
+ "keep": pass
+ "always": DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)
+ "never": if DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_FULLSCREEN:
+ DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
+
+static func h_input():
+ InputManager.apply_input_map(Settings.get_category_dict("input"))
+
+static func h_hints_started(started: bool):
+ if not started:
+ for k in Profile.values["hints"].keys():
+ Profile.set_hint(k, false)