From f6e650b6717cefbf6cd28f75c44056ac8bf3a39e Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Wed, 5 Mar 2025 11:35:40 +0100 Subject: [PATCH] TD-18: Matchmaking UI --- export_presets.cfg | 2 +- project.godot | 2 + scenes/game.tscn | 49 ++++++++++++++++++ scenes/main_menu.tscn | 6 +-- .../match/current_unix_time_message.gd | 12 +++++ scripts/channel/match/match_channel.gd | 20 ++++++++ .../matchmaking/matchmaking_channel.gd | 2 +- .../channel/time/current_unix_time_message.gd | 8 --- scripts/match/current_match.gd | 13 +++++ scripts/match/ui/current_game_time.gd | 9 ++++ scripts/match/ui/opponent_name.gd | 5 ++ scripts/ui/{ => lobby}/search_match.gd | 21 +++++--- scripts/ui/{ => login}/login.gd | 0 .../ui/{ => login}/show_banner_on_error.gd | 0 scripts/ui/websocket_time.gd | 50 ------------------- 15 files changed, 128 insertions(+), 71 deletions(-) create mode 100644 scenes/game.tscn create mode 100644 scripts/channel/match/current_unix_time_message.gd create mode 100644 scripts/channel/match/match_channel.gd delete mode 100644 scripts/channel/time/current_unix_time_message.gd create mode 100644 scripts/match/current_match.gd create mode 100644 scripts/match/ui/current_game_time.gd create mode 100644 scripts/match/ui/opponent_name.gd rename scripts/ui/{ => lobby}/search_match.gd (88%) rename scripts/ui/{ => login}/login.gd (100%) rename scripts/ui/{ => login}/show_banner_on_error.gd (100%) delete mode 100644 scripts/ui/websocket_time.gd diff --git a/export_presets.cfg b/export_presets.cfg index d53b0ac..a3556a0 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -114,7 +114,7 @@ custom_features="" export_filter="all_resources" include_filter="" exclude_filter="" -export_path="../../../../../Downloads/TowerDefence.dmg" +export_path="../../../../../Downloads/TowerDefence.app" encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false diff --git a/project.godot b/project.godot index 77ddc6b..3f6dac5 100644 --- a/project.godot +++ b/project.godot @@ -19,6 +19,8 @@ config/icon="res://textures/icon.svg" ConnectionChannel="*res://scripts/channel/connection/connection_channel.gd" MatchmakingChannel="*res://scripts/channel/matchmaking/matchmaking_channel.gd" +MatchChannel="*res://scripts/channel/match/match_channel.gd" +CurrentMatch="*res://scripts/match/current_match.gd" [display] diff --git a/scenes/game.tscn b/scenes/game.tscn new file mode 100644 index 0000000..f61971f --- /dev/null +++ b/scenes/game.tscn @@ -0,0 +1,49 @@ +[gd_scene load_steps=3 format=3 uid="uid://co1x3hlc2efr6"] + +[ext_resource type="Script" path="res://scripts/match/ui/opponent_name.gd" id="1_saby1"] +[ext_resource type="Script" path="res://scripts/match/ui/current_game_time.gd" id="2_3jcub"] + +[node name="Game" type="Node2D"] + +[node name="CanvasLayer" type="CanvasLayer" parent="."] + +[node name="HUD" type="Control" parent="CanvasLayer"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="Opponent Name" type="RichTextLabel" parent="CanvasLayer/HUD"] +layout_mode = 1 +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -0.5 +offset_right = 0.5 +offset_bottom = 45.0 +grow_horizontal = 2 +text = "Unknown" +fit_content = true +scroll_active = false +autowrap_mode = 0 +script = ExtResource("1_saby1") + +[node name="Time" type="RichTextLabel" parent="CanvasLayer/HUD"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -20.0 +offset_top = -20.0 +offset_right = 20.0 +offset_bottom = 20.0 +grow_horizontal = 2 +grow_vertical = 2 +fit_content = true +scroll_active = false +autowrap_mode = 0 +script = ExtResource("2_3jcub") diff --git a/scenes/main_menu.tscn b/scenes/main_menu.tscn index 7c4ac3c..3fcad8f 100644 --- a/scenes/main_menu.tscn +++ b/scenes/main_menu.tscn @@ -1,12 +1,12 @@ [gd_scene load_steps=12 format=3 uid="uid://bqfijb7bk2g7j"] [ext_resource type="Theme" uid="uid://bt4hxdwromnxs" path="res://ui/theme.tres" id="1_6qgep"] -[ext_resource type="Script" path="res://scripts/ui/show_banner_on_error.gd" id="2_1tbi1"] +[ext_resource type="Script" path="res://scripts/ui/login/show_banner_on_error.gd" id="2_1tbi1"] [ext_resource type="Script" path="res://scripts/ui/swap_menu.gd" id="2_c477a"] -[ext_resource type="Script" path="res://scripts/ui/login.gd" id="3_33cgr"] +[ext_resource type="Script" path="res://scripts/ui/login/login.gd" id="3_33cgr"] [ext_resource type="Resource" uid="uid://cdixdbu3sqgjn" path="res://config/api_config.tres" id="4_5vuod"] [ext_resource type="Script" path="res://scripts/ui/quit.gd" id="6_cixwl"] -[ext_resource type="Script" path="res://scripts/ui/search_match.gd" id="7_dmfpl"] +[ext_resource type="Script" path="res://scripts/ui/lobby/search_match.gd" id="7_dmfpl"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q2pxx"] bg_color = Color(0.52, 0.52, 0.52, 1) diff --git a/scripts/channel/match/current_unix_time_message.gd b/scripts/channel/match/current_unix_time_message.gd new file mode 100644 index 0000000..c6c16cb --- /dev/null +++ b/scripts/channel/match/current_unix_time_message.gd @@ -0,0 +1,12 @@ +class_name CurrentUnixTimeMessage +extends Message + +const MESSAGE_ID: String = "CurrentUnixTime" + +@export var time: int +# gdlint:ignore = class-variable-name +@export var matchId: String + + +func get_message_id() -> String: + return MESSAGE_ID diff --git a/scripts/channel/match/match_channel.gd b/scripts/channel/match/match_channel.gd new file mode 100644 index 0000000..9bf6671 --- /dev/null +++ b/scripts/channel/match/match_channel.gd @@ -0,0 +1,20 @@ +extends Channel + +signal on_match_update(msg: CurrentUnixTimeMessage) + + +func get_channel_location() -> String: + return "match" + + +func _process(_delta: float) -> void: + self.socket.poll() + if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN: + return + while self.socket.get_available_packet_count(): + var msg := CurrentUnixTimeMessage.deserialize( + self.socket.get_packet().get_string_from_utf8(), [CurrentUnixTimeMessage] + ) + if msg.get_message_id() != CurrentUnixTimeMessage.MESSAGE_ID: + return + on_match_update.emit(msg) diff --git a/scripts/channel/matchmaking/matchmaking_channel.gd b/scripts/channel/matchmaking/matchmaking_channel.gd index f14ecb0..804ad06 100644 --- a/scripts/channel/matchmaking/matchmaking_channel.gd +++ b/scripts/channel/matchmaking/matchmaking_channel.gd @@ -33,7 +33,7 @@ func _process(_delta: float) -> void: MatchFoundMessage.MESSAGE_ID: on_match_found.emit(msg) MatchAbortedMessage.MESSAGE_ID: - on_match_found.emit(msg) + on_match_aborted.emit() MatchEstablishedMessage.MESSAGE_ID: on_match_established.emit(msg) _: diff --git a/scripts/channel/time/current_unix_time_message.gd b/scripts/channel/time/current_unix_time_message.gd deleted file mode 100644 index 68a1ae7..0000000 --- a/scripts/channel/time/current_unix_time_message.gd +++ /dev/null @@ -1,8 +0,0 @@ -class_name CurrentUnixTimeMessage -extends Message - -var time: int - - -func get_message_id() -> String: - return "CurrentUnixTime" diff --git a/scripts/match/current_match.gd b/scripts/match/current_match.gd new file mode 100644 index 0000000..ec6ff31 --- /dev/null +++ b/scripts/match/current_match.gd @@ -0,0 +1,13 @@ +extends Node + +enum State { NONE, RUNNING, WON, LOST } + +var state: State = State.NONE +var opponent_name: String = "" + + +func start_game(msg: MatchEstablishedMessage) -> void: + self.opponent_name = msg.opponentName + self.state = State.RUNNING + MatchChannel.connect_socket(msg.token) + get_tree().change_scene_to_file("res://scenes/game.tscn") diff --git a/scripts/match/ui/current_game_time.gd b/scripts/match/ui/current_game_time.gd new file mode 100644 index 0000000..de52222 --- /dev/null +++ b/scripts/match/ui/current_game_time.gd @@ -0,0 +1,9 @@ +extends RichTextLabel + + +func _ready() -> void: + MatchChannel.connect("on_match_update", on_match_update) + + +func on_match_update(msg: CurrentUnixTimeMessage) -> void: + self.text = str(msg.time) diff --git a/scripts/match/ui/opponent_name.gd b/scripts/match/ui/opponent_name.gd new file mode 100644 index 0000000..2415004 --- /dev/null +++ b/scripts/match/ui/opponent_name.gd @@ -0,0 +1,5 @@ +extends RichTextLabel + + +func _ready() -> void: + self.text = CurrentMatch.opponent_name diff --git a/scripts/ui/search_match.gd b/scripts/ui/lobby/search_match.gd similarity index 88% rename from scripts/ui/search_match.gd rename to scripts/ui/lobby/search_match.gd index 60ab43d..c62f7ab 100644 --- a/scripts/ui/search_match.gd +++ b/scripts/ui/lobby/search_match.gd @@ -10,7 +10,7 @@ extends Control var searching: bool = false var sent_accept_message: bool = false -var match_id: String = "" +var found_match: MatchFoundMessage func _ready() -> void: @@ -45,6 +45,13 @@ func _ready() -> void: popup.visible = false +func _process(_delta: float) -> void: + if found_match: + var now := int(Time.get_unix_time_from_system() * 1000) + time_bar.max_value = found_match.ttl + time_bar.value = found_match.ttl - (now - found_match.created) + + # gdlint:ignore = max-public-methods func export_valid() -> bool: if not popup: @@ -93,19 +100,17 @@ func on_match_set_search_state(msg: MatchSetSearchStateMessage) -> void: func on_match_found(msg: MatchFoundMessage) -> void: set_match_accptance_ui(true) set_accaptence_buttons_enabled(true) - match_id = msg.matchId - # TODO: Show and Reset Timer bar + found_match = msg func on_match_aborted() -> void: set_match_accptance_ui(false) set_searching_ui(false) - match_id = "" + found_match = null func on_match_established(msg: MatchEstablishedMessage) -> void: - print(msg.opponentName) - #TODO: Implement + CurrentMatch.start_game(msg) ############################# @@ -129,12 +134,12 @@ func on_abort_pressed() -> void: func on_accept_pressed() -> void: set_accaptence_buttons_enabled(false) - MatchmakingChannel.send_match_accepted(true, match_id) + MatchmakingChannel.send_match_accepted(true, found_match.matchId) func on_decline_pressed() -> void: set_accaptence_buttons_enabled(false) - MatchmakingChannel.send_match_accepted(false, match_id) + MatchmakingChannel.send_match_accepted(false, found_match.matchId) ############################# diff --git a/scripts/ui/login.gd b/scripts/ui/login/login.gd similarity index 100% rename from scripts/ui/login.gd rename to scripts/ui/login/login.gd diff --git a/scripts/ui/show_banner_on_error.gd b/scripts/ui/login/show_banner_on_error.gd similarity index 100% rename from scripts/ui/show_banner_on_error.gd rename to scripts/ui/login/show_banner_on_error.gd diff --git a/scripts/ui/websocket_time.gd b/scripts/ui/websocket_time.gd deleted file mode 100644 index 3c77084..0000000 --- a/scripts/ui/websocket_time.gd +++ /dev/null @@ -1,50 +0,0 @@ -extends RichTextLabel - -@export var login: Login -@export var api_config: ApiConfig -var api := ServerApi.new(api_config) - -# docs.redotengine.org/en/stable/tutorials/networking/websocket.html -var time_channel = WebSocketPeer.new() - - -func _ready() -> void: - login.connect("login_successful", on_login) - ( - ConnectionChannel - . connect( - "on_channel_token_received", - on_channel_token_received, - ) - ) - - -func on_login(session: PlayerLoginSession): - ConnectionChannel.connect_to_channel(session.token) - ConnectionChannel.request_channel_token(Message.Channels.TIME) - - -func on_channel_token_received(msg: ProvidedConnectionTokenMessage) -> void: - if time_channel.get_ready_state() != WebSocketPeer.STATE_CLOSED: - return - if msg.channel != Message.Channels.TIME: - return - time_channel.handshake_headers = PackedStringArray( - ["Authorization: " + msg.token], - ) - time_channel.connect_to_url("ws://localhost:8080/ws/time") - - -func _process(_delta: float) -> void: - time_channel.poll() - var state = time_channel.get_ready_state() - - if state != WebSocketPeer.STATE_OPEN: - return - while time_channel.get_available_packet_count(): - var msg: CurrentUnixTimeMessage = Messize( - time_channel.get_packet().get_string_from_utf8(), [CurrentUnixTimeMessage] - ) - if msg == null: - continue - self.text = str(msg.time)