Add direct-connect multiplayer foundation
This commit is contained in:
parent
9e9850dd20
commit
24f8263175
36 changed files with 2633 additions and 45 deletions
175
ui/network/join_game_page.gd
Normal file
175
ui/network/join_game_page.gd
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
class_name JoinGamePage
|
||||
extends Control
|
||||
|
||||
signal join_requested(endpoint: String)
|
||||
signal back_requested
|
||||
|
||||
@onready var _address: LineEdit = %Address
|
||||
@onready var _join_button: BubbleButton = %JoinButton
|
||||
@onready var _cancel_button: BubbleButton = %CancelButton
|
||||
@onready var _back_button: BubbleButton = %BackButton
|
||||
@onready var _open_close_button: BubbleButton = %OpenCloseButton
|
||||
@onready var _status: Label = %Status
|
||||
@onready var _session_summary: Label = %SessionSummary
|
||||
|
||||
var _network_session: NetworkSession
|
||||
var _saved_servers: SavedServerStore
|
||||
var _gameplay_context: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_join_button.pressed.connect(_on_join_pressed)
|
||||
_cancel_button.pressed.connect(_on_cancel_pressed)
|
||||
_back_button.pressed.connect(_on_back_pressed)
|
||||
_open_close_button.pressed.connect(_on_open_close_pressed)
|
||||
_address.text_submitted.connect(_on_address_submitted)
|
||||
hide()
|
||||
|
||||
|
||||
func setup(
|
||||
network_session: NetworkSession,
|
||||
saved_servers: SavedServerStore,
|
||||
gameplay_context: bool,
|
||||
) -> void:
|
||||
_network_session = network_session
|
||||
_saved_servers = saved_servers
|
||||
_gameplay_context = gameplay_context
|
||||
if not _network_session.state_changed.is_connected(_on_state_changed):
|
||||
_network_session.state_changed.connect(_on_state_changed)
|
||||
if not _network_session.status_message_changed.is_connected(
|
||||
_on_status_message_changed
|
||||
):
|
||||
_network_session.status_message_changed.connect(
|
||||
_on_status_message_changed
|
||||
)
|
||||
if not _network_session.connection_error.is_connected(
|
||||
_on_connection_error
|
||||
):
|
||||
_network_session.connection_error.connect(_on_connection_error)
|
||||
if not _network_session.peer_count_changed.is_connected(
|
||||
_on_peer_count_changed
|
||||
):
|
||||
_network_session.peer_count_changed.connect(_on_peer_count_changed)
|
||||
_refresh()
|
||||
|
||||
|
||||
func open_page(preserved_endpoint: String = "") -> void:
|
||||
if not preserved_endpoint.is_empty():
|
||||
_address.text = preserved_endpoint
|
||||
elif _address.text.is_empty():
|
||||
_address.text = "127.0.0.1:7777"
|
||||
show()
|
||||
_refresh()
|
||||
_address.grab_focus()
|
||||
_address.select_all()
|
||||
|
||||
|
||||
func close_page() -> void:
|
||||
hide()
|
||||
get_viewport().gui_release_focus()
|
||||
|
||||
|
||||
func get_endpoint_text() -> String:
|
||||
return _address.text
|
||||
|
||||
|
||||
func set_status(message: String) -> void:
|
||||
_status.text = message
|
||||
|
||||
|
||||
func _on_join_pressed() -> void:
|
||||
_request_join()
|
||||
|
||||
|
||||
func _on_address_submitted(_value: String) -> void:
|
||||
_request_join()
|
||||
|
||||
|
||||
func _request_join() -> void:
|
||||
if _network_session.state in [
|
||||
NetworkSession.State.CONNECTION_FAILED,
|
||||
NetworkSession.State.SERVER_LOST,
|
||||
]:
|
||||
_network_session.reset_failure()
|
||||
var endpoint: ConnectionEndpoint = EndpointParser.parse(_address.text)
|
||||
if not endpoint.is_valid():
|
||||
_status.text = endpoint.error_message
|
||||
return
|
||||
_address.text = endpoint.normalized_display
|
||||
join_requested.emit(endpoint.normalized_display)
|
||||
|
||||
|
||||
func _on_cancel_pressed() -> void:
|
||||
if _network_session != null:
|
||||
_network_session.cancel_connection()
|
||||
_refresh()
|
||||
|
||||
|
||||
func _on_back_pressed() -> void:
|
||||
if (
|
||||
_network_session != null
|
||||
and _network_session.state in [
|
||||
NetworkSession.State.CONNECTING,
|
||||
NetworkSession.State.AUTHENTICATING,
|
||||
]
|
||||
):
|
||||
_network_session.cancel_connection()
|
||||
back_requested.emit()
|
||||
|
||||
|
||||
func _on_open_close_pressed() -> void:
|
||||
if _network_session == null or not _network_session.is_host():
|
||||
return
|
||||
_network_session.set_host_open(not _network_session.is_open_host())
|
||||
_refresh()
|
||||
|
||||
|
||||
func _on_state_changed(_state: NetworkSession.State) -> void:
|
||||
_refresh()
|
||||
|
||||
|
||||
func _on_status_message_changed(message: String) -> void:
|
||||
_status.text = message
|
||||
_refresh()
|
||||
|
||||
|
||||
func _on_connection_error(message: String) -> void:
|
||||
_status.text = message
|
||||
_refresh()
|
||||
|
||||
|
||||
func _on_peer_count_changed(player_count: int, max_players: int) -> void:
|
||||
_session_summary.text = "%d / %d players" % [
|
||||
player_count,
|
||||
max_players,
|
||||
]
|
||||
|
||||
|
||||
func _refresh() -> void:
|
||||
if not is_node_ready() or _network_session == null:
|
||||
return
|
||||
var connecting: bool = _network_session.state in [
|
||||
NetworkSession.State.CONNECTING,
|
||||
NetworkSession.State.AUTHENTICATING,
|
||||
]
|
||||
_address.editable = not connecting
|
||||
_join_button.disabled = connecting
|
||||
_cancel_button.visible = connecting
|
||||
_open_close_button.visible = (
|
||||
_gameplay_context and _network_session.is_host()
|
||||
)
|
||||
if _open_close_button.visible:
|
||||
_open_close_button.text = (
|
||||
"close\ngame"
|
||||
if _network_session.is_open_host()
|
||||
else "open\ngame"
|
||||
)
|
||||
_session_summary.visible = (
|
||||
_gameplay_context
|
||||
and _network_session.state != NetworkSession.State.INACTIVE
|
||||
)
|
||||
if _session_summary.visible:
|
||||
_session_summary.text = "%d / %d players" % [
|
||||
_network_session.get_player_count(),
|
||||
_network_session.get_session_max_players(),
|
||||
]
|
||||
1
ui/network/join_game_page.gd.uid
Normal file
1
ui/network/join_game_page.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dch42c44t4rj5
|
||||
145
ui/network/join_game_page.tscn
Normal file
145
ui/network/join_game_page.tscn
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
[gd_scene load_steps=5 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/network/join_game_page.gd" id="1_script"]
|
||||
[ext_resource type="Theme" path="res://ui/game_theme.tres" id="2_theme"]
|
||||
[ext_resource type="PackedScene" path="res://ui/components/bubble_menu/bubble_button.tscn" id="3_bubble"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBox_paper"]
|
||||
bg_color = Color(0.93, 0.885, 0.73, 1)
|
||||
shadow_color = Color(0.02, 0.075, 0.11, 0.42)
|
||||
shadow_size = 10
|
||||
shadow_offset = Vector2(7, 8)
|
||||
corner_radius_top_left = 54
|
||||
corner_radius_top_right = 46
|
||||
corner_radius_bottom_right = 58
|
||||
corner_radius_bottom_left = 48
|
||||
|
||||
[node name="JoinGamePage" type="Control"]
|
||||
visible = false
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("2_theme")
|
||||
script = ExtResource("1_script")
|
||||
|
||||
[node name="Paper" type="PanelContainer" parent="."]
|
||||
layout_mode = 0
|
||||
offset_left = 340.0
|
||||
offset_top = 132.0
|
||||
offset_right = 940.0
|
||||
offset_bottom = 570.0
|
||||
theme_override_styles/panel = SubResource("StyleBox_paper")
|
||||
|
||||
[node name="Margin" type="MarginContainer" parent="Paper"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 70
|
||||
theme_override_constants/margin_top = 52
|
||||
theme_override_constants/margin_right = 70
|
||||
theme_override_constants/margin_bottom = 52
|
||||
|
||||
[node name="Layout" type="VBoxContainer" parent="Paper/Margin"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 18
|
||||
alignment = 1
|
||||
|
||||
[node name="Title" type="Label" parent="Paper/Margin/Layout"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.035, 0.145, 0.22, 1)
|
||||
theme_override_font_sizes/font_size = 34
|
||||
text = "join game"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Hint" type="Label" parent="Paper/Margin/Layout"]
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.035, 0.145, 0.22, 1)
|
||||
theme_override_font_sizes/font_size = 17
|
||||
text = "hostname or IP address • optional port"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Address" type="LineEdit" parent="Paper/Margin/Layout"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(0, 52)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.035, 0.145, 0.22, 1)
|
||||
theme_override_font_sizes/font_size = 22
|
||||
placeholder_text = "example.net:7777"
|
||||
alignment = 1
|
||||
max_length = 300
|
||||
|
||||
[node name="Status" type="Label" parent="Paper/Margin/Layout"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(0, 42)
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.035, 0.145, 0.22, 1)
|
||||
theme_override_font_sizes/font_size = 17
|
||||
text = "Direct UDP connection • default port 7777"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="SessionSummary" type="Label" parent="Paper/Margin/Layout"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
theme_override_colors/font_color = Color(0.035, 0.145, 0.22, 1)
|
||||
theme_override_font_sizes/font_size = 17
|
||||
text = "1 / 8 players"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Actions" type="HBoxContainer" parent="Paper/Margin/Layout"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 12
|
||||
alignment = 1
|
||||
|
||||
[node name="JoinButton" parent="Paper/Margin/Layout/Actions" instance=ExtResource("3_bubble")]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(112, 106)
|
||||
layout_mode = 2
|
||||
text = "join"
|
||||
neutral_size = Vector2(112, 106)
|
||||
minimum_font_size = 18
|
||||
maximum_font_size = 24
|
||||
horizontal_amplitude = 0.0
|
||||
vertical_amplitude = 0.0
|
||||
deformation_amplitude = 0.0
|
||||
|
||||
[node name="OpenCloseButton" parent="Paper/Margin/Layout/Actions" instance=ExtResource("3_bubble")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(112, 106)
|
||||
layout_mode = 2
|
||||
text = "open\ngame"
|
||||
neutral_size = Vector2(112, 106)
|
||||
minimum_font_size = 17
|
||||
maximum_font_size = 22
|
||||
horizontal_amplitude = 0.0
|
||||
vertical_amplitude = 0.0
|
||||
deformation_amplitude = 0.0
|
||||
|
||||
[node name="CancelButton" parent="Paper/Margin/Layout/Actions" instance=ExtResource("3_bubble")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(98, 94)
|
||||
layout_mode = 2
|
||||
text = "cancel"
|
||||
neutral_size = Vector2(98, 94)
|
||||
minimum_font_size = 16
|
||||
maximum_font_size = 20
|
||||
horizontal_amplitude = 0.0
|
||||
vertical_amplitude = 0.0
|
||||
deformation_amplitude = 0.0
|
||||
|
||||
[node name="BackButton" parent="Paper/Margin/Layout/Actions" instance=ExtResource("3_bubble")]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(98, 94)
|
||||
layout_mode = 2
|
||||
text = "back"
|
||||
neutral_size = Vector2(98, 94)
|
||||
minimum_font_size = 16
|
||||
maximum_font_size = 20
|
||||
horizontal_amplitude = 0.0
|
||||
vertical_amplitude = 0.0
|
||||
deformation_amplitude = 0.0
|
||||
Loading…
Add table
Add a link
Reference in a new issue