diff --git a/network/network_chat_protocol.gd b/network/network_chat_protocol.gd index da1af63..ef7294d 100644 --- a/network/network_chat_protocol.gd +++ b/network/network_chat_protocol.gd @@ -3,8 +3,8 @@ extends RefCounted const CAPABILITY: StringName = &"chat_v1" const RELIABLE_CHANNEL: int = NetworkProtocol.CHAT_RELIABLE_CHANNEL -const MAX_VISIBLE_CHARACTERS: int = 300 -const MAX_UTF8_BYTES: int = 1200 +const MAX_VISIBLE_CHARACTERS: int = 256 +const MAX_UTF8_BYTES: int = 1024 const MAX_HISTORY: int = 100 const LATE_JOIN_HISTORY: int = 50 const MAX_ID_LENGTH: int = 96 diff --git a/network/network_session.gd b/network/network_session.gd index 1083c24..27b599f 100644 --- a/network/network_session.gd +++ b/network/network_session.gd @@ -1446,6 +1446,10 @@ func _is_valid_movement_input(data: Dictionary) -> bool: or typeof(data.get("sprint")) != TYPE_BOOL or typeof(data.get("sneak")) != TYPE_BOOL or typeof(data.get("slow_walk")) != TYPE_BOOL + or ( + data.has("sitting") + and typeof(data.get("sitting")) != TYPE_BOOL + ) or typeof(data.get("camera_yaw")) not in [TYPE_FLOAT, TYPE_INT] ): return false diff --git a/player/player.gd b/player/player.gd index e5a5076..9c79b2f 100644 --- a/player/player.gd +++ b/player/player.gd @@ -533,6 +533,7 @@ func capture_network_input(sequence: int) -> Dictionary: "sprint": false, "sneak": false, "slow_walk": false, + "sitting": _sitting, } var axis: Vector2 = Input.get_vector( "move_left", @@ -548,6 +549,7 @@ func capture_network_input(sequence: int) -> Dictionary: "sprint": Input.is_action_pressed("sprint"), "sneak": Input.is_action_pressed("sneak"), "slow_walk": Input.is_action_pressed("slow_walk"), + "sitting": _sitting, } @@ -565,6 +567,7 @@ func apply_authoritative_network_input(data: Dictionary) -> void: _network_sprint = bool(data.get("sprint", false)) _network_sneak = bool(data.get("sneak", false)) _network_slow_walk = bool(data.get("slow_walk", false)) + _set_sitting(bool(data.get("sitting", false))) func make_network_snapshot(peer_id: int) -> Dictionary: @@ -575,6 +578,7 @@ func make_network_snapshot(peer_id: int) -> Dictionary: "velocity": [velocity.x, velocity.y, velocity.z], "visual_yaw": _visuals.rotation.y, "grounded": is_on_floor(), + "sitting": _sitting, } @@ -585,6 +589,7 @@ func push_network_snapshot(snapshot: Dictionary) -> void: _network_target_position = parsed["position"] _network_target_velocity = parsed["velocity"] _network_target_visual_yaw = parsed["visual_yaw"] + _set_sitting(bool(parsed["sitting"])) if not _network_snapshot_ready: global_position = _network_target_position velocity = _network_target_velocity @@ -596,6 +601,7 @@ func apply_local_prediction_correction(snapshot: Dictionary) -> void: var parsed: Dictionary = _parse_network_snapshot(snapshot) if parsed.is_empty(): return + _set_sitting(bool(parsed["sitting"])) var authoritative_position: Vector3 = parsed["position"] var error_distance: float = global_position.distance_to( authoritative_position @@ -613,6 +619,7 @@ func apply_network_teleport(snapshot: Dictionary) -> void: global_position = parsed["position"] velocity = parsed["velocity"] _visuals.rotation.y = parsed["visual_yaw"] + _set_sitting(bool(parsed["sitting"])) _network_target_position = global_position _network_target_velocity = velocity _network_target_visual_yaw = _visuals.rotation.y @@ -640,6 +647,9 @@ func _parse_network_snapshot(snapshot: Dictionary) -> Dictionary: float(network_velocity[2]) ) var visual_yaw: float = float(snapshot.get("visual_yaw", 0.0)) + if snapshot.has("sitting") and typeof(snapshot.get("sitting")) != TYPE_BOOL: + return {} + var sitting: bool = bool(snapshot.get("sitting", false)) if ( not parsed_position.is_finite() or not parsed_velocity.is_finite() @@ -650,6 +660,7 @@ func _parse_network_snapshot(snapshot: Dictionary) -> Dictionary: "position": parsed_position, "velocity": parsed_velocity, "visual_yaw": visual_yaw, + "sitting": sitting, } diff --git a/settings/player_settings.gd b/settings/player_settings.gd index 4a7343f..2a8697b 100644 --- a/settings/player_settings.gd +++ b/settings/player_settings.gd @@ -13,7 +13,7 @@ const DEFAULT_WORLD_PIXEL_SIZE: int = 3 const MIN_UI_PIXEL_SIZE: int = 1 const MAX_UI_PIXEL_SIZE: int = 5 const DEFAULT_UI_PIXEL_SIZE: int = 3 -const MAX_CHAT_DRAFT_CHARACTERS: int = 280 +const MAX_CHAT_DRAFT_CHARACTERS: int = 256 const COMPACT_DISPLAY_HEIGHT: int = 560 const WORLD_DESKTOP_GRID_HEIGHTS: Array[int] = [0, 540, 360, 216, 96] const WORLD_COMPACT_GRID_HEIGHTS: Array[int] = [0, 360, 240, 144, 72] diff --git a/ui/chat_ui.gd b/ui/chat_ui.gd index 0d61506..fe7f731 100644 --- a/ui/chat_ui.gd +++ b/ui/chat_ui.gd @@ -20,6 +20,7 @@ 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 SPEECH_BUBBLE_WIDTH: float = 320.0 const MOBILE_COMPACT_WIDTH: float = 620.0 const MOBILE_EXPANDED_WIDTH: float = 820.0 const MOBILE_COMPACT_HEIGHT: float = 220.0 @@ -78,6 +79,7 @@ var _pending_send_body: String = "" var _prior_movement: bool = true var _prior_camera: bool = true var _controller_refocused: bool = false +var _input_lock_applied: bool = false var _output_scale: float = 1.0 var _dock_right: bool = false var _mobile_mode: bool = false @@ -164,6 +166,7 @@ func open_chat() -> void: text_entry_ownership_changed.emit(true) _prior_movement = _player.is_movement_enabled() _prior_camera = _player.is_camera_input_enabled() + _input_lock_applied = true _player.set_movement_enabled(false) _player.set_camera_input_enabled(false) _fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, true) @@ -191,16 +194,18 @@ func set_available(value: bool) -> void: func close_chat() -> void: - if not _opened: - return + var ownership_was_active: bool = _opened or _input_lock_applied _opened = false - text_entry_ownership_changed.emit(false) _entry.virtual_keyboard_enabled = false _entry.release_focus() _entry.hide() - _player.set_movement_enabled(_prior_movement) - _player.set_camera_input_enabled(_prior_camera) - _fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, false) + if _input_lock_applied: + _player.set_movement_enabled(_prior_movement) + _player.set_camera_input_enabled(_prior_camera) + _fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, false) + _input_lock_applied = false + if ownership_was_active: + text_entry_ownership_changed.emit(false) _flush_draft() _refresh_visibility() _refresh_input_ownership() @@ -338,7 +343,7 @@ func _build_ui() -> void: _history.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART _history.fit_content = false _history.scroll_active = true - _history.scroll_following = false + _history.scroll_following = true _history.vertical_alignment = VERTICAL_ALIGNMENT_BOTTOM _history.mouse_filter = Control.MOUSE_FILTER_STOP _history.add_theme_font_override("normal_font", UtilityPageStyle.TuffyFont) @@ -623,13 +628,14 @@ func _on_message(message: Dictionary) -> void: _on_peer_removed(peer_id) var bubble := PanelContainer.new() bubble.mouse_filter = Control.MOUSE_FILTER_IGNORE - bubble.custom_minimum_size = Vector2(270, 0) - bubble.size = Vector2(270, 72) + bubble.custom_minimum_size = Vector2(SPEECH_BUBBLE_WIDTH, 0.0) bubble.add_theme_stylebox_override("panel", _speech_panel_style()) var label := Label.new() - label.text = str(message["body"]).left(120) - label.custom_minimum_size = Vector2(246, 46) - label.size = Vector2(246, 62) + label.text = str(message["body"]) + label.custom_minimum_size = Vector2( + SPEECH_BUBBLE_WIDTH - 20.0, + 0.0, + ) label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER @@ -670,7 +676,6 @@ func _on_rejected(message: String) -> void: func _refresh_history() -> void: if _service == null: return - var scroll_state := _capture_history_scroll() var lines: Array[String] = [] var messages := _service.get_history() for message: Dictionary in messages: @@ -681,7 +686,7 @@ func _refresh_history() -> void: str(message["sender_display_name"]), str(message["body"]), ]) _history.text = "\n".join(lines) - _restore_history_scroll.call_deferred(scroll_state) + _scroll_history_to_bottom.call_deferred() func _refresh_visibility() -> void: @@ -1034,7 +1039,6 @@ func _layout_presentation(animate: bool) -> void: _unread_indicator.position = unread_position _hint.position = hint_position return - var scroll_state := _capture_history_scroll() _height_tween = create_tween().set_parallel(true) _height_tween.tween_property( _panel, "position", target_position, UIMotion.CHAT_RESIZE_DURATION @@ -1073,38 +1077,18 @@ func _layout_presentation(animate: bool) -> void: UIMotion.CHAT_RESIZE_DURATION, ).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT) _height_tween.finished.connect(func() -> void: - _restore_history_scroll(scroll_state) + _scroll_history_to_bottom() ) _hint.position = hint_position -func _capture_history_scroll() -> Dictionary: - if _history == null: - return {"pinned": true, "value": 0.0} - var scroll := _history.get_v_scroll_bar() - if scroll == null: - return {"pinned": true, "value": 0.0} - var bottom := maxf(scroll.min_value, scroll.max_value - scroll.page) - return { - "pinned": scroll.value >= bottom - 2.0, - "value": scroll.value, - } - - -func _restore_history_scroll(state: Dictionary) -> void: +func _scroll_history_to_bottom() -> void: if _history == null: return var scroll := _history.get_v_scroll_bar() if scroll == null: return - if bool(state.get("pinned", true)): - scroll.value = maxf(scroll.min_value, scroll.max_value - scroll.page) - else: - scroll.value = clampf( - float(state.get("value", 0.0)), - scroll.min_value, - maxf(scroll.min_value, scroll.max_value - scroll.page), - ) + scroll.value = maxf(scroll.min_value, scroll.max_value - scroll.page) func _on_viewport_resized() -> void: