# Undercooked - a game about cooking # Copyright 2024 metamuffin # Copyright 2024 tpart # Copyright 2024 nokoe # # 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 . # extends Node # Each setting contains a dictionary with the following keys: # "type": The type of the setting. Can be "toggle", "line", "range", "dropdown", or "dropdown_preset" # "value": The value of the setting. When using "dropdown", this contains an int # as the index for the respecitve element in the "options" array. # (Optional: Only when type "dropdown_preset") "apply": A dictionary to override all other settings. # (Optional: Only when type "range") "min" and "max": The min and max values. # "description": The setting name displayed in the settings menu. # (Optional: Only when type "dropdown") "options": An array which contains all # possible values. var default_profile := { "username": "Giovanni", "character": 0, "last_server_url": "" } var languages := [tr("System default"), "en", "de"] var default_settings := { "language": DropdownSetting.new(tr("Language"), 0, languages), "fullscreen": ToggleSetting.new(tr("Fullscreen"), false), "interpolate_camera_rotation": ToggleSetting.new(tr("Interpolate the camera rotation"), true), "invert_camera": ToggleSetting.new(tr("Invert camera movement"), false), "server_binary": TextSetting.new(tr("Server binary (leave empty to search PATH)"), "", "Enter path"), "server_data": TextSetting.new(tr("Server data directory (leave empty to auto-detect)"), "", "Enter path"), "voxel_gi": ToggleSetting.new(tr("Use VoxelGI (Blocks the game on map update but is more accurate)"), false), "sdfgi": ToggleSetting.new(tr("Use SDFGI (Doesn't block the game but produces more artifacts)"), false), "grass_amount": RangeSetting.new(tr("3D grass amount per grass tile"), 16, 0, 32), "setup_complete": ToggleSetting.new(tr("Initial setup complete. (Uncheck and restart to reenter)"), false) } var profile: Dictionary var settings: Dictionary var server_url = "" var error_message = "" func _init(): profile = load_dict("user://profile", default_profile) load_settings("user://settings") update_fullscreen() update_language() func _ready(): get_viewport().gui_focus_changed.connect(Sound.play_hover_maybe) func _input(_event): if Input.is_action_just_pressed("fullscreen"): Global.set_setting("fullscreen", not Global.get_setting("fullscreen")) save_settings() update_fullscreen() func update_language(): var lang_idx: int = get_setting("language") var lang = languages[lang_idx] if lang_idx != 0: # 0 is system language TranslationServer.set_locale(lang) else: TranslationServer.set_locale(OS.get_locale_language()) func update_fullscreen(): if get_setting("fullscreen"): DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) else: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) func save_profile(): save_dict("user://profile", profile) func save_settings(): for v in settings.values(): v.fetch_setting() var dict := {} for k in settings.keys(): var setting: GameSetting = settings[k] dict[k] = setting.get_value() save_dict("user://settings", dict) func save_dict(path: String, dict: Dictionary): var f = FileAccess.open(path, FileAccess.WRITE) f.store_var(dict.duplicate(true)) func load_dict(path: String, default: Dictionary) -> Dictionary: # TOCTOU here. Godot docs says its fine. if not FileAccess.file_exists(path): print("Skip profile load") return default var f = FileAccess.open(path, FileAccess.READ) var saved_dict = f.get_var() if saved_dict != null and saved_dict is Dictionary: add_missing_keys(saved_dict, default) print("Loaded dict: ", saved_dict) return saved_dict func load_settings(path: String): settings = default_settings if not FileAccess.file_exists(path): print("Skip settings load") return var f = FileAccess.open(path, FileAccess.READ) var saved_dict = f.get_var() if saved_dict != null and saved_dict is Dictionary: for k in default_settings.keys(): var setting: GameSetting = default_settings[k] if saved_dict.has(k): setting.set_value(saved_dict[k]) settings[k] = setting func on_vulkan() -> bool: return ProjectSettings.get_setting("rendering/rendering_device/driver") == "vulkan" func add_missing_keys(dict: Dictionary, reference: Dictionary): for k in reference.keys(): if !dict.has(k): dict[k] = reference[k] else: if dict[k] is Dictionary: add_missing_keys(dict[k], reference[k]) func get_setting(key: String): if settings.has(key): return settings[key].get_value() else: push_error("Tried to access setting \"%s\", which does not exist (missing key)" % key) return null func set_setting(key: String, value): if !settings.has(key): push_error("Tried to set setting \"%s\", which does not yet exist (missing key)" % key) return settings[key].set_value(value)