extends Node # ============================================================================ # SettingsManager.gd - 游戏设置偏好管理器 # ============================================================================ # 统一应用账号级设置,并向运行中的 UI、聊天和角色系统广播变更。 # 设置持久化以后端账号 profile 为准,本管理器不再读写 user:// 配置文件。 # ============================================================================ const BASE_VIEWPORT_SIZE: Vector2i = Vector2i(1920, 1440) const DEFAULT_SETTINGS: Dictionary = { "master_volume": 0.80, "music_volume": 0.60, "effects_volume": 0.90, "ui_scale": 1.00, "fullscreen": false, "show_interaction_hints": false, "show_name_always": false, "show_chat_bubbles": true, "world_notifications": true, "private_notifications": true, "friend_request_notifications": true, "allow_nearby_private": true, "allow_nearby_friend_requests": true, "mute_ui_sfx": false, } var _settings: Dictionary = DEFAULT_SETTINGS.duplicate(true) func _ready() -> void: _connect_auth_events() reset_to_defaults(false) apply_all_settings() func load_settings() -> void: _settings = DEFAULT_SETTINGS.duplicate(true) apply_all_settings() _emit_settings_changed() func save_settings() -> bool: _emit_settings_changed() return true func get_default_settings() -> Dictionary: return DEFAULT_SETTINGS.duplicate(true) func get_settings() -> Dictionary: return _settings.duplicate(true) func set_settings(settings: Dictionary, saveImmediately: bool = true) -> void: for key in DEFAULT_SETTINGS.keys(): if settings.has(key): _settings[key] = settings[key] apply_all_settings() if saveImmediately: save_settings() else: _emit_settings_changed() func apply_account_settings(settings: Dictionary) -> void: set_settings(settings, false) func reset_to_defaults(emitChanged: bool = true) -> void: _settings = DEFAULT_SETTINGS.duplicate(true) apply_all_settings() if emitChanged: _emit_settings_changed() func set_setting(key: String, value: Variant, saveImmediately: bool = true) -> void: if not DEFAULT_SETTINGS.has(key): return _settings[key] = value apply_all_settings() if saveImmediately: save_settings() else: _emit_settings_changed() func get_setting(key: String, fallback: Variant = null) -> Variant: return _settings.get(key, fallback if fallback != null else DEFAULT_SETTINGS.get(key)) func get_bool(key: String) -> bool: return bool(_settings.get(key, DEFAULT_SETTINGS.get(key, false))) func get_float(key: String) -> float: return float(_settings.get(key, DEFAULT_SETTINGS.get(key, 0.0))) func apply_all_settings() -> void: _apply_fullscreen_setting() _apply_audio_settings() _apply_ui_scale_setting() func _apply_audio_settings() -> void: _apply_bus_volume("Master", get_float("master_volume")) _apply_bus_volume("Music", get_float("music_volume")) _apply_bus_volume("SFX", get_float("effects_volume")) func _apply_bus_volume(busName: String, value: float) -> void: var busIndex := AudioServer.get_bus_index(busName) if busIndex < 0: return var clamped := clampf(value, 0.0, 1.0) AudioServer.set_bus_mute(busIndex, clamped <= 0.001) if clamped > 0.001: AudioServer.set_bus_volume_db(busIndex, linear_to_db(clamped)) func _apply_fullscreen_setting() -> void: if DisplayServer.get_name() == "headless": return var fullscreen := get_bool("fullscreen") DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN if fullscreen else DisplayServer.WINDOW_MODE_WINDOWED) func _apply_ui_scale_setting() -> void: var viewport := get_tree().root if viewport == null: return var scale := clampf(get_float("ui_scale"), 0.8, 1.2) viewport.content_scale_size = Vector2i( int(round(float(BASE_VIEWPORT_SIZE.x) / scale)), int(round(float(BASE_VIEWPORT_SIZE.y) / scale)) ) func _emit_settings_changed() -> void: var eventSystem := get_node_or_null("/root/EventSystem") if eventSystem != null: eventSystem.call("emit_event", EventNames.SETTINGS_CHANGED, get_settings()) func _connect_auth_events() -> void: var eventSystem := get_node_or_null("/root/EventSystem") if eventSystem == null: return eventSystem.call("connect_event", EventNames.AUTH_LOGOUT, _on_auth_logout, self) func _on_auth_logout(_data: Variant = null) -> void: reset_to_defaults()