diff --git a/export_presets.cfg b/export_presets.cfg index 370bbc2..5f595cd 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -9,7 +9,7 @@ custom_features="" export_filter="all_resources" include_filter="" exclude_filter="builds/*,playtest/*,scripts/*" -export_path="builds/v0.4.1-prealpha/windows-x86_64/NETfishing.exe" +export_path="builds/v0.4.0-prealpha/windows-x86_64/NETfishing.exe" patches=PackedStringArray() encryption_include_filters="" encryption_exclude_filters="" @@ -35,11 +35,11 @@ application/modify_resources=true application/icon="" application/console_wrapper_icon="" application/icon_interpolation=4 -application/file_version="0.4.1.0" -application/product_version="0.4.1.0" +application/file_version="0.4.0.0" +application/product_version="0.4.0.0" application/company_name="" application/product_name="NETfishing" -application/file_description="NETfishing v0.4.1-prealpha" +application/file_description="NETfishing v0.4.0-prealpha" application/copyright="" application/trademarks="" application/export_angle=0 @@ -83,8 +83,8 @@ architectures/armeabi-v7a=false architectures/arm64-v8a=true architectures/x86=false architectures/x86_64=false -version/code=40100 -version/name="0.4.1-prealpha" +version/code=40000 +version/name="0.4.0-prealpha" package/unique_name="io.makearmy.netfishing" package/name="NETfishing" package/signed=true @@ -121,7 +121,7 @@ custom_features="" export_filter="all_resources" include_filter="" exclude_filter="builds/*,playtest/*,scripts/*" -export_path="builds/v0.4.1-prealpha/linux-x86_64/NETfishing.x86_64" +export_path="builds/v0.4.0-prealpha/linux-x86_64/NETfishing.x86_64" patches=PackedStringArray() encryption_include_filters="" encryption_exclude_filters="" diff --git a/main/main.gd b/main/main.gd index 343435c..059d0b1 100644 --- a/main/main.gd +++ b/main/main.gd @@ -16,9 +16,6 @@ const PlayerSettingsManagerType = preload( "res://settings/player_settings_manager.gd" ) const PlayerSettingsType = preload("res://settings/player_settings.gd") -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) const TitleScreenType = preload("res://ui/title_screen.gd") const PauseMenuType = preload("res://ui/pause_menu.gd") const ItemCatalogType = preload("res://items/item_catalog.gd") @@ -114,9 +111,6 @@ const SHOP_PATTERN_SCALE: float = 1.75 @onready var _water_recovery: WaterRecoveryControllerType = %WaterRecovery @onready var _save_manager: PlayerSaveManagerType = %PlayerSaveManager @onready var _settings_manager: PlayerSettingsManagerType = %PlayerSettingsManager -@onready var _controller_mapping_manager: ControllerMappingManagerType = ( - %ControllerMappingManager -) @onready var _interface_fonts: InterfaceFontController = %InterfaceFontController @onready var _title_music: AudioStreamPlayer = %TitleMusic @onready var _ui_pixelation: UIPixelationPresenterType = %UIPresentation @@ -540,7 +534,6 @@ func _initialize_after_data_root() -> void: _network_session, _interface_fonts, ) - _game_ui.setup_controller_mapping(_controller_mapping_manager) _data_root.conflict_detected.connect(_on_portable_conflict) _data_root.status_changed.connect(_on_data_root_status) if ( @@ -934,8 +927,6 @@ func _on_peer_identity_observed(_peer_id: int, status: String) -> void: func _input(event: InputEvent) -> void: - if _game_ui.is_controller_mapping_capturing(): - return if ( not ( event.is_action_pressed("ui_cancel") @@ -944,7 +935,6 @@ func _input(event: InputEvent) -> void: or (event is InputEventKey and event.echo) ): return - var pause_open_requested: bool = _is_pause_open_request(event) var title_screen: TitleScreenType = _game_ui.get_title_screen() if title_screen.visible or not _gameplay_started: return @@ -963,8 +953,7 @@ func _input(event: InputEvent) -> void: get_viewport().set_input_as_handled() return if ( - pause_open_requested - and not _water_recovery.is_recovery_active() + not _water_recovery.is_recovery_active() and _fishing_spot.can_open_system_menu() ): _game_ui.close_player_menu_for_game_menu() @@ -972,13 +961,6 @@ func _input(event: InputEvent) -> void: get_viewport().set_input_as_handled() -func _is_pause_open_request(event: InputEvent) -> bool: - return ( - event.is_action_pressed("open_system_menu") - or event is InputEventKey - ) - - func _unhandled_input(event: InputEvent) -> void: if ( not _gameplay_started @@ -1020,7 +1002,6 @@ func _apply_runtime_settings(settings: PlayerSettingsType) -> void: _game_ui.set_edge_docks( settings.chat_dock_right, settings.paint_dock_right, - settings.chat_mobile_mode, ) diff --git a/main/main.tscn b/main/main.tscn index 64247ca..8f66df1 100644 --- a/main/main.tscn +++ b/main/main.tscn @@ -55,7 +55,6 @@ [ext_resource type="Script" path="res://network/network_job_service.gd" id="53_network_jobs"] [ext_resource type="Script" path="res://world/shoreline_ambience.gd" id="54_shoreline_ambience"] [ext_resource type="AudioStream" path="res://audio/ambience/waves.wav" id="55_waves"] -[ext_resource type="Script" path="res://settings/controller_mapping_manager.gd" id="56_controller_mapping"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_title_water_native"] shader = ExtResource("40_title_water") @@ -274,10 +273,6 @@ script = ExtResource("9_save") unique_name_in_owner = true script = ExtResource("10_settings") -[node name="ControllerMappingManager" type="Node" parent="."] -unique_name_in_owner = true -script = ExtResource("56_controller_mapping") - [node name="TitleMusic" type="AudioStreamPlayer" parent="." unique_id=1292939956] unique_name_in_owner = true stream = ExtResource("13_title_music") diff --git a/player/player.gd b/player/player.gd index e5a5076..99a8e65 100644 --- a/player/player.gd +++ b/player/player.gd @@ -24,9 +24,6 @@ const PlayerArtUnlocksType = preload( const PlayerExperienceType = preload( "res://progression/player_experience.gd" ) -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) const FishingRodAttachmentScene = preload( "res://player/fishing_rod_attachment.tscn" ) @@ -35,10 +32,6 @@ const CHARACTER_IDLE_ANIMATION: StringName = &"idle" const CHARACTER_WALKING_ANIMATION: StringName = &"walking" const CHARACTER_SITTING_ANIMATION: StringName = &"sitting" const BASE_REEL_SPEED: float = 0.16 -# The target Android handheld exposes its physical right trigger through -# Godot's left-trigger axis. Keep the role named here so the platform mapping -# remains isolated from camera behavior. -const CONTROLLER_ZOOM_TRIGGER_AXIS: JoyAxis = JOY_AXIS_TRIGGER_LEFT var appearance_snapshot: Dictionary = ( CharacterCustomizationCatalog.default_snapshot() @@ -167,7 +160,6 @@ var _character_animation_name: StringName = &"" var _sitting: bool = false var _fishing_rod: Node3D var _fishing_rod_tip: Marker3D -var _controller_mapping_manager: ControllerMappingManagerType func _ready() -> void: @@ -177,12 +169,6 @@ func _ready() -> void: _camera.current = local_control_enabled -func set_controller_mapping_manager( - mapping_manager: ControllerMappingManagerType, -) -> void: - _controller_mapping_manager = mapping_manager - - func _initialize_fishing_rod() -> void: var skeleton := get_node_or_null( "Visuals/CharacterRig/CharacterRig/Skeleton3D" @@ -301,10 +287,13 @@ func _process(delta: float) -> void: _camera_dragging = false if _camera_input_enabled: - var stick: Vector2 = _get_controller_camera_stick() + var stick: Vector2 = Vector2( + Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), + Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y) + ) if stick.length() > controller_camera_deadzone: if ( - _get_controller_zoom_strength() + Input.get_joy_axis(0, JOY_AXIS_TRIGGER_RIGHT) >= controller_trigger_threshold ): var vertical_zoom_input: float = _apply_axis_deadzone(stick.y) @@ -332,36 +321,6 @@ func _process(delta: float) -> void: ) -func _get_controller_camera_stick() -> Vector2: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): - return Vector2( - _controller_mapping_manager.get_role_axis( - ControllerMappingManagerType.ROLE_RIGHT_STICK_X - ), - _controller_mapping_manager.get_role_axis( - ControllerMappingManagerType.ROLE_RIGHT_STICK_Y - ), - ) - return Vector2( - Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), - Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y), - ) - - -func _get_controller_zoom_strength() -> float: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): - return _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_RT - ) - return Input.get_joy_axis(0, CONTROLLER_ZOOM_TRIGGER_AXIS) - - func _update_character_animation() -> void: if _character_animation_player == null: return diff --git a/playtest/README-PLAYTEST.txt b/playtest/README-PLAYTEST.txt index 7bc45ca..48ee3fd 100644 --- a/playtest/README-PLAYTEST.txt +++ b/playtest/README-PLAYTEST.txt @@ -1,6 +1,6 @@ NETfishing -v0.4.1-prealpha -Pre-Alpha 0.4.1 +v0.4.0-prealpha +Pre-Alpha 0.4.0 Thank you for trying this early private playtest. diff --git a/project.godot b/project.godot index 4721204..9ec4067 100644 --- a/project.godot +++ b/project.godot @@ -11,7 +11,7 @@ config_version=5 [application] config/name="NETFISHING" -config/version="0.4.1-prealpha" +config/version="0.4.0-prealpha" run/main_scene="res://main/main.tscn" config/features=PackedStringArray("4.7", "GL Compatibility") config/icon="res://icon.svg" @@ -162,7 +162,7 @@ hotbar_next={ open_backpack={ "deadzone": 0.2, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":16,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194306,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) -, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":2,"pressure":0.0,"pressed":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":4,"pressure":0.0,"pressed":false,"script":null) ] } open_system_menu={ @@ -183,11 +183,6 @@ open_quick_actions={ } open_chat={ "deadzone": 0.2, -"events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":4,"pressure":0.0,"pressed":false,"script":null) -] -} -focus_gameplay={ -"deadzone": 0.2, "events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":9,"pressure":0.0,"pressed":false,"script":null) ] } diff --git a/scripts/build_playtest.sh b/scripts/build_playtest.sh index 5871383..2c168c8 100755 --- a/scripts/build_playtest.sh +++ b/scripts/build_playtest.sh @@ -4,12 +4,12 @@ set -euo pipefail readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" -readonly BUILD_ROOT="${PROJECT_ROOT}/builds/v0.4.1-prealpha" +readonly BUILD_ROOT="${PROJECT_ROOT}/builds/v0.4.0-prealpha" readonly WINDOWS_DIR="${BUILD_ROOT}/windows-x86_64" readonly LINUX_DIR="${BUILD_ROOT}/linux-x86_64" readonly README_SOURCE="${PROJECT_ROOT}/playtest/README-PLAYTEST.txt" -readonly WINDOWS_ZIP="${BUILD_ROOT}/NETfishing-v0.4.1-prealpha-windows-x86_64.zip" -readonly LINUX_ZIP="${BUILD_ROOT}/NETfishing-v0.4.1-prealpha-linux-x86_64.zip" +readonly WINDOWS_ZIP="${BUILD_ROOT}/NETfishing-v0.4.0-prealpha-windows-x86_64.zip" +readonly LINUX_ZIP="${BUILD_ROOT}/NETfishing-v0.4.0-prealpha-linux-x86_64.zip" readonly GODOT_BIN="${GODOT_BIN:-godot}" if [[ ! -f "${PROJECT_ROOT}/project.godot" ]]; then diff --git a/settings/controller_mapping_manager.gd b/settings/controller_mapping_manager.gd deleted file mode 100644 index f352888..0000000 --- a/settings/controller_mapping_manager.gd +++ /dev/null @@ -1,751 +0,0 @@ -class_name ControllerMappingManager -extends Node - -signal active_profile_changed -signal active_controller_changed(controller_name: String) - -const FORMAT_VERSION: int = 1 -const PROFILE_PATH: String = "user://controller_mappings.json" -const PROFILE_TEMP_PATH: String = "user://controller_mappings.json.tmp" -const PROFILE_BACKUP_PATH: String = "user://controller_mappings.json.backup" -const MAX_PROFILE_BYTES: int = 1024 * 1024 -const CAPTURE_AXIS_THRESHOLD: float = 0.55 -const ROLE_A: StringName = &"a" -const ROLE_B: StringName = &"b" -const ROLE_X: StringName = &"x" -const ROLE_Y: StringName = &"y" -const ROLE_LB: StringName = &"lb" -const ROLE_RB: StringName = &"rb" -const ROLE_LT: StringName = &"lt" -const ROLE_RT: StringName = &"rt" -const ROLE_SELECT: StringName = &"select" -const ROLE_START: StringName = &"start" -const ROLE_LEFT_STICK_CLICK: StringName = &"left_stick_click" -const ROLE_RIGHT_STICK_CLICK: StringName = &"right_stick_click" -const ROLE_DPAD_UP: StringName = &"dpad_up" -const ROLE_DPAD_DOWN: StringName = &"dpad_down" -const ROLE_DPAD_LEFT: StringName = &"dpad_left" -const ROLE_DPAD_RIGHT: StringName = &"dpad_right" -const ROLE_LEFT_STICK_X: StringName = &"left_stick_x" -const ROLE_LEFT_STICK_Y: StringName = &"left_stick_y" -const ROLE_RIGHT_STICK_X: StringName = &"right_stick_x" -const ROLE_RIGHT_STICK_Y: StringName = &"right_stick_y" - -const ROLE_ORDER: Array[StringName] = [ - ROLE_A, - ROLE_B, - ROLE_X, - ROLE_Y, - ROLE_LB, - ROLE_RB, - ROLE_LT, - ROLE_RT, - ROLE_SELECT, - ROLE_START, - ROLE_LEFT_STICK_CLICK, - ROLE_RIGHT_STICK_CLICK, - ROLE_DPAD_UP, - ROLE_DPAD_DOWN, - ROLE_DPAD_LEFT, - ROLE_DPAD_RIGHT, - ROLE_LEFT_STICK_X, - ROLE_LEFT_STICK_Y, - ROLE_RIGHT_STICK_X, - ROLE_RIGHT_STICK_Y, -] - -const ROLE_LABELS: Dictionary = { - ROLE_A: "jump / menu accept", - ROLE_B: "menu back", - ROLE_X: "player menu", - ROLE_Y: "interact", - ROLE_LB: "focus chat or world", - ROLE_RB: "primary action", - ROLE_LT: "virtual mouse", - ROLE_RT: "camera zoom", - ROLE_SELECT: "chat", - ROLE_START: "pause", - ROLE_LEFT_STICK_CLICK: "sprint", - ROLE_RIGHT_STICK_CLICK: "unassigned stick click", - ROLE_DPAD_UP: "emote wheel", - ROLE_DPAD_DOWN: "quick menu", - ROLE_DPAD_LEFT: "previous hotbar slot", - ROLE_DPAD_RIGHT: "next hotbar slot", - ROLE_LEFT_STICK_X: "move left / right", - ROLE_LEFT_STICK_Y: "move up / down", - ROLE_RIGHT_STICK_X: "camera left / right", - ROLE_RIGHT_STICK_Y: "camera up / down", -} - -const ROLE_PROMPTS: Dictionary = { - ROLE_A: "press the a button", - ROLE_B: "press the b button", - ROLE_X: "press the x button", - ROLE_Y: "press the y button", - ROLE_LB: "press the left bumper", - ROLE_RB: "press the right bumper", - ROLE_LT: "squeeze the left trigger", - ROLE_RT: "squeeze the right trigger", - ROLE_SELECT: "press select / back", - ROLE_START: "press start", - ROLE_LEFT_STICK_CLICK: "click the left stick", - ROLE_RIGHT_STICK_CLICK: "click the right stick", - ROLE_DPAD_UP: "press d-pad up", - ROLE_DPAD_DOWN: "press d-pad down", - ROLE_DPAD_LEFT: "press d-pad left", - ROLE_DPAD_RIGHT: "press d-pad right", - ROLE_LEFT_STICK_X: "move the left stick left", - ROLE_LEFT_STICK_Y: "move the left stick up", - ROLE_RIGHT_STICK_X: "move the right stick left", - ROLE_RIGHT_STICK_Y: "move the right stick up", -} - -const STICK_AXIS_ROLES: Array[StringName] = [ - ROLE_LEFT_STICK_X, - ROLE_LEFT_STICK_Y, - ROLE_RIGHT_STICK_X, - ROLE_RIGHT_STICK_Y, -] -const TRIGGER_ROLES: Array[StringName] = [ROLE_LT, ROLE_RT] - -const BUTTON_ACTION_ROLES: Dictionary = { - &"jump": ROLE_A, - &"ui_accept": ROLE_A, - &"ui_cancel": ROLE_B, - &"open_backpack": ROLE_X, - &"interact": ROLE_Y, - &"focus_gameplay": ROLE_LB, - &"fish_primary": ROLE_RB, - &"open_chat": ROLE_SELECT, - &"open_system_menu": ROLE_START, - &"sprint": ROLE_LEFT_STICK_CLICK, - &"open_emotes": ROLE_DPAD_UP, - &"open_quick_actions": ROLE_DPAD_DOWN, - &"hotbar_previous": ROLE_DPAD_LEFT, - &"hotbar_next": ROLE_DPAD_RIGHT, -} - -const AXIS_ACTION_ROLES: Dictionary = { - &"move_left": [ROLE_LEFT_STICK_X, -1.0], - &"move_right": [ROLE_LEFT_STICK_X, 1.0], - &"move_forward": [ROLE_LEFT_STICK_Y, -1.0], - &"move_backward": [ROLE_LEFT_STICK_Y, 1.0], - &"ui_left": [ROLE_LEFT_STICK_X, -1.0], - &"ui_right": [ROLE_LEFT_STICK_X, 1.0], - &"ui_up": [ROLE_LEFT_STICK_Y, -1.0], - &"ui_down": [ROLE_LEFT_STICK_Y, 1.0], -} - -const UI_DPAD_ACTION_ROLES: Dictionary = { - &"ui_up": ROLE_DPAD_UP, - &"ui_down": ROLE_DPAD_DOWN, - &"ui_left": ROLE_DPAD_LEFT, - &"ui_right": ROLE_DPAD_RIGHT, -} - -var _profiles: Dictionary = {} -var _active_device_id: int = 0 -var _active_profile_key: String = "default" -var _active_controller_name: String = "controller" -var _default_joy_events: Dictionary = {} -var _axis_rest_by_device: Dictionary = {} - - -func _ready() -> void: - _capture_project_defaults() - load_profiles() - _refresh_active_controller() - - -func _input(event: InputEvent) -> void: - var device_id: int = -1 - var button_event := event as InputEventJoypadButton - if button_event != null and button_event.pressed: - device_id = button_event.device - var motion_event := event as InputEventJoypadMotion - if ( - motion_event != null - and absf(motion_event.axis_value) >= CAPTURE_AXIS_THRESHOLD - ): - device_id = motion_event.device - if device_id >= 0 and device_id != _active_device_id: - _set_active_controller(device_id) - - -func _process(_delta: float) -> void: - var connected: Array[int] = Input.get_connected_joypads() - if connected.is_empty(): - connected.append(0) - if not connected.has(_active_device_id): - _set_active_controller(connected[0]) - elif ( - _active_controller_name == "controller" - and Input.get_connected_joypads().has(_active_device_id) - ): - _set_active_controller(_active_device_id) - _sample_axis_rest_values(_active_device_id) - - -func load_profiles() -> bool: - _recover_interrupted_write() - if not FileAccess.file_exists(PROFILE_PATH): - _profiles = {} - return true - var file := FileAccess.open(PROFILE_PATH, FileAccess.READ) - if file == null: - return false - if file.get_length() > MAX_PROFILE_BYTES: - file.close() - push_warning("Controller mappings are too large; using defaults.") - _profiles = {} - return false - var json := JSON.new() - var error: Error = json.parse(file.get_as_text()) - file.close() - if error != OK or typeof(json.data) != TYPE_DICTIONARY: - push_warning("Controller mappings are malformed; using defaults.") - _profiles = {} - return false - var data: Dictionary = json.data - if int(data.get("format_version", -1)) != FORMAT_VERSION: - push_warning("Controller mapping version is unsupported; using defaults.") - _profiles = {} - return false - var raw_profiles: Variant = data.get("profiles", {}) - if typeof(raw_profiles) != TYPE_DICTIONARY: - _profiles = {} - return false - _profiles = _validated_profiles(raw_profiles as Dictionary) - return true - - -func _validated_profiles(raw_profiles: Dictionary) -> Dictionary: - var validated: Dictionary = {} - for key_value: Variant in raw_profiles: - var raw_profile: Variant = raw_profiles[key_value] - if typeof(raw_profile) != TYPE_DICTIONARY: - continue - var profile := raw_profile as Dictionary - var raw_bindings: Variant = profile.get("bindings", {}) - if typeof(raw_bindings) != TYPE_DICTIONARY: - continue - var bindings := raw_bindings as Dictionary - var complete: bool = true - for role: StringName in ROLE_ORDER: - var raw_binding: Variant = bindings.get(str(role), {}) - if ( - typeof(raw_binding) != TYPE_DICTIONARY - or not validate_binding(role, raw_binding as Dictionary) - ): - complete = false - break - if not complete: - continue - validated[str(key_value)] = { - "controller_name": str( - profile.get("controller_name", "controller") - ), - "bindings": bindings.duplicate(true), - } - return validated - - -func has_custom_mapping() -> bool: - return _profiles.has(_active_profile_key) - - -func get_active_device_id() -> int: - return _active_device_id - - -func get_active_controller_name() -> String: - return _active_controller_name - - -func get_role_label(role: StringName) -> String: - return str(ROLE_LABELS.get(role, str(role))) - - -func get_role_prompt(role: StringName) -> String: - return str(ROLE_PROMPTS.get(role, "press or move the requested input")) - - -func role_expects_axis(role: StringName) -> bool: - return role in STICK_AXIS_ROLES - - -func role_accepts_axis(role: StringName) -> bool: - return role in STICK_AXIS_ROLES or role in TRIGGER_ROLES - - -func get_active_bindings() -> Dictionary: - var raw_profile: Variant = _profiles.get(_active_profile_key, {}) - var profile: Dictionary = ( - raw_profile as Dictionary - if typeof(raw_profile) == TYPE_DICTIONARY else {} - ) - var bindings: Variant = profile.get("bindings", {}) - if ( - typeof(bindings) == TYPE_DICTIONARY - and not (bindings as Dictionary).is_empty() - ): - return (bindings as Dictionary).duplicate(true) - return default_bindings() - - -func get_binding(role: StringName) -> Dictionary: - var bindings: Dictionary = get_active_bindings() - var binding: Variant = bindings.get(str(role), {}) - if typeof(binding) == TYPE_DICTIONARY: - return (binding as Dictionary).duplicate(true) - return {} - - -func set_binding(role: StringName, binding: Dictionary) -> bool: - if role not in ROLE_ORDER or not validate_binding(role, binding): - return false - var bindings: Dictionary = get_active_bindings() - bindings[str(role)] = binding.duplicate(true) - return replace_active_bindings(bindings) - - -func replace_active_bindings(bindings: Dictionary) -> bool: - for role: StringName in ROLE_ORDER: - var binding: Variant = bindings.get(str(role), {}) - if typeof(binding) != TYPE_DICTIONARY: - return false - if not validate_binding(role, binding as Dictionary): - return false - var previous: Dictionary = _profiles.duplicate(true) - _profiles[_active_profile_key] = { - "controller_name": _active_controller_name, - "bindings": bindings.duplicate(true), - } - if not _save_profiles(): - _profiles = previous - return false - _apply_active_profile() - active_profile_changed.emit() - return true - - -func reset_active_profile() -> bool: - if not _profiles.has(_active_profile_key): - _restore_project_defaults() - active_profile_changed.emit() - return true - var previous: Dictionary = _profiles.duplicate(true) - _profiles.erase(_active_profile_key) - if not _save_profiles(): - _profiles = previous - return false - _restore_project_defaults() - active_profile_changed.emit() - return true - - -func binding_from_event(role: StringName, event: InputEvent) -> Dictionary: - var button := event as InputEventJoypadButton - if role in TRIGGER_ROLES and button != null and button.pressed: - return { - "kind": "button", - "button": int(button.button_index), - } - if role_accepts_axis(role): - var motion := event as InputEventJoypadMotion - if motion == null: - return {} - _sample_axis_rest_values(motion.device) - var rest: float = _axis_rest_value(motion.device, motion.axis) - var travel: float = motion.axis_value - rest - if absf(travel) < CAPTURE_AXIS_THRESHOLD: - return {} - return { - "kind": "axis", - "axis": int(motion.axis), - "direction": signf(travel), - "rest": rest, - } - if button == null or not button.pressed: - return {} - return { - "kind": "button", - "button": int(button.button_index), - } - - -func validate_binding(role: StringName, binding: Dictionary) -> bool: - var binding_kind: String = str(binding.get("kind", "")) - if role_expects_axis(role) and binding_kind != "axis": - return false - if role not in STICK_AXIS_ROLES and role not in TRIGGER_ROLES: - if binding_kind != "button": - return false - if role in TRIGGER_ROLES and binding_kind not in ["axis", "button"]: - return false - if binding_kind == "button": - var button_index: int = int(binding.get("button", -1)) - return button_index >= 0 and button_index < JOY_BUTTON_MAX - var axis_index: int = int(binding.get("axis", -1)) - var direction: float = float(binding.get("direction", 0.0)) - var rest: float = float(binding.get("rest", 0.0)) - return ( - axis_index >= 0 - and axis_index < JOY_AXIS_MAX - and not is_zero_approx(direction) - and rest >= -1.0 - and rest <= 1.0 - ) - - -func binding_label(binding: Dictionary) -> String: - if str(binding.get("kind", "")) == "button": - return "button %d" % int(binding.get("button", -1)) - if str(binding.get("kind", "")) == "axis": - return "axis %d %s" % [ - int(binding.get("axis", -1)), - "+" if float(binding.get("direction", 0.0)) > 0.0 else "−", - ] - return "unmapped" - - -func get_role_strength(role: StringName) -> float: - if not has_custom_mapping(): - return 0.0 - var binding: Dictionary = get_binding(role) - if str(binding.get("kind", "")) == "button": - return ( - 1.0 - if Input.is_joy_button_pressed( - _active_device_id, - int(binding.get("button", -1)), - ) - else 0.0 - ) - return _axis_binding_strength(binding) - - -func get_role_axis(role: StringName) -> float: - if not has_custom_mapping(): - return 0.0 - var binding: Dictionary = get_binding(role) - if str(binding.get("kind", "")) != "axis": - return 0.0 - var raw: float = Input.get_joy_axis( - _active_device_id, - int(binding.get("axis", -1)), - ) - var direction: float = signf(float(binding.get("direction", -1.0))) - var rest: float = float(binding.get("rest", 0.0)) - var delta: float = raw - rest - if is_zero_approx(delta): - return 0.0 - var toward_captured_direction: bool = signf(delta) == direction - var endpoint: float = direction if toward_captured_direction else -direction - var available: float = absf(endpoint - rest) - if available <= 0.001: - return 0.0 - var magnitude: float = clampf(absf(delta) / available, 0.0, 1.0) - return -magnitude if toward_captured_direction else magnitude - - -func event_matches_role(event: InputEvent, role: StringName) -> bool: - if not has_custom_mapping(): - return false - var binding: Dictionary = get_binding(role) - var button := event as InputEventJoypadButton - if button != null and str(binding.get("kind", "")) == "button": - return button.button_index == int(binding.get("button", -1)) - var motion := event as InputEventJoypadMotion - if motion == null or str(binding.get("kind", "")) != "axis": - return false - if motion.axis != int(binding.get("axis", -1)): - return false - return _axis_binding_strength(binding, motion.axis_value) >= 0.5 - - -func event_uses_role(event: InputEvent, role: StringName) -> bool: - if not has_custom_mapping(): - return false - var binding: Dictionary = get_binding(role) - var button := event as InputEventJoypadButton - if button != null and str(binding.get("kind", "")) == "button": - return button.button_index == int(binding.get("button", -1)) - var motion := event as InputEventJoypadMotion - return ( - motion != null - and str(binding.get("kind", "")) == "axis" - and motion.axis == int(binding.get("axis", -1)) - ) - - -static func default_bindings() -> Dictionary: - return { - str(ROLE_A): _button_binding(JOY_BUTTON_A), - str(ROLE_B): _button_binding(JOY_BUTTON_B), - str(ROLE_X): _button_binding(JOY_BUTTON_X), - str(ROLE_Y): _button_binding(JOY_BUTTON_Y), - str(ROLE_LB): _button_binding(JOY_BUTTON_LEFT_SHOULDER), - str(ROLE_RB): _button_binding(JOY_BUTTON_RIGHT_SHOULDER), - str(ROLE_LT): _axis_binding(JOY_AXIS_TRIGGER_RIGHT, 1.0, 0.0), - str(ROLE_RT): _axis_binding(JOY_AXIS_TRIGGER_LEFT, 1.0, 0.0), - str(ROLE_SELECT): _button_binding(JOY_BUTTON_BACK), - str(ROLE_START): _button_binding(JOY_BUTTON_START), - str(ROLE_LEFT_STICK_CLICK): _button_binding(JOY_BUTTON_LEFT_STICK), - str(ROLE_RIGHT_STICK_CLICK): _button_binding(JOY_BUTTON_RIGHT_STICK), - str(ROLE_DPAD_UP): _button_binding(JOY_BUTTON_DPAD_UP), - str(ROLE_DPAD_DOWN): _button_binding(JOY_BUTTON_DPAD_DOWN), - str(ROLE_DPAD_LEFT): _button_binding(JOY_BUTTON_DPAD_LEFT), - str(ROLE_DPAD_RIGHT): _button_binding(JOY_BUTTON_DPAD_RIGHT), - str(ROLE_LEFT_STICK_X): _axis_binding(JOY_AXIS_LEFT_X, -1.0, 0.0), - str(ROLE_LEFT_STICK_Y): _axis_binding(JOY_AXIS_LEFT_Y, -1.0, 0.0), - str(ROLE_RIGHT_STICK_X): _axis_binding(JOY_AXIS_RIGHT_X, -1.0, 0.0), - str(ROLE_RIGHT_STICK_Y): _axis_binding(JOY_AXIS_RIGHT_Y, -1.0, 0.0), - } - - -static func _button_binding(button: JoyButton) -> Dictionary: - return {"kind": "button", "button": int(button)} - - -static func _axis_binding( - axis: JoyAxis, - direction: float, - rest: float, -) -> Dictionary: - return { - "kind": "axis", - "axis": int(axis), - "direction": direction, - "rest": rest, - } - - -func _axis_binding_strength( - binding: Dictionary, - raw_override: float = INF, -) -> float: - var axis: int = int(binding.get("axis", -1)) - if axis < 0: - return 0.0 - var raw: float = ( - Input.get_joy_axis(_active_device_id, axis) - if is_inf(raw_override) else raw_override - ) - var rest: float = float(binding.get("rest", 0.0)) - var direction: float = signf(float(binding.get("direction", 0.0))) - var endpoint: float = direction - var available: float = absf(endpoint - rest) - if available <= 0.001: - return 0.0 - return clampf((raw - rest) * direction / available, 0.0, 1.0) - - -func _refresh_active_controller() -> void: - var connected: Array[int] = Input.get_connected_joypads() - _set_active_controller(connected[0] if not connected.is_empty() else 0) - - -func _set_active_controller(device_id: int) -> void: - var previous_profile_key: String = _active_profile_key - _active_device_id = maxi(device_id, 0) - var controller_is_listed: bool = Input.get_connected_joypads().has( - _active_device_id - ) - var guid: String = ( - Input.get_joy_guid(_active_device_id).strip_edges() - if controller_is_listed else "" - ) - var controller_name: String = ( - Input.get_joy_name(_active_device_id).strip_edges() - if controller_is_listed else "controller" - ) - if controller_name.is_empty(): - controller_name = "controller" - _active_controller_name = controller_name - _active_profile_key = ( - guid - if not guid.is_empty() - else "name:" + controller_name - ) - if ( - previous_profile_key == "name:controller" - and _active_profile_key != previous_profile_key - and _profiles.has(previous_profile_key) - and not _profiles.has(_active_profile_key) - ): - var previous_profile: Variant = _profiles[previous_profile_key] - if typeof(previous_profile) == TYPE_DICTIONARY: - _profiles[_active_profile_key] = ( - previous_profile as Dictionary - ).duplicate(true) - _profiles.erase(previous_profile_key) - _save_profiles() - _sample_axis_rest_values(_active_device_id) - _apply_active_profile() - active_controller_changed.emit(_active_controller_name) - - -func _sample_axis_rest_values(device_id: int) -> void: - var key: String = str(device_id) - if _axis_rest_by_device.has(key): - return - var values: Dictionary = {} - for axis: int in JOY_AXIS_MAX: - values[str(axis)] = Input.get_joy_axis(device_id, axis) - _axis_rest_by_device[key] = values - - -func _axis_rest_value(device_id: int, axis: int) -> float: - _sample_axis_rest_values(device_id) - var values: Dictionary = _axis_rest_by_device.get(str(device_id), {}) - return float(values.get(str(axis), 0.0)) - - -func _capture_project_defaults() -> void: - for action: StringName in _all_managed_actions(): - var joy_events: Array[InputEvent] = [] - for event: InputEvent in InputMap.action_get_events(action): - if event is InputEventJoypadButton or event is InputEventJoypadMotion: - joy_events.append(event.duplicate()) - _default_joy_events[action] = joy_events - - -func _all_managed_actions() -> Array[StringName]: - var result: Array[StringName] = [] - for source: Dictionary in [ - BUTTON_ACTION_ROLES, - AXIS_ACTION_ROLES, - UI_DPAD_ACTION_ROLES, - ]: - for action_value: Variant in source.keys(): - var action: StringName = StringName(action_value) - if action not in result: - result.append(action) - return result - - -func _remove_managed_joy_events() -> void: - for action: StringName in _all_managed_actions(): - if not InputMap.has_action(action): - continue - for event: InputEvent in InputMap.action_get_events(action): - if event is InputEventJoypadButton or event is InputEventJoypadMotion: - InputMap.action_erase_event(action, event) - - -func _restore_project_defaults() -> void: - _remove_managed_joy_events() - for action_value: Variant in _default_joy_events: - var action: StringName = StringName(action_value) - for event: InputEvent in _default_joy_events[action]: - InputMap.action_add_event(action, event.duplicate()) - - -func _apply_active_profile() -> void: - if not has_custom_mapping(): - _restore_project_defaults() - return - _remove_managed_joy_events() - var bindings: Dictionary = get_active_bindings() - for action_value: Variant in BUTTON_ACTION_ROLES: - var action: StringName = StringName(action_value) - _add_button_action_binding( - action, - bindings.get(str(BUTTON_ACTION_ROLES[action]), {}), - ) - for action_value: Variant in AXIS_ACTION_ROLES: - var action: StringName = StringName(action_value) - var role_data: Array = AXIS_ACTION_ROLES[action] - _add_axis_action_binding( - action, - bindings.get(str(role_data[0]), {}), - float(role_data[1]), - ) - for action_value: Variant in UI_DPAD_ACTION_ROLES: - var action: StringName = StringName(action_value) - _add_button_action_binding( - action, - bindings.get(str(UI_DPAD_ACTION_ROLES[action]), {}), - ) - - -func _add_button_action_binding(action: StringName, value: Variant) -> void: - if not InputMap.has_action(action) or typeof(value) != TYPE_DICTIONARY: - return - var binding: Dictionary = value as Dictionary - if str(binding.get("kind", "")) != "button": - return - var event := InputEventJoypadButton.new() - event.device = -1 - event.button_index = int(binding.get("button", -1)) - InputMap.action_add_event(action, event) - - -func _add_axis_action_binding( - action: StringName, - value: Variant, - logical_direction: float, -) -> void: - if not InputMap.has_action(action) or typeof(value) != TYPE_DICTIONARY: - return - var binding: Dictionary = value as Dictionary - if str(binding.get("kind", "")) != "axis": - return - var captured_negative_direction: float = signf( - float(binding.get("direction", -1.0)) - ) - var event := InputEventJoypadMotion.new() - event.device = -1 - event.axis = int(binding.get("axis", -1)) - event.axis_value = logical_direction * -captured_negative_direction - InputMap.action_add_event(action, event) - - -func _save_profiles() -> bool: - var file := FileAccess.open(PROFILE_TEMP_PATH, FileAccess.WRITE) - if file == null: - return false - file.store_string(JSON.stringify({ - "format_version": FORMAT_VERSION, - "profiles": _profiles, - }, "\t")) - file.flush() - var write_error: Error = file.get_error() - file.close() - if write_error != OK: - _remove_if_present(PROFILE_TEMP_PATH) - return false - _remove_if_present(PROFILE_BACKUP_PATH) - var had_primary: bool = FileAccess.file_exists(PROFILE_PATH) - if had_primary and not _rename_file(PROFILE_PATH, PROFILE_BACKUP_PATH): - _remove_if_present(PROFILE_TEMP_PATH) - return false - if not _rename_file(PROFILE_TEMP_PATH, PROFILE_PATH): - if had_primary: - _rename_file(PROFILE_BACKUP_PATH, PROFILE_PATH) - return false - _remove_if_present(PROFILE_BACKUP_PATH) - return true - - -func _recover_interrupted_write() -> void: - if FileAccess.file_exists(PROFILE_PATH): - _remove_if_present(PROFILE_TEMP_PATH) - _remove_if_present(PROFILE_BACKUP_PATH) - return - if FileAccess.file_exists(PROFILE_BACKUP_PATH): - _rename_file(PROFILE_BACKUP_PATH, PROFILE_PATH) - _remove_if_present(PROFILE_TEMP_PATH) - - -func _rename_file(from_path: String, to_path: String) -> bool: - return DirAccess.rename_absolute( - ProjectSettings.globalize_path(from_path), - ProjectSettings.globalize_path(to_path), - ) == OK - - -func _remove_if_present(path: String) -> void: - if FileAccess.file_exists(path): - DirAccess.remove_absolute(ProjectSettings.globalize_path(path)) diff --git a/settings/controller_mapping_manager.gd.uid b/settings/controller_mapping_manager.gd.uid deleted file mode 100644 index 3fcbc13..0000000 --- a/settings/controller_mapping_manager.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c80x8jkdnx0xy diff --git a/settings/player_settings.gd b/settings/player_settings.gd index 4a7343f..c83e534 100644 --- a/settings/player_settings.gd +++ b/settings/player_settings.gd @@ -30,7 +30,6 @@ const UI_COMPACT_RENDER_HEIGHTS: Array[int] = [0, 408, 336, 264, 192] @export var chat_draft: String = "" @export var chat_collapsed: bool = false @export var chat_dock_right: bool = false -@export var chat_mobile_mode: bool = false @export var paint_dock_right: bool = true @export_range(1, 5, 1) var world_pixel_size: int = DEFAULT_WORLD_PIXEL_SIZE @export_range(1, 5, 1) var ui_pixel_size: int = DEFAULT_UI_PIXEL_SIZE @@ -66,7 +65,6 @@ func copy() -> PlayerSettings: result.chat_draft = chat_draft result.chat_collapsed = chat_collapsed result.chat_dock_right = chat_dock_right - result.chat_mobile_mode = chat_mobile_mode result.paint_dock_right = paint_dock_right result.world_pixel_size = world_pixel_size result.ui_pixel_size = ui_pixel_size diff --git a/settings/player_settings_manager.gd b/settings/player_settings_manager.gd index 7597c82..acaf23d 100644 --- a/settings/player_settings_manager.gd +++ b/settings/player_settings_manager.gd @@ -61,10 +61,6 @@ func load_settings() -> bool: presentation.has("chat_dock_right") and typeof(presentation["chat_dock_right"]) != TYPE_BOOL ) - or ( - presentation.has("chat_mobile_mode") - and typeof(presentation["chat_mobile_mode"]) != TYPE_BOOL - ) or ( presentation.has("paint_dock_right") and typeof(presentation["paint_dock_right"]) != TYPE_BOOL @@ -111,9 +107,6 @@ func load_settings() -> bool: ) loaded.chat_collapsed = bool(presentation.get("chat_collapsed", false)) loaded.chat_dock_right = bool(presentation.get("chat_dock_right", false)) - loaded.chat_mobile_mode = bool( - presentation.get("chat_mobile_mode", false) - ) loaded.paint_dock_right = bool(presentation.get("paint_dock_right", true)) if not loaded.is_valid(): return _use_defaults_after_corruption("Player settings values are invalid.") @@ -188,7 +181,6 @@ func save_now() -> bool: "chat_draft": current_settings.chat_draft, "chat_collapsed": current_settings.chat_collapsed, "chat_dock_right": current_settings.chat_dock_right, - "chat_mobile_mode": current_settings.chat_mobile_mode, "paint_dock_right": current_settings.paint_dock_right, }, } diff --git a/tests/android_readiness_validation.gd b/tests/android_readiness_validation.gd index b383202..480fcce 100644 --- a/tests/android_readiness_validation.gd +++ b/tests/android_readiness_validation.gd @@ -1,8 +1,5 @@ extends SceneTree -const GameUIType = preload("res://ui/game_ui.gd") -const PlayerType = preload("res://player/player.gd") - func _init() -> void: assert( @@ -37,50 +34,11 @@ func _init() -> void: )) assert(_has_joypad_button(&"hotbar_previous", JOY_BUTTON_DPAD_LEFT)) assert(_has_joypad_button(&"hotbar_next", JOY_BUTTON_DPAD_RIGHT)) - assert(_has_joypad_button(&"open_backpack", JOY_BUTTON_X)) + assert(_has_joypad_button(&"open_backpack", JOY_BUTTON_BACK)) assert(_has_joypad_button(&"open_system_menu", JOY_BUTTON_START)) assert(_has_joypad_button(&"open_emotes", JOY_BUTTON_DPAD_UP)) assert(_has_joypad_button(&"open_quick_actions", JOY_BUTTON_DPAD_DOWN)) - assert(_has_joypad_button(&"open_chat", JOY_BUTTON_BACK)) - assert(_has_joypad_button(&"focus_gameplay", JOY_BUTTON_LEFT_SHOULDER)) - assert( - GameUIType.VIRTUAL_MOUSE_TRIGGER_AXIS == JOY_AXIS_TRIGGER_RIGHT - ) - assert( - GameUIType.VIRTUAL_MOUSE_SHARED_TRIGGER_AXIS - == JOY_AXIS_TRIGGER_LEFT - ) - assert( - GameUIType.VIRTUAL_MOUSE_SECONDARY_CLICK_AXIS - == JOY_AXIS_TRIGGER_LEFT - ) - assert(PlayerType.CONTROLLER_ZOOM_TRIGGER_AXIS == JOY_AXIS_TRIGGER_LEFT) - assert(is_zero_approx( - GameUIType.normalized_trigger_strength(-1.0, -1.0) - )) - assert(is_equal_approx( - GameUIType.normalized_trigger_strength(1.0, -1.0), - 1.0, - )) - assert(is_equal_approx( - GameUIType.normalized_trigger_strength(-1.0, 0.0), - 1.0, - )) - assert(is_equal_approx( - GameUIType.normalized_trigger_strength(-1.0, 1.0), - 1.0, - )) - assert(is_equal_approx( - GameUIType.directional_trigger_strength(-1.0, 0.0, -1.0), - 1.0, - )) - assert(is_zero_approx( - GameUIType.directional_trigger_strength(1.0, 0.0, -1.0) - )) - assert(is_equal_approx( - GameUIType.directional_trigger_strength(1.0, 0.0, 1.0), - 1.0, - )) + assert(_has_joypad_button(&"open_chat", JOY_BUTTON_LEFT_SHOULDER)) print("android readiness validation passed") quit() diff --git a/tests/art_tools_validation.gd b/tests/art_tools_validation.gd index 6cab7f7..ab04d4a 100644 --- a/tests/art_tools_validation.gd +++ b/tests/art_tools_validation.gd @@ -37,33 +37,17 @@ func _run() -> void: var chat_ui := game_ui.get_node("%ChatUI") as ChatUI assert(player != null and service != null and toolbar != null) assert(chat_ui != null) - assert(bool(game_ui.call("_can_start_virtual_mouse"))) - game_ui.call("_begin_virtual_mouse", 0) - var virtual_cursor := game_ui.get_node( - "%ControllerVirtualCursor" - ) as ControllerVirtualCursor - assert(virtual_cursor.visible) - assert(not player.is_camera_input_enabled()) - game_ui.call("_end_virtual_mouse") - assert(not virtual_cursor.visible) - assert(player.is_camera_input_enabled()) var settings_panel := game_ui.get( "_pause_settings_panel" ) as SettingsPanel var chat_dock_button := settings_panel.get_node("%ChatDock") as BubbleButton - var chat_mode_button := settings_panel.get_node("%ChatMode") as BubbleButton var paint_dock_button := settings_panel.get_node("%PaintDock") as BubbleButton assert(chat_dock_button.neutral_size.x == chat_dock_button.neutral_size.y) - assert(chat_mode_button.neutral_size.x == chat_mode_button.neutral_size.y) assert(paint_dock_button.neutral_size.x == paint_dock_button.neutral_size.y) assert( chat_dock_button.compact_minimum_size.x == chat_dock_button.compact_minimum_size.y ) - assert( - chat_mode_button.compact_minimum_size.x - == chat_mode_button.compact_minimum_size.y - ) assert( paint_dock_button.compact_minimum_size.x == paint_dock_button.compact_minimum_size.y @@ -76,85 +60,24 @@ func _run() -> void: assert(settings_manager != null) var changed_docks: PlayerSettings = settings_manager.current_settings.copy() changed_docks.chat_dock_right = true - changed_docks.chat_mobile_mode = true changed_docks.paint_dock_right = false assert(settings_manager.apply_settings(changed_docks)) await process_frame assert(chat_ui.is_docked_right()) - assert(chat_ui.is_mobile_mode()) assert(not toolbar.is_docked_right()) - var chat_panel := chat_ui.get_node("ChatPanel") as PanelContainer - var chat_height_button := chat_ui.get_node("ChatHeightButton") as Button - assert(is_zero_approx(chat_panel.position.y)) - assert(is_equal_approx(chat_panel.size.x, ChatUI.MOBILE_COMPACT_WIDTH)) - assert(not chat_height_button.visible) var reloaded_settings := PlayerSettingsManager.new() root.add_child(reloaded_settings) assert(reloaded_settings.load_settings()) assert(reloaded_settings.current_settings.chat_dock_right) - assert(reloaded_settings.current_settings.chat_mobile_mode) assert(not reloaded_settings.current_settings.paint_dock_right) reloaded_settings.queue_free() var default_docks: PlayerSettings = settings_manager.current_settings.copy() default_docks.chat_dock_right = false - default_docks.chat_mobile_mode = false default_docks.paint_dock_right = true assert(settings_manager.apply_settings(default_docks)) await process_frame assert(not chat_ui.is_docked_right()) - assert(not chat_ui.is_mobile_mode()) assert(toolbar.is_docked_right()) - assert(chat_height_button.visible) - var select_button := InputEventJoypadButton.new() - select_button.button_index = JOY_BUTTON_BACK - select_button.pressed = true - assert(bool(game_ui.call("_handle_controller_chat_controls", select_button))) - assert(chat_ui.is_open()) - assert(chat_panel.mouse_filter == Control.MOUSE_FILTER_STOP) - var typed_chat_entry := chat_ui.find_child( - "ChatEntry", true, false - ) as LineEdit - assert(typed_chat_entry != null) - assert(not typed_chat_entry.virtual_keyboard_enabled) - var accept_button := InputEventJoypadButton.new() - accept_button.button_index = JOY_BUTTON_A - accept_button.pressed = true - assert(bool(game_ui.call("_handle_controller_chat_controls", accept_button))) - assert(typed_chat_entry.virtual_keyboard_enabled) - var left_bumper := InputEventJoypadButton.new() - left_bumper.button_index = JOY_BUTTON_LEFT_SHOULDER - left_bumper.pressed = true - assert(bool(game_ui.call("_handle_controller_chat_controls", left_bumper))) - assert(not chat_ui.is_open()) - assert(chat_panel.mouse_filter == Control.MOUSE_FILTER_IGNORE) - assert(not typed_chat_entry.virtual_keyboard_enabled) - assert(bool(game_ui.call("_handle_controller_chat_controls", left_bumper))) - assert(chat_ui.is_open()) - assert(not typed_chat_entry.virtual_keyboard_enabled) - assert(bool(game_ui.call("_handle_controller_chat_controls", left_bumper))) - assert(not chat_ui.is_open()) - assert(bool(game_ui.call("_handle_controller_chat_controls", select_button))) - assert(not chat_ui.is_open()) - assert(chat_ui.is_collapsed()) - assert(bool(game_ui.call("_handle_controller_chat_controls", select_button))) - assert(chat_ui.is_open()) - chat_ui.refocus_gameplay() - var cancel_button := InputEventJoypadButton.new() - cancel_button.button_index = JOY_BUTTON_B - cancel_button.pressed = true - assert(not bool(main.call("_is_pause_open_request", cancel_button))) - var start_button := InputEventJoypadButton.new() - start_button.button_index = JOY_BUTTON_START - start_button.pressed = true - assert(bool(main.call("_is_pause_open_request", start_button))) - var player_menu := game_ui.get_node("%PlayerMenu") as PlayerMenu - player_menu.open_section(PlayerMenu.Section.PROFILE) - for _frame: int in 12: - await process_frame - assert(root.gui_get_focus_owner() is not LineEdit) - player_menu.close_menu() - for _frame: int in 12: - await process_frame assert(not service.can_activate()) assert(not service.is_active() and not toolbar.visible) assert(player.bag.add_item(ArtShopStock.ART_KIT_ITEM_ID, 1)) diff --git a/tests/controller_mapping_validation.gd b/tests/controller_mapping_validation.gd deleted file mode 100644 index 280c2c7..0000000 --- a/tests/controller_mapping_validation.gd +++ /dev/null @@ -1,157 +0,0 @@ -extends SceneTree - -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) -const ControllerMappingPanelType = preload( - "res://ui/controller_mapping_panel.gd" -) -const GameUIType = preload("res://ui/game_ui.gd") - - -func _init() -> void: - call_deferred("_run") - - -func _run() -> void: - var manager := ControllerMappingManagerType.new() - root.add_child(manager) - await process_frame - var failure: String = _validate_manager(manager) - if failure.is_empty(): - failure = _validate_auto_map(manager) - if failure.is_empty(): - failure = _validate_virtual_mouse_bounds() - if failure.is_empty(): - print("controller mapping validation passed") - quit(0) - return - push_error(failure) - quit(1) - - -func _validate_manager(manager: ControllerMappingManagerType) -> String: - var defaults: Dictionary = manager.get_active_bindings() - if defaults.size() != ControllerMappingManagerType.ROLE_ORDER.size(): - return "default mapping covers %d of %d controller roles: %s" % [ - defaults.size(), - ControllerMappingManagerType.ROLE_ORDER.size(), - str(defaults.keys()), - ] - var trigger_button := InputEventJoypadButton.new() - trigger_button.button_index = JOY_BUTTON_MISC1 - trigger_button.pressed = true - var trigger_binding: Dictionary = manager.binding_from_event( - ControllerMappingManagerType.ROLE_LT, - trigger_button, - ) - if str(trigger_binding.get("kind", "")) != "button": - return "trigger role did not accept a button-backed handheld trigger" - var trigger_motion := InputEventJoypadMotion.new() - trigger_motion.axis = JOY_AXIS_TRIGGER_RIGHT - trigger_motion.axis_value = 1.0 - trigger_binding = manager.binding_from_event( - ControllerMappingManagerType.ROLE_LT, - trigger_motion, - ) - if str(trigger_binding.get("kind", "")) != "axis": - return "trigger role did not accept an axis-backed controller trigger" - var stick_button := manager.binding_from_event( - ControllerMappingManagerType.ROLE_RIGHT_STICK_X, - trigger_button, - ) - if not stick_button.is_empty(): - return "stick axis role accepted a button" - var keyboard_events_before: int = _keyboard_event_count(&"jump") - var custom: Dictionary = defaults.duplicate(true) - custom[str(ControllerMappingManagerType.ROLE_A)] = { - "kind": "button", - "button": int(JOY_BUTTON_X), - } - custom[str(ControllerMappingManagerType.ROLE_LT)] = trigger_binding - if not manager.replace_active_bindings(custom): - return "valid custom mapping could not be saved" - if not manager.has_custom_mapping(): - return "saved custom mapping did not become active" - if _keyboard_event_count(&"jump") != keyboard_events_before: - return "controller remapping changed keyboard bindings" - if not FileAccess.file_exists( - ControllerMappingManagerType.PROFILE_PATH - ): - return "controller mapping was not stored device-locally" - return "" - - -func _validate_auto_map(manager: ControllerMappingManagerType) -> String: - var panel := ControllerMappingPanelType.new() - root.add_child(panel) - panel.setup(manager) - panel.open_panel() - panel._begin_auto_map() - for role: StringName in ControllerMappingManagerType.ROLE_ORDER: - var binding := ( - ControllerMappingManagerType.default_bindings()[str(role)] - as Dictionary - ) - if role == ControllerMappingManagerType.ROLE_B: - binding = ( - ControllerMappingManagerType.default_bindings()[ - str(ControllerMappingManagerType.ROLE_A) - ] as Dictionary - ) - if str(binding.get("kind", "")) == "button": - var button := InputEventJoypadButton.new() - button.button_index = int(binding.get("button", -1)) - button.pressed = true - panel._input(button) - else: - var motion := InputEventJoypadMotion.new() - motion.axis = int(binding.get("axis", -1)) - motion.axis_value = float(binding.get("direction", -1.0)) - panel._input(motion) - if panel._auto_map_active: - return "auto-map did not complete after every requested input" - if not manager.has_custom_mapping(): - return "completed auto-map did not activate its profile" - if panel._binding_buttons.size() != ( - ControllerMappingManagerType.ROLE_ORDER.size() - ): - return "manual override list does not expose every mapped role" - var conflict_button := panel._binding_buttons.get( - ControllerMappingManagerType.ROLE_A - ) as Button - var conflict_style := conflict_button.get_theme_stylebox( - &"normal" - ) as StyleBoxFlat - if ( - conflict_style == null - or conflict_style.bg_color - != UtilityPageStyle.OCEAN_DANGER - ): - return "duplicate controller bindings were not marked in red" - panel._begin_manual_capture(ControllerMappingManagerType.ROLE_LT) - if "left trigger" in panel._progress_label.text.to_lower(): - return "manual remapping still dictates a specific physical input" - if "any button" not in panel._progress_label.text.to_lower(): - return "manual remapping does not request a generic controller input" - panel._cancel_capture() - return "" - - -func _validate_virtual_mouse_bounds() -> String: - var window_size := Vector2(3840.0, 2160.0) - var bounds: Rect2 = GameUIType.get_virtual_mouse_window_bounds(window_size) - var expected_margin := Vector2(42.0, 42.0) - if not bounds.position.is_equal_approx(expected_margin): - return "4K virtual cursor minimum bounds are incorrect: %s" % bounds - if not bounds.end.is_equal_approx(window_size - expected_margin): - return "4K virtual cursor maximum bounds are incorrect: %s" % bounds - return "" - - -func _keyboard_event_count(action: StringName) -> int: - var count: int = 0 - for event: InputEvent in InputMap.action_get_events(action): - if event is InputEventKey or event is InputEventMouseButton: - count += 1 - return count diff --git a/tests/controller_mapping_validation.gd.uid b/tests/controller_mapping_validation.gd.uid deleted file mode 100644 index 7840fe3..0000000 --- a/tests/controller_mapping_validation.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dhwkjojmpjc13 diff --git a/ui/chat_ui.gd b/ui/chat_ui.gd index 0d61506..58b7c81 100644 --- a/ui/chat_ui.gd +++ b/ui/chat_ui.gd @@ -20,11 +20,6 @@ const HANDLE_SIZE := Vector2(34, 42) const HANDLE_GAP: float = 6.0 const COLLAPSED_REVEAL_WIDTH: float = 8.0 const HINT_EDGE_MARGIN: float = 4.0 -const MOBILE_COMPACT_WIDTH: float = 620.0 -const MOBILE_EXPANDED_WIDTH: float = 820.0 -const MOBILE_COMPACT_HEIGHT: float = 220.0 -const MOBILE_EXPANDED_HEIGHT: float = 390.0 -const MOBILE_EDGE_MARGIN: float = 12.0 const CLOCK_SIZE := Vector2(116.0, 34.0) const CLOCK_EDGE_MARGIN: float = 10.0 const WEATHER_ICON_SIZE := Vector2(34.0, 34.0) @@ -77,10 +72,8 @@ var _send_pending: bool = false var _pending_send_body: String = "" var _prior_movement: bool = true var _prior_camera: bool = true -var _controller_refocused: bool = false var _output_scale: float = 1.0 var _dock_right: bool = false -var _mobile_mode: bool = false var _world_time: WorldTimeServiceType var _world_weather: WorldWeatherServiceType @@ -132,7 +125,6 @@ func setup( _world_weather.get_weather(), _world_weather.get_seconds_remaining(), ) - set_mobile_mode(_settings.current_settings.chat_mobile_mode) set_dock_right(_settings.current_settings.chat_dock_right) _service.message_received.connect(_on_message) _service.local_message_confirmed.connect(_on_local_message_confirmed) @@ -159,7 +151,6 @@ func open_chat() -> void: return if _presentation_state == PresentationState.COLLAPSED: _set_presentation_state(_visible_state_before_collapse, true, true) - _controller_refocused = false _opened = true text_entry_ownership_changed.emit(true) _prior_movement = _player.is_movement_enabled() @@ -171,10 +162,8 @@ func open_chat() -> void: # prediction would let a remote host continue the last held movement. _session.submit_neutral_local_movement() _entry.show() - _entry.virtual_keyboard_enabled = false _entry.grab_focus() _hint.hide() - _refresh_input_ownership() _update_panel_opacity(true) Input.mouse_mode = Input.MOUSE_MODE_VISIBLE @@ -195,7 +184,6 @@ func close_chat() -> void: return _opened = false text_entry_ownership_changed.emit(false) - _entry.virtual_keyboard_enabled = false _entry.release_focus() _entry.hide() _player.set_movement_enabled(_prior_movement) @@ -203,62 +191,14 @@ func close_chat() -> void: _fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, false) _flush_draft() _refresh_visibility() - _refresh_input_ownership() - - -func toggle_chat() -> void: - if _presentation_state == PresentationState.COLLAPSED: - open_chat() - return - if _opened: - close_chat() - _set_presentation_state(PresentationState.COLLAPSED, true, true) - return - if _controller_refocused: - _controller_refocused = false - _set_presentation_state(PresentationState.COLLAPSED, true, true) - return - open_chat() - - -func refocus_gameplay() -> void: - close_chat() - _controller_refocused = true - get_viewport().gui_release_focus() - - -func toggle_focus() -> void: - if _presentation_state == PresentationState.COLLAPSED: - return - if _opened: - refocus_gameplay() - else: - open_chat() - - -func request_virtual_keyboard() -> bool: - if not _opened or not _entry.has_focus(): - return false - _entry.virtual_keyboard_enabled = true - # Re-entering focus after the controller accept event is the explicit - # request Android uses to display its keyboard. Merely focusing Chat keeps - # the keyboard disabled so the world remains readable. - _entry.release_focus() - _entry.call_deferred("grab_focus") - return true - - -func is_open() -> bool: - return _opened - - -func is_collapsed() -> bool: - return _presentation_state == PresentationState.COLLAPSED func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("open_chat"): - toggle_chat() + if _opened: + close_chat() + elif _available: + open_chat() get_viewport().set_input_as_handled() return if event is InputEventKey and event.pressed and not event.echo: @@ -464,21 +404,14 @@ func _build_ui() -> void: _unread_indicator.hide() _hint.hide() _layout_presentation(false) - _refresh_input_ownership() func _chat_panel_style() -> StyleBoxFlat: var style := _borderless_style(Color(0.025, 0.13, 0.19, 0.94)) - if _mobile_mode: - style.corner_radius_top_left = 0 - style.corner_radius_top_right = 0 - style.corner_radius_bottom_left = 10 - style.corner_radius_bottom_right = 10 - else: - style.corner_radius_top_left = 10 if _dock_right else 0 - style.corner_radius_bottom_left = 10 if _dock_right else 0 - style.corner_radius_top_right = 0 if _dock_right else 10 - style.corner_radius_bottom_right = 0 if _dock_right else 10 + style.corner_radius_top_left = 10 if _dock_right else 0 + style.corner_radius_bottom_left = 10 if _dock_right else 0 + style.corner_radius_top_right = 0 if _dock_right else 10 + style.corner_radius_bottom_right = 0 if _dock_right else 10 style.content_margin_left = 12 style.content_margin_right = 12 style.content_margin_top = 10 @@ -486,18 +419,6 @@ func _chat_panel_style() -> StyleBoxFlat: return style -func _refresh_input_ownership() -> void: - if _panel == null or _history == null: - return - var filter: Control.MouseFilter = ( - Control.MOUSE_FILTER_STOP - if _opened - else Control.MOUSE_FILTER_IGNORE - ) - _panel.mouse_filter = filter - _history.mouse_filter = filter - - func _clock_panel_style() -> StyleBoxFlat: var style := _borderless_style(Color(0.025, 0.13, 0.19, 0.94)) style.set_corner_radius_all(12) @@ -699,10 +620,7 @@ func _refresh_visibility() -> void: _collapse_button.show() var collapsed := _presentation_state == PresentationState.COLLAPSED _panel.show() - _height_button.visible = not _mobile_mode - _height_button.focus_mode = ( - Control.FOCUS_NONE if _mobile_mode else Control.FOCUS_ALL - ) + _height_button.show() _unread_indicator.visible = collapsed and _collapsed_has_unread _hint.visible = not _opened @@ -752,31 +670,10 @@ func is_docked_right() -> bool: return _dock_right -func set_mobile_mode(enabled: bool) -> void: - _mobile_mode = enabled - if not is_node_ready() or _panel == null: - return - if _mobile_mode: - if _presentation_state == PresentationState.EXPANDED: - _presentation_state = PresentationState.COMPACT - if _visible_state_before_collapse == PresentationState.EXPANDED: - _visible_state_before_collapse = PresentationState.COMPACT - _panel.add_theme_stylebox_override("panel", _chat_panel_style()) - _refresh_handle_labels(_presentation_state) - _refresh_visibility() - _layout_presentation(false) - - -func is_mobile_mode() -> bool: - return _mobile_mode - - func _refresh_handle_labels(state: PresentationState) -> void: var collapsed := state == PresentationState.COLLAPSED var height_state := _visible_state_before_collapse if collapsed else state - if _mobile_mode: - _collapse_button.text = "v" if collapsed else "^" - elif _dock_right: + if _dock_right: _collapse_button.text = "<" if collapsed else ">" else: _collapse_button.text = ">" if collapsed else "<" @@ -901,101 +798,32 @@ func _layout_presentation(animate: bool) -> void: var viewport_height := size.y if viewport_height <= 0.0: viewport_height = 720.0 - var layout_state := ( - _visible_state_before_collapse - if _presentation_state == PresentationState.COLLAPSED - else _presentation_state - ) - var collapsed := _presentation_state == PresentationState.COLLAPSED var bottom_margin := minf( BOTTOM_MARGIN, maxf(MIN_TOP_MARGIN, (viewport_height - MIN_HISTORY_HEIGHT) * 0.25), ) var bottom := viewport_height - bottom_margin var height := COMPACT_HEIGHT - var panel_width := PANEL_WIDTH - var panel_x: float = 0.0 - var panel_y: float = 0.0 - var collapse_position := Vector2.ZERO - var height_position := Vector2.ZERO - var unread_position := Vector2.ZERO - if _mobile_mode: - panel_width = ( - MOBILE_EXPANDED_WIDTH - if layout_state == PresentationState.EXPANDED - else MOBILE_COMPACT_WIDTH + var layout_state := ( + _visible_state_before_collapse + if _presentation_state == PresentationState.COLLAPSED + else _presentation_state + ) + if layout_state == PresentationState.EXPANDED: + height = maxf(MIN_HISTORY_HEIGHT, viewport_height - 2.0 * bottom_margin) + height = minf(height, maxf(MIN_HISTORY_HEIGHT, bottom - MIN_TOP_MARGIN)) + var collapsed := _presentation_state == PresentationState.COLLAPSED + var panel_x: float + if _dock_right: + panel_x = ( + viewport_width - COLLAPSED_REVEAL_WIDTH + if collapsed + else viewport_width - PANEL_WIDTH ) - panel_width = minf( - panel_width, - maxf(1.0, viewport_width - MOBILE_EDGE_MARGIN * 2.0), - ) - height = ( - MOBILE_EXPANDED_HEIGHT - if layout_state == PresentationState.EXPANDED - else MOBILE_COMPACT_HEIGHT - ) - height = minf( - height, - maxf(MIN_HISTORY_HEIGHT, viewport_height - HANDLE_SIZE.y), - ) - panel_x = (viewport_width - panel_width) * 0.5 - panel_y = -(height - COLLAPSED_REVEAL_WIDTH) if collapsed else 0.0 - var mobile_handle_y: float = ( - COLLAPSED_REVEAL_WIDTH if collapsed else height - ) - collapse_position = Vector2( - panel_x + panel_width - HANDLE_SIZE.x, - mobile_handle_y, - ) - height_position = Vector2( - collapse_position.x - HANDLE_SIZE.x - HANDLE_GAP, - mobile_handle_y, - ) - unread_position = collapse_position + Vector2(6.0, -18.0) else: - if layout_state == PresentationState.EXPANDED: - height = maxf( - MIN_HISTORY_HEIGHT, - viewport_height - 2.0 * bottom_margin, - ) - height = minf( - height, - maxf(MIN_HISTORY_HEIGHT, bottom - MIN_TOP_MARGIN), - ) - if _dock_right: - panel_x = ( - viewport_width - COLLAPSED_REVEAL_WIDTH - if collapsed - else viewport_width - PANEL_WIDTH - ) - else: - panel_x = ( - -(PANEL_WIDTH - COLLAPSED_REVEAL_WIDTH) - if collapsed - else 0.0 - ) - panel_y = bottom - height - var handle_stack_height := HANDLE_SIZE.y * 2.0 + HANDLE_GAP - var handle_stack_top := ( - bottom - COMPACT_HEIGHT * 0.5 - handle_stack_height * 0.5 - ) - var handle_x: float = ( - panel_x - HANDLE_SIZE.x - if _dock_right - else COLLAPSED_REVEAL_WIDTH if collapsed else PANEL_WIDTH - ) - collapse_position = Vector2( - handle_x, - handle_stack_top + HANDLE_SIZE.y + HANDLE_GAP, - ) - height_position = Vector2(handle_x, handle_stack_top) - var unread_offset_x := -18.0 if _dock_right else 6.0 - unread_position = collapse_position + Vector2( - unread_offset_x, - -18.0, - ) - var target_position := Vector2(panel_x, panel_y) - var target_size := Vector2(panel_width, height) + panel_x = -(PANEL_WIDTH - COLLAPSED_REVEAL_WIDTH) if collapsed else 0.0 + var target_position := Vector2(panel_x, bottom - height) + var target_size := Vector2(PANEL_WIDTH, height) var clock_x: float = ( viewport_width - CLOCK_SIZE.x - CLOCK_EDGE_MARGIN if _dock_right else CLOCK_EDGE_MARGIN @@ -1012,6 +840,22 @@ func _layout_presentation(animate: bool) -> void: var weather_icon_position := Vector2( weather_icon_x, clock_position.y ) + var handle_stack_height := HANDLE_SIZE.y * 2.0 + HANDLE_GAP + var handle_stack_top := ( + bottom - COMPACT_HEIGHT * 0.5 - handle_stack_height * 0.5 + ) + var handle_x: float + if _dock_right: + handle_x = panel_x - HANDLE_SIZE.x + else: + handle_x = COLLAPSED_REVEAL_WIDTH if collapsed else PANEL_WIDTH + var collapse_position := Vector2( + handle_x, + handle_stack_top + HANDLE_SIZE.y + HANDLE_GAP, + ) + var height_position := Vector2(handle_x, handle_stack_top) + var unread_offset_x := -18.0 if _dock_right else 6.0 + var unread_position := collapse_position + Vector2(unread_offset_x, -18.0) var hint_position := Vector2( ( viewport_width - _hint.size.x - HINT_EDGE_MARGIN diff --git a/ui/controller_mapping_panel.gd b/ui/controller_mapping_panel.gd deleted file mode 100644 index 538a4aa..0000000 --- a/ui/controller_mapping_panel.gd +++ /dev/null @@ -1,450 +0,0 @@ -class_name ControllerMappingPanel -extends Control - -signal closed - -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) -const UtilityPageStyleType = preload("res://ui/utility_page_style.gd") - -var _mapping_manager: ControllerMappingManagerType -var _binding_buttons: Dictionary = {} -var _controller_label: Label -var _instruction_label: Label -var _progress_label: Label -var _auto_map_button: Button -var _reset_button: Button -var _close_button: Button -var _capturing_role: StringName = &"" -var _auto_map_active: bool = false -var _auto_map_index: int = -1 -var _auto_map_draft: Dictionary = {} - - -func _ready() -> void: - set_process_input(true) - _build_interface() - hide() - - -func setup(mapping_manager: ControllerMappingManagerType) -> void: - _mapping_manager = mapping_manager - if not _mapping_manager.active_controller_changed.is_connected( - _on_active_controller_changed - ): - _mapping_manager.active_controller_changed.connect( - _on_active_controller_changed - ) - if not _mapping_manager.active_profile_changed.is_connected( - _refresh_bindings - ): - _mapping_manager.active_profile_changed.connect(_refresh_bindings) - _refresh_bindings() - - -func open_panel() -> void: - if _mapping_manager == null: - return - _cancel_capture() - show() - _refresh_bindings() - _auto_map_button.grab_focus() - - -func is_open() -> bool: - return visible - - -func is_capturing() -> bool: - return visible and not _capturing_role.is_empty() - - -func request_back() -> void: - if not visible: - return - if not _capturing_role.is_empty(): - _cancel_capture() - return - close_panel() - - -func close_panel() -> void: - _cancel_capture() - hide() - closed.emit() - - -func _input(event: InputEvent) -> void: - if not visible or _mapping_manager == null: - return - if _capturing_role.is_empty(): - return - var key_event := event as InputEventKey - if ( - key_event != null - and key_event.pressed - and not key_event.echo - and key_event.keycode == KEY_ESCAPE - ): - get_viewport().set_input_as_handled() - _cancel_capture() - _progress_label.text = "controller mapping cancelled" - return - if not ( - event is InputEventJoypadButton - or event is InputEventJoypadMotion - ): - return - var binding: Dictionary = _mapping_manager.binding_from_event( - _capturing_role, - event, - ) - if binding.is_empty(): - return - if not _mapping_manager.validate_binding(_capturing_role, binding): - return - get_viewport().set_input_as_handled() - _accept_captured_binding(binding) - - -func _build_interface() -> void: - set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) - mouse_filter = Control.MOUSE_FILTER_STOP - z_index = 100 - UtilityPageStyleType.apply_page(self) - - var frame := PanelContainer.new() - frame.set_anchors_preset(Control.PRESET_FULL_RECT) - frame.offset_left = 18.0 - frame.offset_top = 18.0 - frame.offset_right = -18.0 - frame.offset_bottom = -18.0 - frame.add_theme_stylebox_override( - "panel", - UtilityPageStyleType.rounded_style( - UtilityPageStyleType.OCEAN_PANEL_DEEP, - 20, - ), - ) - add_child(frame) - - var outer_margin := MarginContainer.new() - outer_margin.add_theme_constant_override("margin_left", 24) - outer_margin.add_theme_constant_override("margin_top", 20) - outer_margin.add_theme_constant_override("margin_right", 24) - outer_margin.add_theme_constant_override("margin_bottom", 20) - frame.add_child(outer_margin) - - var page := VBoxContainer.new() - page.add_theme_constant_override("separation", 12) - outer_margin.add_child(page) - - var heading_row := HBoxContainer.new() - heading_row.add_theme_constant_override("separation", 12) - page.add_child(heading_row) - - var title := Label.new() - title.text = "controller mapping" - title.add_theme_font_size_override("font_size", 28) - title.add_theme_color_override( - "font_color", UtilityPageStyleType.OCEAN_TEXT_PRIMARY - ) - title.size_flags_horizontal = Control.SIZE_EXPAND_FILL - heading_row.add_child(title) - - _controller_label = Label.new() - _controller_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT - _controller_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER - _controller_label.add_theme_font_size_override("font_size", 15) - _controller_label.add_theme_color_override( - "font_color", UtilityPageStyleType.OCEAN_TEXT_SECONDARY - ) - heading_row.add_child(_controller_label) - - _instruction_label = Label.new() - _instruction_label.text = ( - "auto-map walks through a standard xbox-style controller. " - + "select any row afterward to override it." - ) - _instruction_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART - _instruction_label.add_theme_font_size_override("font_size", 15) - _instruction_label.add_theme_color_override( - "font_color", UtilityPageStyleType.OCEAN_TEXT_SECONDARY - ) - page.add_child(_instruction_label) - - _progress_label = Label.new() - _progress_label.custom_minimum_size.y = 34.0 - _progress_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER - _progress_label.add_theme_font_size_override("font_size", 18) - _progress_label.add_theme_color_override( - "font_color", UtilityPageStyleType.OCEAN_TEXT_PRIMARY - ) - page.add_child(_progress_label) - - var scroll := ScrollContainer.new() - scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL - scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED - page.add_child(scroll) - - var role_grid := GridContainer.new() - role_grid.columns = 2 - role_grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL - role_grid.add_theme_constant_override("h_separation", 12) - role_grid.add_theme_constant_override("v_separation", 7) - scroll.add_child(role_grid) - - for role: StringName in ControllerMappingManagerType.ROLE_ORDER: - var role_label := Label.new() - role_label.text = ControllerMappingManagerType.ROLE_LABELS.get( - role, - str(role), - ) - role_label.custom_minimum_size = Vector2(330.0, 42.0) - role_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER - role_label.add_theme_font_size_override("font_size", 16) - role_label.add_theme_color_override( - "font_color", UtilityPageStyleType.OCEAN_TEXT_PRIMARY - ) - role_grid.add_child(role_label) - - var binding_button := Button.new() - binding_button.custom_minimum_size = Vector2(210.0, 42.0) - binding_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL - binding_button.focus_mode = Control.FOCUS_ALL - binding_button.tooltip_text = ( - "change " + str(ControllerMappingManagerType.ROLE_LABELS.get( - role, - str(role), - )) - ) - UtilityPageStyleType.apply_compact_ocean_button(binding_button) - binding_button.pressed.connect(_begin_manual_capture.bind(role)) - role_grid.add_child(binding_button) - _binding_buttons[role] = binding_button - - var footer := HBoxContainer.new() - footer.alignment = BoxContainer.ALIGNMENT_END - footer.add_theme_constant_override("separation", 10) - page.add_child(footer) - - _auto_map_button = Button.new() - _auto_map_button.text = "auto-map controller" - _auto_map_button.tooltip_text = ( - "walk through every input on a standard xbox-style controller" - ) - UtilityPageStyleType.apply_ocean_button(_auto_map_button) - _auto_map_button.pressed.connect(_begin_auto_map) - footer.add_child(_auto_map_button) - - _reset_button = Button.new() - _reset_button.text = "restore defaults" - _reset_button.tooltip_text = "remove this controller's custom mapping" - UtilityPageStyleType.apply_ocean_button(_reset_button) - _reset_button.pressed.connect(_reset_mapping) - footer.add_child(_reset_button) - - _close_button = Button.new() - _close_button.text = "done" - UtilityPageStyleType.apply_ocean_button(_close_button) - _close_button.pressed.connect(close_panel) - footer.add_child(_close_button) - - -func _begin_auto_map() -> void: - if _mapping_manager == null: - return - _auto_map_active = true - _auto_map_index = 0 - _auto_map_draft = {} - _set_capture_role(ControllerMappingManagerType.ROLE_ORDER[_auto_map_index]) - - -func _begin_manual_capture(role: StringName) -> void: - _auto_map_active = false - _auto_map_index = -1 - _auto_map_draft.clear() - _set_capture_role(role) - - -func _set_capture_role(role: StringName) -> void: - _capturing_role = role - _set_action_buttons_disabled(true) - if _auto_map_active: - _progress_label.text = "step %d of %d: %s" % [ - _auto_map_index + 1, - ControllerMappingManagerType.ROLE_ORDER.size(), - _mapping_manager.get_role_prompt(role), - ] - return - var input_instruction: String = "press any controller button" - if _mapping_manager.role_expects_axis(role): - input_instruction = "move any controller axis" - elif _mapping_manager.role_accepts_axis(role): - input_instruction = "press any button or move any controller axis" - _progress_label.text = "%s for %s" % [ - input_instruction, - _mapping_manager.get_role_label(role), - ] - - -func _accept_captured_binding(binding: Dictionary) -> void: - if _auto_map_active: - _auto_map_draft[str(_capturing_role)] = binding.duplicate(true) - _auto_map_index += 1 - if _auto_map_index < ControllerMappingManagerType.ROLE_ORDER.size(): - _set_capture_role( - ControllerMappingManagerType.ROLE_ORDER[_auto_map_index] - ) - return - var saved: bool = _mapping_manager.replace_active_bindings( - _auto_map_draft - ) - _cancel_capture() - _progress_label.text = ( - "controller mapped successfully" - if saved else "could not save the controller mapping" - ) - _refresh_bindings() - return - var role: StringName = _capturing_role - var saved: bool = _mapping_manager.set_binding(role, binding) - _cancel_capture() - _progress_label.text = ( - "updated " + _mapping_manager.get_role_label(role) - if saved else "could not save that controller input" - ) - _refresh_bindings() - -func _cancel_capture() -> void: - _capturing_role = &"" - _auto_map_active = false - _auto_map_index = -1 - _auto_map_draft.clear() - _set_action_buttons_disabled(false) - if _progress_label != null: - _progress_label.text = "" - - -func _set_action_buttons_disabled(disabled: bool) -> void: - if _auto_map_button != null: - _auto_map_button.disabled = disabled - if _reset_button != null: - _reset_button.disabled = disabled - for button_value: Variant in _binding_buttons.values(): - var button := button_value as Button - if button != null: - button.disabled = disabled - - -func _reset_mapping() -> void: - if _mapping_manager == null: - return - var reset: bool = _mapping_manager.reset_active_profile() - _progress_label.text = ( - "restored the project controller defaults" - if reset else "could not restore controller defaults" - ) - _refresh_bindings() - - -func _refresh_bindings() -> void: - if _mapping_manager == null or _controller_label == null: - return - _controller_label.text = _mapping_manager.get_active_controller_name() - var bindings: Dictionary = _mapping_manager.get_active_bindings() - for role: StringName in ControllerMappingManagerType.ROLE_ORDER: - var button := _binding_buttons.get(role) as Button - if button == null: - continue - var raw_binding: Variant = bindings.get(str(role), {}) - button.text = ( - _mapping_manager.binding_label(raw_binding as Dictionary) - if typeof(raw_binding) == TYPE_DICTIONARY else "unmapped" - ) - var conflict_role: StringName = _find_binding_conflict( - role, - raw_binding as Dictionary, - bindings, - ) - _apply_binding_button_style(button, not conflict_role.is_empty()) - button.tooltip_text = ( - "warning: also assigned to " - + _mapping_manager.get_role_label(conflict_role) - if not conflict_role.is_empty() - else "change " + _mapping_manager.get_role_label(role) - ) - _reset_button.disabled = not _mapping_manager.has_custom_mapping() - - -func _find_binding_conflict( - role: StringName, - binding: Dictionary, - bindings: Dictionary, -) -> StringName: - if binding.is_empty(): - return &"" - for other_role: StringName in ControllerMappingManagerType.ROLE_ORDER: - if other_role == role: - continue - var raw_other: Variant = bindings.get(str(other_role), {}) - if typeof(raw_other) != TYPE_DICTIONARY: - continue - var other := raw_other as Dictionary - if _bindings_conflict(role, binding, other_role, other): - return other_role - return &"" - - -func _bindings_conflict( - first_role: StringName, - first: Dictionary, - second_role: StringName, - second: Dictionary, -) -> bool: - var binding_kind: String = str(first.get("kind", "")) - if binding_kind != str(second.get("kind", "")): - return false - if binding_kind == "button": - return int(first.get("button", -1)) == int( - second.get("button", -1) - ) - if binding_kind != "axis": - return false - if int(first.get("axis", -1)) != int(second.get("axis", -1)): - return false - var opposite_trigger_halves: bool = ( - first_role in ControllerMappingManagerType.TRIGGER_ROLES - and second_role in ControllerMappingManagerType.TRIGGER_ROLES - and signf(float(first.get("direction", 0.0))) - != signf(float(second.get("direction", 0.0))) - ) - return not opposite_trigger_halves - - -func _apply_binding_button_style(button: Button, has_conflict: bool) -> void: - UtilityPageStyleType.apply_compact_ocean_button(button) - if not has_conflict: - return - var colors: Dictionary = { - &"normal": UtilityPageStyleType.OCEAN_DANGER, - &"hover": UtilityPageStyleType.OCEAN_DANGER.lightened(0.12), - &"pressed": UtilityPageStyleType.OCEAN_DANGER.darkened(0.12), - &"focus": UtilityPageStyleType.OCEAN_DANGER.lightened(0.12), - } - for state: StringName in colors: - var style := UtilityPageStyleType.ocean_button_style( - colors[state] as Color - ) - style.content_margin_left = 10.0 - style.content_margin_right = 10.0 - style.content_margin_top = 4.0 - style.content_margin_bottom = 4.0 - button.add_theme_stylebox_override(state, style) - - -func _on_active_controller_changed(_controller_name: String) -> void: - if not _capturing_role.is_empty(): - _cancel_capture() - _refresh_bindings() diff --git a/ui/controller_mapping_panel.gd.uid b/ui/controller_mapping_panel.gd.uid deleted file mode 100644 index 41f5e25..0000000 --- a/ui/controller_mapping_panel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b0rl6lgpc0h85 diff --git a/ui/emote_radial_menu.gd b/ui/emote_radial_menu.gd index 165ceac..e0c35de 100644 --- a/ui/emote_radial_menu.gd +++ b/ui/emote_radial_menu.gd @@ -14,21 +14,11 @@ const SIT_SECTOR: int = 0 const RING_RADIUS: float = 172.0 const BUBBLE_SIZE: Vector2 = Vector2(92.0, 88.0) const CONTROLLER_SELECTION_DEADZONE: float = 0.35 -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) var _buttons: Array[BubbleButton] = [] var _is_open: bool = false var _selected_sector: int = SIT_SECTOR var _controller_selection_mode: bool = false -var _controller_mapping_manager: ControllerMappingManagerType - - -func setup_controller_mapping( - mapping_manager: ControllerMappingManagerType, -) -> void: - _controller_mapping_manager = mapping_manager func _ready() -> void: @@ -102,7 +92,10 @@ func _layout_bubbles() -> void: func _update_selection() -> void: - var stick: Vector2 = _get_selection_stick() + var stick: Vector2 = Vector2( + Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), + Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y), + ) if stick.length() >= CONTROLLER_SELECTION_DEADZONE: _select_sector_from_offset(stick) return @@ -111,25 +104,6 @@ func _update_selection() -> void: _update_mouse_selection() -func _get_selection_stick() -> Vector2: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): - return Vector2( - _controller_mapping_manager.get_role_axis( - ControllerMappingManagerType.ROLE_RIGHT_STICK_X - ), - _controller_mapping_manager.get_role_axis( - ControllerMappingManagerType.ROLE_RIGHT_STICK_Y - ), - ) - return Vector2( - Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), - Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y), - ) - - func _update_mouse_selection() -> void: var offset: Vector2 = get_local_mouse_position() - size * 0.5 if offset.length() < 24.0: diff --git a/ui/game_ui.gd b/ui/game_ui.gd index a7e7906..8b2b02d 100644 --- a/ui/game_ui.gd +++ b/ui/game_ui.gd @@ -44,9 +44,6 @@ const SurfaceDrawingToolbarType = preload( const PlayerSettingsManagerType = preload( "res://settings/player_settings_manager.gd" ) -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) const WorldTimeServiceType = preload("res://world/world_time_service.gd") const WorldWeatherServiceType = preload( "res://world/world_weather_service.gd" @@ -67,15 +64,8 @@ signal shop_backdrop_visibility_changed(is_visible: bool) const VIRTUAL_MOUSE_INPUT_OWNER: StringName = &"controller_virtual_mouse" const VIRTUAL_MOUSE_TRIGGER_THRESHOLD: float = 0.55 -const VIRTUAL_MOUSE_TRIGGER_RELEASE_THRESHOLD: float = 0.35 const VIRTUAL_MOUSE_STICK_DEADZONE: float = 0.18 const VIRTUAL_MOUSE_SPEED: float = 720.0 -# Android controller mappings may expose LT on its own axis or as the negative -# half of the same signed axis used by RT. Support both without letting the RT -# zoom direction enter virtual-pointer mode. -const VIRTUAL_MOUSE_TRIGGER_AXIS: JoyAxis = JOY_AXIS_TRIGGER_RIGHT -const VIRTUAL_MOUSE_SHARED_TRIGGER_AXIS: JoyAxis = JOY_AXIS_TRIGGER_LEFT -const VIRTUAL_MOUSE_SECONDARY_CLICK_AXIS: JoyAxis = JOY_AXIS_TRIGGER_LEFT @onready var _status_label: Label = %StatusLabel @onready var _gameplay_transient_hud: Control = %GameplayTransientHUD @@ -147,12 +137,7 @@ var _virtual_mouse_prior_mouse_mode: Input.MouseMode = Input.MOUSE_MODE_VISIBLE var _virtual_mouse_window_position: Vector2 = Vector2.ZERO var _virtual_mouse_button_mask: int = 0 var _virtual_mouse_right_pressed: bool = false -var _virtual_mouse_device_id: int = 0 -var _virtual_mouse_trigger_strength: float = 0.0 -var _virtual_mouse_stick: Vector2 = Vector2.ZERO -var _virtual_mouse_trigger_rest_by_device: Dictionary[int, float] = {} -var _shared_trigger_rest_by_device: Dictionary[int, float] = {} -var _controller_mapping_manager: ControllerMappingManagerType +var _injecting_virtual_mouse_event: bool = false func _ready() -> void: @@ -309,17 +294,21 @@ func setup( set_edge_docks( settings_manager.current_settings.chat_dock_right, settings_manager.current_settings.paint_dock_right, - settings_manager.current_settings.chat_mobile_mode, ) func _input(event: InputEvent) -> void: + if ( + _virtual_mouse_active + and _injecting_virtual_mouse_event + and event is InputEventMouseMotion + ): + _update_virtual_cursor_position( + (event as InputEventMouseMotion).position + ) if _handle_virtual_mouse_input(event): get_viewport().set_input_as_handled() return - if _handle_controller_chat_controls(event): - get_viewport().set_input_as_handled() - return if ( _surface_drawing_toolbar != null and _surface_drawing_toolbar.owns_pointer_event(event) @@ -389,55 +378,6 @@ func _input(event: InputEvent) -> void: get_viewport().set_input_as_handled() -func _handle_controller_chat_controls(event: InputEvent) -> bool: - var button_event: InputEventJoypadButton = event as InputEventJoypadButton - if ( - button_event == null - or not button_event.pressed - or not _gameplay_ui_enabled - or _system_menu_open - or _player_menu_open - or _shop_open - ): - return false - var use_mapping: bool = ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ) - var select_pressed: bool = ( - _controller_mapping_manager.event_matches_role( - event, ControllerMappingManagerType.ROLE_SELECT - ) - if use_mapping - else button_event.button_index == JOY_BUTTON_BACK - ) - var focus_pressed: bool = ( - _controller_mapping_manager.event_matches_role( - event, ControllerMappingManagerType.ROLE_LB - ) - if use_mapping - else button_event.button_index == JOY_BUTTON_LEFT_SHOULDER - ) - var accept_pressed: bool = ( - _controller_mapping_manager.event_matches_role( - event, ControllerMappingManagerType.ROLE_A - ) - if use_mapping - else button_event.button_index == JOY_BUTTON_A - ) - if select_pressed: - # Handle Select before focused LineEdit controls consume it. Select owns - # chat visibility while LB only returns input ownership to the world. - _chat_ui.toggle_chat() - return true - if focus_pressed: - _chat_ui.toggle_focus() - return true - if accept_pressed: - return _chat_ui.request_virtual_keyboard() - return false - - func _on_emote_selected(emote_id: StringName) -> void: if emote_id == &"sit" and _player != null: _player.toggle_sitting() @@ -464,59 +404,24 @@ func _on_quick_action_selected(action_id: StringName) -> void: func _handle_virtual_mouse_input(event: InputEvent) -> bool: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): - return _handle_mapped_virtual_mouse_input(event) var motion_event: InputEventJoypadMotion = event as InputEventJoypadMotion if motion_event != null: - if motion_event.axis in [ - VIRTUAL_MOUSE_TRIGGER_AXIS, - VIRTUAL_MOUSE_SHARED_TRIGGER_AXIS, - ]: - if ( - _virtual_mouse_active - and motion_event.device != _virtual_mouse_device_id - ): - return false - _sample_trigger_rest_values(motion_event.device) - _virtual_mouse_trigger_strength = ( - _virtual_mouse_strength_for_device(motion_event.device) - ) + if motion_event.axis == JOY_AXIS_TRIGGER_LEFT: var was_active: bool = _virtual_mouse_active - if ( - _virtual_mouse_trigger_strength - >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD - ): + if motion_event.axis_value >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD: if not _virtual_mouse_active and _can_start_virtual_mouse(): - _begin_virtual_mouse(motion_event.device) - elif ( - _virtual_mouse_active - and _virtual_mouse_trigger_strength - < VIRTUAL_MOUSE_TRIGGER_RELEASE_THRESHOLD - ): - _end_virtual_mouse() + _begin_virtual_mouse() elif _virtual_mouse_active: - _set_virtual_mouse_button( - MOUSE_BUTTON_RIGHT, - _secondary_click_strength_for_device( - motion_event.device - ) >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD, - ) + _end_virtual_mouse() return was_active or _virtual_mouse_active if ( _virtual_mouse_active - and motion_event.device == _virtual_mouse_device_id - and motion_event.axis in [ - JOY_AXIS_RIGHT_X, - JOY_AXIS_RIGHT_Y, - ] + and motion_event.axis == JOY_AXIS_TRIGGER_RIGHT ): - if motion_event.axis == JOY_AXIS_RIGHT_X: - _virtual_mouse_stick.x = motion_event.axis_value - else: - _virtual_mouse_stick.y = motion_event.axis_value + _set_virtual_mouse_button( + MOUSE_BUTTON_RIGHT, + motion_event.axis_value >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD, + ) return true var button_event: InputEventJoypadButton = event as InputEventJoypadButton if ( @@ -524,124 +429,34 @@ func _handle_virtual_mouse_input(event: InputEvent) -> bool: and button_event.button_index == JOY_BUTTON_RIGHT_SHOULDER and ( _virtual_mouse_active - or _virtual_mouse_trigger_strength - >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD + or Input.get_joy_axis(0, JOY_AXIS_TRIGGER_LEFT) + >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD ) ): if not _virtual_mouse_active and _can_start_virtual_mouse(): - _begin_virtual_mouse(button_event.device) + _begin_virtual_mouse() if _virtual_mouse_active: _set_virtual_mouse_button(MOUSE_BUTTON_LEFT, button_event.pressed) return true return false -func _handle_mapped_virtual_mouse_input(event: InputEvent) -> bool: - var uses_activation: bool = _controller_mapping_manager.event_uses_role( - event, - ControllerMappingManagerType.ROLE_LT, - ) - if uses_activation: - var was_active: bool = _virtual_mouse_active - _virtual_mouse_trigger_strength = ( - _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_LT - ) - ) - if ( - _virtual_mouse_trigger_strength - >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD - and not _virtual_mouse_active - and _can_start_virtual_mouse() - ): - _begin_virtual_mouse( - _controller_mapping_manager.get_active_device_id() - ) - elif ( - _virtual_mouse_active - and _virtual_mouse_trigger_strength - < VIRTUAL_MOUSE_TRIGGER_RELEASE_THRESHOLD - ): - _end_virtual_mouse() - return was_active or _virtual_mouse_active - if not _virtual_mouse_active: - return false - if ( - _controller_mapping_manager.event_uses_role( - event, - ControllerMappingManagerType.ROLE_RIGHT_STICK_X, - ) - or _controller_mapping_manager.event_uses_role( - event, - ControllerMappingManagerType.ROLE_RIGHT_STICK_Y, - ) - ): - _virtual_mouse_stick = _mapped_virtual_mouse_stick() - return true - var button_event := event as InputEventJoypadButton - if button_event != null and _controller_mapping_manager.event_uses_role( - event, - ControllerMappingManagerType.ROLE_RB, - ): - _set_virtual_mouse_button(MOUSE_BUTTON_LEFT, button_event.pressed) - return true - if _controller_mapping_manager.event_uses_role( - event, - ControllerMappingManagerType.ROLE_RT, - ): - _set_virtual_mouse_button( - MOUSE_BUTTON_RIGHT, - _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_RT - ) >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD, - ) - return true - return false - - -func _mapped_virtual_mouse_stick() -> Vector2: - return Vector2( - _controller_mapping_manager.get_role_axis( - ControllerMappingManagerType.ROLE_RIGHT_STICK_X - ), - _controller_mapping_manager.get_role_axis( - ControllerMappingManagerType.ROLE_RIGHT_STICK_Y - ), - ) - - func _can_start_virtual_mouse() -> bool: return ( _gameplay_ui_enabled and not _showcase_active - and not _system_menu_open - and not _player_menu_open - and not _shop_open - and not _chat_input_open and _player != null and _fishing_spot != null - and _fishing_spot.can_open_system_menu() + and _fishing_spot.can_use_surface_drawing() and not _emote_radial_menu.is_open() and not _quick_radial_menu.is_open() ) -func _begin_virtual_mouse(device_id: int) -> void: +func _begin_virtual_mouse() -> void: if _virtual_mouse_active: return _virtual_mouse_active = true - _virtual_mouse_device_id = maxi(device_id, 0) - _virtual_mouse_stick = ( - _mapped_virtual_mouse_stick() - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ) - else Vector2( - Input.get_joy_axis(_virtual_mouse_device_id, JOY_AXIS_RIGHT_X), - Input.get_joy_axis(_virtual_mouse_device_id, JOY_AXIS_RIGHT_Y), - ) - ) _virtual_mouse_prior_camera_input_enabled = ( _player.is_camera_input_enabled() ) @@ -655,11 +470,8 @@ func _begin_virtual_mouse(device_id: int) -> void: Input.mouse_mode = Input.MOUSE_MODE_HIDDEN _virtual_mouse_button_mask = 0 _virtual_mouse_right_pressed = false - _virtual_mouse_window_position = _clamp_virtual_mouse_window_position( - Vector2(get_window().size) * 0.5 - ) + _virtual_mouse_window_position = Vector2(get_window().size) * 0.5 _controller_virtual_cursor.visible = true - _update_virtual_cursor_position(_virtual_mouse_window_position) _emit_virtual_mouse_motion(Vector2.ZERO) @@ -671,8 +483,6 @@ func _end_virtual_mouse() -> void: if _virtual_mouse_right_pressed: _set_virtual_mouse_button(MOUSE_BUTTON_RIGHT, false) _virtual_mouse_active = false - _virtual_mouse_trigger_strength = 0.0 - _virtual_mouse_stick = Vector2.ZERO _controller_virtual_cursor.visible = false if _fishing_spot != null: _fishing_spot.set_local_menu_input_suppressed( @@ -690,12 +500,15 @@ func _update_virtual_mouse(delta: float) -> void: if not _virtual_mouse_active: return if ( - _virtual_mouse_trigger_strength - < VIRTUAL_MOUSE_TRIGGER_RELEASE_THRESHOLD + Input.get_joy_axis(0, JOY_AXIS_TRIGGER_LEFT) + < VIRTUAL_MOUSE_TRIGGER_THRESHOLD ): _end_virtual_mouse() return - var stick: Vector2 = _virtual_mouse_stick + var stick: Vector2 = Vector2( + Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), + Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y), + ) var stick_length: float = stick.length() if stick_length <= VIRTUAL_MOUSE_STICK_DEADZONE: return @@ -713,166 +526,22 @@ func _update_virtual_mouse(delta: float) -> void: * display_scale * delta ) - _virtual_mouse_window_position = _clamp_virtual_mouse_window_position( - _virtual_mouse_window_position + relative_motion + var window_size: Vector2 = Vector2(get_window().size) + _virtual_mouse_window_position = Vector2( + clampf( + _virtual_mouse_window_position.x + relative_motion.x, + 0.0, + window_size.x, + ), + clampf( + _virtual_mouse_window_position.y + relative_motion.y, + 0.0, + window_size.y, + ), ) - _update_virtual_cursor_position(_virtual_mouse_window_position) _emit_virtual_mouse_motion(relative_motion) -func _poll_virtual_mouse_controller_state() -> void: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): - _poll_mapped_virtual_mouse_controller_state() - return - var device_ids: Array[int] = Input.get_connected_joypads() - # Some Android controller backends deliver device-0 axes without including - # that device in get_connected_joypads(). Player camera input already uses - # this same primary-device fallback. - if device_ids.is_empty(): - device_ids.append(0) - for device_id: int in device_ids: - _sample_trigger_rest_values(device_id) - if _virtual_mouse_active: - if not device_ids.has(_virtual_mouse_device_id): - _end_virtual_mouse() - return - _virtual_mouse_trigger_strength = _virtual_mouse_strength_for_device( - _virtual_mouse_device_id - ) - _set_virtual_mouse_button( - MOUSE_BUTTON_RIGHT, - _secondary_click_strength_for_device( - _virtual_mouse_device_id - ) >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD, - ) - _virtual_mouse_stick = Vector2( - Input.get_joy_axis( - _virtual_mouse_device_id, - JOY_AXIS_RIGHT_X, - ), - Input.get_joy_axis( - _virtual_mouse_device_id, - JOY_AXIS_RIGHT_Y, - ), - ) - return - if not _can_start_virtual_mouse(): - return - for device_id: int in device_ids: - var trigger_strength: float = _virtual_mouse_strength_for_device( - device_id - ) - if trigger_strength < VIRTUAL_MOUSE_TRIGGER_THRESHOLD: - continue - _virtual_mouse_trigger_strength = trigger_strength - _begin_virtual_mouse(device_id) - return - - -func _poll_mapped_virtual_mouse_controller_state() -> void: - var trigger_strength: float = _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_LT - ) - if _virtual_mouse_active: - _virtual_mouse_trigger_strength = trigger_strength - if trigger_strength < VIRTUAL_MOUSE_TRIGGER_RELEASE_THRESHOLD: - _end_virtual_mouse() - return - _virtual_mouse_stick = _mapped_virtual_mouse_stick() - _set_virtual_mouse_button( - MOUSE_BUTTON_RIGHT, - _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_RT - ) >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD, - ) - return - if ( - trigger_strength >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD - and _can_start_virtual_mouse() - ): - _virtual_mouse_trigger_strength = trigger_strength - _begin_virtual_mouse( - _controller_mapping_manager.get_active_device_id() - ) - - -func _sample_trigger_rest_values(device_id: int) -> void: - if not _virtual_mouse_trigger_rest_by_device.has(device_id): - _virtual_mouse_trigger_rest_by_device[device_id] = Input.get_joy_axis( - device_id, - VIRTUAL_MOUSE_TRIGGER_AXIS, - ) - if not _shared_trigger_rest_by_device.has(device_id): - _shared_trigger_rest_by_device[device_id] = Input.get_joy_axis( - device_id, - VIRTUAL_MOUSE_SHARED_TRIGGER_AXIS, - ) - - -func _virtual_mouse_strength_for_device(device_id: int) -> float: - _sample_trigger_rest_values(device_id) - var dedicated_rest: float = ( - _virtual_mouse_trigger_rest_by_device[device_id] - ) - var shared_rest: float = _shared_trigger_rest_by_device[device_id] - var dedicated_strength: float = normalized_trigger_strength( - Input.get_joy_axis(device_id, VIRTUAL_MOUSE_TRIGGER_AXIS), - dedicated_rest, - ) - var shared_negative_strength: float = directional_trigger_strength( - Input.get_joy_axis(device_id, VIRTUAL_MOUSE_SHARED_TRIGGER_AXIS), - shared_rest, - -1.0, - ) - return maxf(dedicated_strength, shared_negative_strength) - - -func _secondary_click_strength_for_device(device_id: int) -> float: - _sample_trigger_rest_values(device_id) - return directional_trigger_strength( - Input.get_joy_axis(device_id, VIRTUAL_MOUSE_SECONDARY_CLICK_AXIS), - _shared_trigger_rest_by_device[device_id], - 1.0, - ) - - -static func normalized_trigger_strength( - axis_value: float, - resting_value: float, -) -> float: - var negative_travel: float = absf(-1.0 - resting_value) - var positive_travel: float = absf(1.0 - resting_value) - var available_travel: float = maxf(negative_travel, positive_travel) - if available_travel <= 0.001: - return 0.0 - return clampf( - absf(axis_value - resting_value) / available_travel, - 0.0, - 1.0, - ) - - -static func directional_trigger_strength( - axis_value: float, - resting_value: float, - direction: float, -) -> float: - var normalized_direction: float = signf(direction) - if is_zero_approx(normalized_direction): - return 0.0 - var endpoint: float = normalized_direction - var available_travel: float = absf(endpoint - resting_value) - if available_travel <= 0.001: - return 0.0 - var directed_travel: float = ( - (axis_value - resting_value) * normalized_direction - ) - return clampf(directed_travel / available_travel, 0.0, 1.0) - - func _set_virtual_mouse_button(button: MouseButton, pressed: bool) -> void: var mask: int = ( MOUSE_BUTTON_MASK_LEFT @@ -908,42 +577,18 @@ func _emit_virtual_mouse_motion(relative_motion: Vector2) -> void: func _parse_virtual_mouse_event(event: InputEventMouse) -> void: + _injecting_virtual_mouse_event = true Input.parse_input_event(event) + _injecting_virtual_mouse_event = false func _update_virtual_cursor_position(viewport_position: Vector2) -> void: - var output_scale: float = UIReferencePresentationType.get_scale( - Vector2(get_window().size) - ) + var root_transform: Transform2D = _ui_root.get_global_transform_with_canvas() _controller_virtual_cursor.set_pointer_position( - viewport_position / output_scale + root_transform.affine_inverse() * viewport_position ) -func _clamp_virtual_mouse_window_position( - window_position: Vector2, -) -> Vector2: - var bounds: Rect2 = get_virtual_mouse_window_bounds( - Vector2(get_window().size) - ) - return Vector2( - clampf(window_position.x, bounds.position.x, bounds.end.x), - clampf(window_position.y, bounds.position.y, bounds.end.y), - ) - - -static func get_virtual_mouse_window_bounds(window_size: Vector2) -> Rect2: - var output_scale: float = UIReferencePresentationType.get_scale(window_size) - var cursor_margin: Vector2 = ( - ControllerVirtualCursorType.CURSOR_SIZE * output_scale * 0.5 - ) - var bounds_size: Vector2 = Vector2( - maxf(window_size.x - cursor_margin.x * 2.0, 0.0), - maxf(window_size.y - cursor_margin.y * 2.0, 0.0), - ) - return Rect2(cursor_margin, bounds_size) - - func _toggle_surface_drawing() -> void: if _surface_drawing == null: return @@ -974,29 +619,7 @@ func setup_data_and_identity( ) -func setup_controller_mapping( - mapping_manager: ControllerMappingManagerType, -) -> void: - _controller_mapping_manager = mapping_manager - _player.set_controller_mapping_manager(_controller_mapping_manager) - _emote_radial_menu.setup_controller_mapping(_controller_mapping_manager) - _quick_radial_menu.setup_controller_mapping(_controller_mapping_manager) - _player_menu.setup_controller_mapping(_controller_mapping_manager) - for panel: SettingsPanelType in [ - _title_settings_panel, _pause_settings_panel - ]: - panel.setup_controller_mapping(_controller_mapping_manager) - - -func is_controller_mapping_capturing() -> bool: - return ( - _title_settings_panel.is_controller_mapping_capturing() - or _pause_settings_panel.is_controller_mapping_capturing() - ) - - func _process(delta: float) -> void: - _poll_virtual_mouse_controller_state() _update_virtual_mouse(delta) _update_experience_bubble_position() if _item_effects == null or not _gameplay_ui_enabled: @@ -1130,13 +753,8 @@ func set_effective_ui_pixel_size(pixel_size: int) -> void: _pause_settings_panel.set_effective_ui_pixel_size(pixel_size) -func set_edge_docks( - chat_dock_right: bool, - paint_dock_right: bool, - chat_mobile_mode: bool, -) -> void: +func set_edge_docks(chat_dock_right: bool, paint_dock_right: bool) -> void: _chat_ui.set_dock_right(chat_dock_right) - _chat_ui.set_mobile_mode(chat_mobile_mode) _surface_drawing_toolbar.set_dock_right(paint_dock_right) @@ -1513,8 +1131,6 @@ func _update_experience_bubble_position() -> void: func _on_player_menu_visibility_changed(is_open: bool) -> void: _player_menu_open = is_open - if is_open: - _end_virtual_mouse() if is_open and _surface_drawing != null: _surface_drawing.deactivate() _gameplay_transient_hud.visible = _gameplay_ui_enabled and not is_open diff --git a/ui/player_menu.gd b/ui/player_menu.gd index 208d329..d3ccfcf 100644 --- a/ui/player_menu.gd +++ b/ui/player_menu.gd @@ -30,9 +30,6 @@ const PlayerCoolerCapacityType = preload( const PlayerExperienceType = preload( "res://progression/player_experience.gd" ) -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) const FishBatchSelectionType = preload( "res://ui/fish_batch_selection.gd" ) @@ -283,7 +280,6 @@ var _network_mail_service: NetworkMailService var _reservations: PlayerAssetReservationService var _network_profile_service: NetworkProfileService var _network_player_list: NetworkPlayerListService -var _controller_mapping_manager: ControllerMappingManagerType var _default_buyer: FishBuyerProfileType var _sale_buyer_override: FishBuyerProfileType var _shop_cooler_context_active: bool = false @@ -568,19 +564,9 @@ func setup( _refresh_all() -func setup_controller_mapping( - mapping_manager: ControllerMappingManagerType, -) -> void: - _controller_mapping_manager = mapping_manager - _profile_page.setup_controller_mapping(_controller_mapping_manager) - - func _input(event: InputEvent) -> void: if event is InputEventKey and event.echo: return - if _handle_controller_page_switch(event): - get_viewport().set_input_as_handled() - return if _handle_direct_page_shortcut(event): get_viewport().set_input_as_handled() return @@ -599,71 +585,6 @@ func _input(event: InputEvent) -> void: get_viewport().set_input_as_handled() -func _handle_controller_page_switch(event: InputEvent) -> bool: - var button_event: InputEventJoypadButton = event as InputEventJoypadButton - var use_mapping: bool = ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ) - var uses_left_bumper: bool = ( - _controller_mapping_manager.event_uses_role( - event, ControllerMappingManagerType.ROLE_LB - ) - if use_mapping - else ( - button_event != null - and button_event.button_index == JOY_BUTTON_LEFT_SHOULDER - ) - ) - var uses_right_bumper: bool = ( - _controller_mapping_manager.event_uses_role( - event, ControllerMappingManagerType.ROLE_RB - ) - if use_mapping - else ( - button_event != null - and button_event.button_index == JOY_BUTTON_RIGHT_SHOULDER - ) - ) - if ( - button_event == null - or not (uses_left_bumper or uses_right_bumper) - or not visible - ): - return false - if not button_event.pressed: - return true - # Shoulder input belongs to the Player Menu while it is visible, even when - # a transition or modal temporarily prevents changing pages. This keeps LB - # from opening Chat and RB from leaking into gameplay behind the menu. - if ( - _transitioning - or _page_transitioning - or _sale_confirmation.visible - or get_viewport().gui_is_dragging() - ): - return true - var sections: Array[Section] = [ - _last_inventory_section, - Section.LOGBOOK, - Section.NET, - Section.MAIL, - Section.PROFILE, - Section.PLAYERS, - ] - var current_index: int = 0 - if not _is_inventory_section(_current_section): - current_index = sections.find(_current_section) - if current_index < 0: - current_index = 0 - var direction: int = ( - -1 if uses_left_bumper else 1 - ) - var next_index: int = wrapi(current_index + direction, 0, sections.size()) - _show_section(sections[next_index]) - return true - - func _handle_direct_page_shortcut(event: InputEvent) -> bool: var key_event := event as InputEventKey if ( diff --git a/ui/profile_page.gd b/ui/profile_page.gd index f7cc710..dac52b3 100644 --- a/ui/profile_page.gd +++ b/ui/profile_page.gd @@ -2,9 +2,6 @@ class_name ProfilePage extends Control const CHECK_DEBOUNCE_SECONDS: float = 0.4 -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) var _service: NetworkProfileService var _experience: PlayerExperience @@ -73,20 +70,12 @@ func setup( ) -func setup_controller_mapping( - mapping_manager: ControllerMappingManagerType, -) -> void: - if _preview != null: - _preview.setup_controller_mapping(mapping_manager) - - func activate() -> void: visible = true UtilityPageStyle.animate_in(self) if _service != null: _load_persisted() - # Keep controller page switches on the Profile navigation bubble. Focusing - # the name field here summons the Android keyboard during LB/RB traversal. + _name_edit.grab_focus() func deactivate() -> void: diff --git a/ui/profile_preview.gd b/ui/profile_preview.gd index eaec042..c0bef1c 100644 --- a/ui/profile_preview.gd +++ b/ui/profile_preview.gd @@ -1,10 +1,6 @@ class_name ProfilePreview extends SubViewportContainer -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) - @export_range(0.1, 2.0, 0.05) var drag_sensitivity: float = 0.012 @export_range(0.1, 4.0, 0.1) var keyboard_speed: float = 1.8 @@ -12,13 +8,6 @@ const ControllerMappingManagerType = preload( var _dragging: bool = false var _visuals: Node3D -var _controller_mapping_manager: ControllerMappingManagerType - - -func setup_controller_mapping( - mapping_manager: ControllerMappingManagerType, -) -> void: - _controller_mapping_manager = mapping_manager func _ready() -> void: @@ -47,16 +36,7 @@ func _process(delta: float) -> void: if not has_focus(): return var axis := Input.get_axis("ui_left", "ui_right") - var right_stick: float = ( - _controller_mapping_manager.get_role_axis( - ControllerMappingManagerType.ROLE_RIGHT_STICK_X - ) - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ) - else Input.get_joy_axis(0, JOY_AXIS_RIGHT_X) - ) + var right_stick := Input.get_joy_axis(0, JOY_AXIS_RIGHT_X) if absf(right_stick) > 0.2: axis = right_stick if absf(axis) > 0.1: diff --git a/ui/quick_radial_menu.gd b/ui/quick_radial_menu.gd index 88b461d..585bae2 100644 --- a/ui/quick_radial_menu.gd +++ b/ui/quick_radial_menu.gd @@ -13,9 +13,6 @@ const SECTOR_COUNT: int = 8 const RING_RADIUS: float = 172.0 const BUBBLE_SIZE: Vector2 = Vector2(92.0, 88.0) const CONTROLLER_SELECTION_DEADZONE: float = 0.35 -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) const ACTIONS: Array[StringName] = [ &"stuff", &"logbook", @@ -41,13 +38,6 @@ var _buttons: Array[BubbleButton] = [] var _is_open: bool = false var _selected_sector: int = 0 var _controller_selection_mode: bool = false -var _controller_mapping_manager: ControllerMappingManagerType - - -func setup_controller_mapping( - mapping_manager: ControllerMappingManagerType, -) -> void: - _controller_mapping_manager = mapping_manager func _ready() -> void: @@ -124,7 +114,10 @@ func _layout_bubbles() -> void: func _update_selection() -> void: - var stick: Vector2 = _get_selection_stick() + var stick: Vector2 = Vector2( + Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), + Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y), + ) if stick.length() >= CONTROLLER_SELECTION_DEADZONE: _select_sector_from_offset(stick) return @@ -133,25 +126,6 @@ func _update_selection() -> void: _update_mouse_selection() -func _get_selection_stick() -> Vector2: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): - return Vector2( - _controller_mapping_manager.get_role_axis( - ControllerMappingManagerType.ROLE_RIGHT_STICK_X - ), - _controller_mapping_manager.get_role_axis( - ControllerMappingManagerType.ROLE_RIGHT_STICK_Y - ), - ) - return Vector2( - Input.get_joy_axis(0, JOY_AXIS_RIGHT_X), - Input.get_joy_axis(0, JOY_AXIS_RIGHT_Y), - ) - - func _update_mouse_selection() -> void: var offset: Vector2 = get_local_mouse_position() - size * 0.5 if offset.length() < 24.0: diff --git a/ui/settings_panel.gd b/ui/settings_panel.gd index a29cade..05b0c07 100644 --- a/ui/settings_panel.gd +++ b/ui/settings_panel.gd @@ -18,12 +18,6 @@ const PIXELATION_NAMES: PackedStringArray = [ const SettingsManagerType = preload( "res://settings/player_settings_manager.gd" ) -const ControllerMappingManagerType = preload( - "res://settings/controller_mapping_manager.gd" -) -const ControllerMappingPanelType = preload( - "res://ui/controller_mapping_panel.gd" -) signal applied signal closed @@ -48,7 +42,6 @@ enum PresentationMode { @onready var _world_value: BubbleButton = %WorldValue @onready var _ui_value: BubbleButton = %UIValue @onready var _chat_dock: BubbleButton = %ChatDock -@onready var _chat_mode: BubbleButton = %ChatMode @onready var _paint_dock: BubbleButton = %PaintDock @onready var _mouse_value: BubbleButton = %MouseValue @onready var _controller_value: BubbleButton = %ControllerValue @@ -91,8 +84,6 @@ var _identity_backups: IdentityBackupService var _player_identity: PlayerIdentityStore var _host_identity: HostIdentityStore var _interface_fonts: InterfaceFontController -var _controller_mapping_manager: ControllerMappingManagerType -var _controller_mapping_panel: ControllerMappingPanelType var _data_folder_dialog: FileDialog var _backup_file_dialog: FileDialog var _export_file_dialog: FileDialog @@ -123,7 +114,6 @@ func _ready() -> void: %RootBackButton.pressed.connect(close_panel) %DisplayBackButton.pressed.connect(handle_back) %ControlsBackButton.pressed.connect(handle_back) - %ControllerMapping.pressed.connect(_open_controller_mapping) %AccessibilityBackButton.pressed.connect(handle_back) %DataBackButton.pressed.connect(handle_back) %RootBackButton.gui_input.connect(_on_back_bubble_gui_input) @@ -146,7 +136,6 @@ func _ready() -> void: _set_ui_pixelation.bind(index + 1) ) _chat_dock.pressed.connect(_toggle_chat_dock) - _chat_mode.pressed.connect(_toggle_chat_mode) _paint_dock.pressed.connect(_toggle_paint_dock) %MouseDecrease.pressed.connect(_adjust_mouse_sensitivity.bind(-1)) %MouseIncrease.pressed.connect(_adjust_mouse_sensitivity.bind(1)) @@ -189,11 +178,6 @@ func _ready() -> void: parent_control.resized.connect(_refresh_panel_size) for page: SettingsBubblePage in _pages.values(): page.hide_page() - _controller_mapping_panel = ControllerMappingPanelType.new() - add_child(_controller_mapping_panel) - _controller_mapping_panel.closed.connect( - _on_controller_mapping_panel_closed - ) _style_data_page() call_deferred("_refresh_panel_size") @@ -206,13 +190,6 @@ func setup_network_profile( _network_session = session -func setup_controller_mapping( - mapping_manager: ControllerMappingManagerType, -) -> void: - _controller_mapping_manager = mapping_manager - _controller_mapping_panel.setup(_controller_mapping_manager) - - func setup_data_and_identity( data_root: PlayerDataRoot, identity_backups: IdentityBackupService, @@ -286,11 +263,6 @@ func close_panel(immediate: bool = false) -> void: func _finish_panel_close(applied_result: bool) -> void: _cancel_page_transition() - if ( - _controller_mapping_panel != null - and _controller_mapping_panel.is_open() - ): - _controller_mapping_panel.close_panel() for page: SettingsBubblePage in _pages.values(): page.hide_page() _page_stack.clear() @@ -304,12 +276,6 @@ func _finish_panel_close(applied_result: bool) -> void: func handle_back() -> void: - if ( - _controller_mapping_panel != null - and _controller_mapping_panel.is_open() - ): - _controller_mapping_panel.request_back() - return if _page_transition_active: return if _page_stack.size() > 1: @@ -318,28 +284,10 @@ func handle_back() -> void: close_panel() -func _open_controller_mapping() -> void: - if _controller_mapping_manager == null: - _feedback.text = "no controller mapping service is available" - return - _controller_mapping_panel.open_panel() - - -func _on_controller_mapping_panel_closed() -> void: - %ControllerMapping.grab_focus() - - func get_active_page_id() -> StringName: return _page_stack.back() if not _page_stack.is_empty() else StringName() -func is_controller_mapping_capturing() -> bool: - return ( - _controller_mapping_panel != null - and _controller_mapping_panel.is_capturing() - ) - - func _push_page(page_id: StringName) -> void: if ( _page_transition_active @@ -741,9 +689,6 @@ func _refresh_value_labels() -> void: + _pixel_size_label(settings.ui_pixel_size) ) _chat_dock.text = "chat dock\n" + ("right" if settings.chat_dock_right else "left") - _chat_mode.text = ( - "chat mode\n" + ("mobile" if settings.chat_mobile_mode else "desktop") - ) _paint_dock.text = ( "paint dock\n" + ("right" if settings.paint_dock_right else "left") ) @@ -829,17 +774,6 @@ func _toggle_chat_dock() -> void: _refresh_value_labels() -func _toggle_chat_mode() -> void: - if _settings_manager == null: - return - var edited: PlayerSettings = _settings_manager.current_settings.copy() - edited.chat_mobile_mode = not edited.chat_mobile_mode - if not _settings_manager.apply_settings(edited): - _feedback.text = "failed to save chat mode setting." - return - _refresh_value_labels() - - func _toggle_paint_dock() -> void: if _settings_manager == null: return diff --git a/ui/settings_panel.tscn b/ui/settings_panel.tscn index e821c82..90e2a13 100644 --- a/ui/settings_panel.tscn +++ b/ui/settings_panel.tscn @@ -157,8 +157,8 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("3_page") page_id = &"display" -bubble_paths = Array[NodePath]([NodePath("BubbleCluster/WorldValue"), NodePath("BubbleCluster/WorldLegible"), NodePath("BubbleCluster/WorldCute"), NodePath("BubbleCluster/WorldRetro"), NodePath("BubbleCluster/WorldHardcore"), NodePath("BubbleCluster/WorldWtf"), NodePath("BubbleCluster/UIValue"), NodePath("BubbleCluster/UILegible"), NodePath("BubbleCluster/UICute"), NodePath("BubbleCluster/UIRetro"), NodePath("BubbleCluster/UIHardcore"), NodePath("BubbleCluster/UIWtf"), NodePath("BubbleCluster/ChatDock"), NodePath("BubbleCluster/ChatMode"), NodePath("BubbleCluster/PaintDock"), NodePath("BubbleCluster/DisplayBackButton")]) -focus_paths = Array[NodePath]([NodePath("BubbleCluster/WorldLegible"), NodePath("BubbleCluster/WorldCute"), NodePath("BubbleCluster/WorldRetro"), NodePath("BubbleCluster/WorldHardcore"), NodePath("BubbleCluster/WorldWtf"), NodePath("BubbleCluster/UILegible"), NodePath("BubbleCluster/UICute"), NodePath("BubbleCluster/UIRetro"), NodePath("BubbleCluster/UIHardcore"), NodePath("BubbleCluster/UIWtf"), NodePath("BubbleCluster/ChatDock"), NodePath("BubbleCluster/ChatMode"), NodePath("BubbleCluster/PaintDock"), NodePath("BubbleCluster/DisplayBackButton")]) +bubble_paths = Array[NodePath]([NodePath("BubbleCluster/WorldValue"), NodePath("BubbleCluster/WorldLegible"), NodePath("BubbleCluster/WorldCute"), NodePath("BubbleCluster/WorldRetro"), NodePath("BubbleCluster/WorldHardcore"), NodePath("BubbleCluster/WorldWtf"), NodePath("BubbleCluster/UIValue"), NodePath("BubbleCluster/UILegible"), NodePath("BubbleCluster/UICute"), NodePath("BubbleCluster/UIRetro"), NodePath("BubbleCluster/UIHardcore"), NodePath("BubbleCluster/UIWtf"), NodePath("BubbleCluster/ChatDock"), NodePath("BubbleCluster/PaintDock"), NodePath("BubbleCluster/DisplayBackButton")]) +focus_paths = Array[NodePath]([NodePath("BubbleCluster/WorldLegible"), NodePath("BubbleCluster/WorldCute"), NodePath("BubbleCluster/WorldRetro"), NodePath("BubbleCluster/WorldHardcore"), NodePath("BubbleCluster/WorldWtf"), NodePath("BubbleCluster/UILegible"), NodePath("BubbleCluster/UICute"), NodePath("BubbleCluster/UIRetro"), NodePath("BubbleCluster/UIHardcore"), NodePath("BubbleCluster/UIWtf"), NodePath("BubbleCluster/ChatDock"), NodePath("BubbleCluster/PaintDock"), NodePath("BubbleCluster/DisplayBackButton")]) initial_focus_path = NodePath("BubbleCluster/WorldRetro") back_focus_path = NodePath("BubbleCluster/DisplayBackButton") compact_maximum_layout_size = Vector2(544, 400) @@ -337,48 +337,36 @@ unique_name_in_owner = true custom_minimum_size = Vector2(0, 0) text = "chat dock\nleft" neutral_size = Vector2(96, 96) -desktop_anchor = Vector2(105, 435) -compact_anchor = Vector2(76, 378) +desktop_anchor = Vector2(190, 435) +compact_anchor = Vector2(160, 378) compact_minimum_size = Vector2(82, 82) minimum_font_size = 12 maximum_font_size = 16 motion_phase = 1.1 -[node name="ChatMode" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "chat mode\ndesktop" -neutral_size = Vector2(96, 96) -desktop_anchor = Vector2(275, 435) -compact_anchor = Vector2(225, 378) -compact_minimum_size = Vector2(82, 82) -minimum_font_size = 12 -maximum_font_size = 16 -motion_phase = 1.4 - [node name="PaintDock" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] unique_name_in_owner = true custom_minimum_size = Vector2(0, 0) text = "paint dock\nright" neutral_size = Vector2(96, 96) -desktop_anchor = Vector2(445, 435) -compact_anchor = Vector2(380, 378) +desktop_anchor = Vector2(530, 435) +compact_anchor = Vector2(448, 378) compact_minimum_size = Vector2(82, 82) minimum_font_size = 12 maximum_font_size = 16 -motion_phase = 1.7 +motion_phase = 1.65 [node name="DisplayBackButton" parent="DisplayPage/BubbleCluster" instance=ExtResource("4_bubble")] unique_name_in_owner = true custom_minimum_size = Vector2(0, 0) text = "back" neutral_size = Vector2(96, 90) -desktop_anchor = Vector2(615, 435) -compact_anchor = Vector2(530, 378) +desktop_anchor = Vector2(350, 445) +compact_anchor = Vector2(315, 390) compact_minimum_size = Vector2(82, 78) minimum_font_size = 13 maximum_font_size = 16 -motion_phase = 2.0 +motion_phase = 2.2 [node name="ControlsPage" type="Control" parent="."] unique_name_in_owner = true @@ -391,8 +379,8 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("3_page") page_id = &"controls" -bubble_paths = Array[NodePath]([NodePath("BubbleCluster/MouseDecrease"), NodePath("BubbleCluster/MouseValue"), NodePath("BubbleCluster/MouseIncrease"), NodePath("BubbleCluster/ControllerDecrease"), NodePath("BubbleCluster/ControllerValue"), NodePath("BubbleCluster/ControllerIncrease"), NodePath("BubbleCluster/InvertYToggle"), NodePath("BubbleCluster/ControllerMapping"), NodePath("BubbleCluster/ControlsBackButton")]) -focus_paths = Array[NodePath]([NodePath("BubbleCluster/MouseDecrease"), NodePath("BubbleCluster/MouseValue"), NodePath("BubbleCluster/MouseIncrease"), NodePath("BubbleCluster/ControllerDecrease"), NodePath("BubbleCluster/ControllerValue"), NodePath("BubbleCluster/ControllerIncrease"), NodePath("BubbleCluster/InvertYToggle"), NodePath("BubbleCluster/ControllerMapping"), NodePath("BubbleCluster/ControlsBackButton")]) +bubble_paths = Array[NodePath]([NodePath("BubbleCluster/MouseDecrease"), NodePath("BubbleCluster/MouseValue"), NodePath("BubbleCluster/MouseIncrease"), NodePath("BubbleCluster/ControllerDecrease"), NodePath("BubbleCluster/ControllerValue"), NodePath("BubbleCluster/ControllerIncrease"), NodePath("BubbleCluster/InvertYToggle"), NodePath("BubbleCluster/ControlsBackButton")]) +focus_paths = Array[NodePath]([NodePath("BubbleCluster/MouseDecrease"), NodePath("BubbleCluster/MouseValue"), NodePath("BubbleCluster/MouseIncrease"), NodePath("BubbleCluster/ControllerDecrease"), NodePath("BubbleCluster/ControllerValue"), NodePath("BubbleCluster/ControllerIncrease"), NodePath("BubbleCluster/InvertYToggle"), NodePath("BubbleCluster/ControlsBackButton")]) initial_focus_path = NodePath("BubbleCluster/MouseValue") back_focus_path = NodePath("BubbleCluster/ControlsBackButton") @@ -482,36 +470,24 @@ unique_name_in_owner = true custom_minimum_size = Vector2(0, 0) text = "invert\nvertical\ncamera\noff" neutral_size = Vector2(176, 170) +desktop_anchor = Vector2(525, 230) +compact_anchor = Vector2(485, 225) compact_minimum_size = Vector2(170, 164) minimum_font_size = 14 maximum_font_size = 24 -desktop_anchor = Vector2(525, 145) -compact_anchor = Vector2(485, 135) motion_phase = 4.5 -[node name="ControllerMapping" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] -unique_name_in_owner = true -custom_minimum_size = Vector2(0, 0) -text = "map\ncontroller" -neutral_size = Vector2(160, 150) -desktop_anchor = Vector2(525, 330) -compact_anchor = Vector2(485, 300) -compact_minimum_size = Vector2(148, 138) -minimum_font_size = 14 -maximum_font_size = 23 -motion_phase = 4.9 - [node name="ControlsBackButton" parent="ControlsPage/BubbleCluster" instance=ExtResource("4_bubble")] unique_name_in_owner = true custom_minimum_size = Vector2(0, 0) text = "back" neutral_size = Vector2(100, 94) -desktop_anchor = Vector2(635, 445) -compact_anchor = Vector2(555, 405) +desktop_anchor = Vector2(525, 425) +compact_anchor = Vector2(540, 395) compact_minimum_size = Vector2(84, 80) minimum_font_size = 14 maximum_font_size = 17 -motion_phase = 5.5 +motion_phase = 5.2 [node name="AccessibilityPage" type="Control" parent="."] unique_name_in_owner = true diff --git a/ui/title_screen.gd b/ui/title_screen.gd index 4531b3f..d950da8 100644 --- a/ui/title_screen.gd +++ b/ui/title_screen.gd @@ -490,11 +490,6 @@ func _process(delta: float) -> void: func _input(event: InputEvent) -> void: if not visible: return - if ( - _settings_panel.visible - and _settings_panel.is_controller_mapping_capturing() - ): - return if _join_game_page.visible: if event.is_action_pressed("ui_cancel"): _close_join_game() diff --git a/ui/title_screen.tscn b/ui/title_screen.tscn index 516f20e..6c46d28 100644 --- a/ui/title_screen.tscn +++ b/ui/title_screen.tscn @@ -206,7 +206,7 @@ unique_name_in_owner = true layout_mode = 2 theme_override_colors/font_color = Color(0.682, 0.733, 0.761, 1) theme_override_font_sizes/font_size = 22 -text = "v0.4.1-prealpha" +text = "v0.4.0-prealpha" horizontal_alignment = 1 [node name="Spacer" type="Control" parent="ResponsiveTitleStage/TitlePresentationScaleRoot/Center/MainContent"]