extends Node const MIN_VOLUME = -20.0 var fullscreen: bool: get: return ( DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_FULLSCREEN ) set(value): DisplayServer.window_set_mode( DisplayServer.WINDOW_MODE_FULLSCREEN if value else DisplayServer.WINDOW_MODE_WINDOWED ) var master_volume: float: get: return AudioServer.get_bus_volume_db(0) set(value): AudioServer.set_bus_volume_db(0, value) AudioServer.set_bus_mute(0, bool(value < MIN_VOLUME + 0.0001)) var music_volume: float: get: return AudioServer.get_bus_volume_db(1) set(value): AudioServer.set_bus_volume_db(1, value) AudioServer.set_bus_mute(1, bool(value < MIN_VOLUME + 0.0001)) var sound_volume: float: get: return AudioServer.get_bus_volume_db(2) set(value): AudioServer.set_bus_volume_db(2, value) AudioServer.set_bus_mute(2, bool(value < MIN_VOLUME + 0.0001)) var _mouselook: bool = true var _mouselook_requested: bool = false var mouselook: bool: get: return _mouselook set(value): _mouselook = value _update_mouse_mode() var mouselook_requested: bool: get: return _mouselook_requested set(value): _mouselook_requested = value _update_mouse_mode() var mouse_sensitivity: float = 0.125 var mouse_wheel_sensitivity: float = 0.375 var right_stick_sensitivity: float = 0.125 var invert_mouselook := false var invert_mouse_wheel := false var invert_right_stick := false func _update_mouse_mode() -> void: if _mouselook and _mouselook_requested: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED else: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE func reset_non_input_map_options() -> void: fullscreen = false master_volume = 0.0 music_volume = 0.0 sound_volume = 0.0 mouselook = true mouse_sensitivity = 0.25 mouse_wheel_sensitivity = 0.375 right_stick_sensitivity = 0.25 invert_mouselook = false invert_mouse_wheel = false invert_right_stick = false func reset_input_map() -> void: InputMap.load_from_project_settings() func load_file() -> bool: var file := FileAccess.open("user://settings.json", FileAccess.READ) if file: var json = JSON.parse_string(file.get_as_text()) file.close() if json and json is Dictionary: fullscreen = json.get('fullscreen', false) as bool master_volume = json.get('master_volume', 0.0) as float music_volume = json.get('music_volume', 0.0) as float sound_volume = json.get('sound_volume', 0.0) as float mouselook = json.get('mouselook', true) as bool mouse_sensitivity = json.get('mouse_sensitivity', 0.125) as float mouse_wheel_sensitivity = json.get( 'mouse_wheel_sensitivity', 0.375 ) as float right_stick_sensitivity = json.get( 'right_stick_sensitivity', 0.125 ) as float invert_mouselook = json.get('invert_mouselook', false) as bool invert_mouse_wheel = json.get('invert_mouse_wheel', false) as bool invert_right_stick = json.get('invert_right_stick', false) as bool apply_bindings_config(json.get('bindings')) return true else: return false else: return false func save_file() -> bool: var file := FileAccess.open("user://settings.json", FileAccess.WRITE) if file: file.store_string(JSON.stringify({ 'fullscreen': fullscreen, 'master_volume': master_volume, 'music_volume': music_volume, 'sound_volume': sound_volume, 'mouselook': mouselook, 'mouse_sensitivity': mouse_sensitivity, 'mouse_wheel_sensitivity': mouse_wheel_sensitivity, 'right_stick_sensitivity': right_stick_sensitivity, 'invert_mouselook': invert_mouselook, 'invert_mouse_wheel': invert_mouse_wheel, 'invert_right_stick': invert_right_stick, 'bindings': make_bindings_config() }, "\t")) file.close() return true else: return false func apply_bindings_config(bindings: Dictionary) -> void: if bindings: for action in bindings: InputMap.action_erase_events(action) for binding in bindings[action]: InputMap.action_add_event(action, dict_to_input_event(binding)) func make_bindings_config() -> Dictionary: var bindings := {} for action in InputMap.get_actions(): var array: Array[Dictionary] = [] for event in InputMap.action_get_events(action): array.push_back(input_event_to_dict(event)) bindings[action] = array return bindings func dict_to_input_event(dict: Dictionary) -> InputEvent: var result: InputEvent match dict['TYPE']: 'InputEventKey': result = InputEventKey.new() 'InputEventJoypadMotion': result = InputEventJoypadMotion.new() 'InputEventJoypadButton': result = InputEventJoypadButton.new() 'InputEventMouseButton': result = InputEventMouseButton.new() 'InputEventMouseMotion': result = InputEventMouseMotion.new() for key in dict: if key != 'TYPE': result.set(key, dict[key]) return result func input_event_to_dict(event: InputEvent) -> Dictionary: var result := {} if event is InputEventKey: result['TYPE'] = 'InputEventKey' elif event is InputEventJoypadMotion: result['TYPE'] = 'InputEventJoypadMotion' elif event is InputEventJoypadButton: result['TYPE'] = 'InputEventJoypadButton' elif event is InputEventMouseButton: result['TYPE'] = 'InputEventMouseButton' elif event is InputEventMouseMotion: result['TYPE'] = 'InputEventMouseMotion' else: push_warning("skipping event of unhandled type: %s" % event) for property in event.get_property_list(): if property['usage'] & PROPERTY_USAGE_STORAGE != 0: var value = event.get(property['name']) if value is String or value is StringName: result[property['name']] = value as String elif ( value is int or value is float or value is bool or value == null ): result[property['name']] = value return result func _ready(): reset_non_input_map_options() reset_input_map() if not load_file(): save_file()