diff --git a/assets/arrow.glb b/assets/arrow.glb new file mode 100644 index 0000000..203319c Binary files /dev/null and b/assets/arrow.glb differ diff --git a/assets/arrow.glb.import b/assets/arrow.glb.import new file mode 100644 index 0000000..2d5b60d --- /dev/null +++ b/assets/arrow.glb.import @@ -0,0 +1,37 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://bdmr8tox2w2qn" +path="res://.godot/imported/arrow.glb-fbbbd1f233a05b386bf12d76bd49138b.scn" + +[deps] + +source_file="res://assets/arrow.glb" +dest_files=["res://.godot/imported/arrow.glb-fbbbd1f233a05b386bf12d76bd49138b.scn"] + +[params] + +nodes/root_type="" +nodes/root_name="" +nodes/apply_root_scale=true +nodes/root_scale=1.0 +nodes/import_as_skeleton_bones=false +nodes/use_node_type_suffixes=true +meshes/ensure_tangents=true +meshes/generate_lods=true +meshes/create_shadow_meshes=true +meshes/light_baking=1 +meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false +skins/use_named_skins=true +animation/import=true +animation/fps=30 +animation/trimming=false +animation/remove_immutable_tracks=true +animation/import_rest_as_RESET=false +import_script/path="" +_subresources={} +gltf/naming_version=1 +gltf/embedded_image_handling=1 diff --git a/components/web_client.gd b/components/web_client.gd index 109988e..c9999f1 100644 --- a/components/web_client.gd +++ b/components/web_client.gd @@ -59,6 +59,9 @@ signal received_end_game_request() signal request_next_play() signal request_next_round() +## Notifies to signal a player's turn. +signal notify_player_turn(client_id: String, is_self: bool) + enum ConnectionStatus { DISCONNECTED, ATTEMPTING_CONNECTION, @@ -156,16 +159,16 @@ func _handle_response(response: String) -> void: "request_bet": if data["client_id"] == _own_client_data.client_id: received_bet_request.emit.call_deferred(data["disallowed_bet"], data["round"]) - else: - pass # display currently betting person + notify_player_turn.emit.call_deferred(data["client_id"], data["client_id"] == _own_client_data.client_id) "begin_playing_cards": # all players know it's time to play print(data) _is_first_play = true reset_first_card.emit.call_deferred() "request_card": - # individual player asked to play card - notify_play_card_request.emit.call_deferred() + if data["client_id"] == _own_client_data.client_id: + notify_play_card_request.emit.call_deferred() + notify_player_turn.emit.call_deferred(data["client_id"], data["client_id"] == _own_client_data.client_id) "begin_next_play": print("beginning next play!") _is_first_play = true diff --git a/elements/player_hand.gd b/elements/player_hand.gd index 9afa746..096ef0c 100644 --- a/elements/player_hand.gd +++ b/elements/player_hand.gd @@ -23,6 +23,9 @@ var _is_owned: bool @export var hide_client_name: bool = false @export var card_disallowed_label: Label +@export var top_arrow_container: Node3D +@export var bottom_arrow_container: Node3D + var _selected_card: PlayingCard = null var _cards_in_hand_ids: Array[int] = [] var _allow_clicking_cards: bool = false @@ -38,11 +41,24 @@ signal card_played(card_id: int) func _ready() -> void: if hide_client_name: name_label.hide() + + top_arrow_container.hide() + bottom_arrow_container.hide() func set_player_data(client_data: ClientData) -> void: _client_data = client_data name_label.text = _client_data.client_name +func set_turn(is_turn: bool, is_self: bool) -> void: + if is_turn: + if is_self: + top_arrow_container.show() + else: + bottom_arrow_container.show() + else: + top_arrow_container.hide() + bottom_arrow_container.hide() + func add_card(card: PlayingCard) -> void: card_container.add_child(card) _arrange_cards() diff --git a/elements/player_hand.tscn b/elements/player_hand.tscn index 956b665..87f9d8f 100644 --- a/elements/player_hand.tscn +++ b/elements/player_hand.tscn @@ -1,15 +1,102 @@ -[gd_scene load_steps=3 format=3 uid="uid://jlovgr2iojrg"] +[gd_scene load_steps=8 format=3 uid="uid://jlovgr2iojrg"] [ext_resource type="Script" uid="uid://b5b5cl2qlhywv" path="res://elements/player_hand.gd" id="1_ank64"] [ext_resource type="PackedScene" uid="uid://b55xpcxk7g5ph" path="res://cards/playing_card.tscn" id="2_11xsc"] +[ext_resource type="PackedScene" uid="uid://bdmr8tox2w2qn" path="res://assets/arrow.glb" id="3_ksc6e"] -[node name="PlayerHand" type="Node3D" node_paths=PackedStringArray("card_container", "name_label", "rank_label")] +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ksc6e"] +albedo_color = Color(0.84, 0.4725, 0.21, 1) + +[sub_resource type="Animation" id="Animation_ksc6e"] +resource_name = "hover" +length = 2.0 +loop_mode = 1 +tracks/0/type = "bezier" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:position:x") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"handle_modes": PackedInt32Array(0, 0, 0), +"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0, 0, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0, 1, 2) +} +tracks/1/type = "bezier" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:position:y") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"handle_modes": PackedInt32Array(2, 2, 2), +"points": PackedFloat32Array(-0.576859, 0, 0, 0.333333, 0, -0.720279, -0.333333, 0, 0.333333, 0, -0.576859, -0.333333, 0, 0, 0), +"times": PackedFloat32Array(0, 1, 2) +} +tracks/2/type = "bezier" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath(".:position:z") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"handle_modes": PackedInt32Array(0, 0, 0), +"points": PackedFloat32Array(-0.0702564, -0.25, 0, 0.25, 0, -0.0702564, -0.25, 0, 0.25, 0, -0.0702564, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0, 1, 2) +} + +[sub_resource type="Animation" id="Animation_j3yk6"] +length = 0.001 +loop_mode = 1 +tracks/0/type = "bezier" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:position:x") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"handle_modes": PackedInt32Array(0), +"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0) +} +tracks/1/type = "bezier" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:position:y") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"handle_modes": PackedInt32Array(0), +"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0) +} +tracks/2/type = "bezier" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath(".:position:z") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"handle_modes": PackedInt32Array(0), +"points": PackedFloat32Array(0, -0.25, 0, 0.25, 0), +"times": PackedFloat32Array(0) +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_v6rd7"] +_data = { +&"RESET": SubResource("Animation_j3yk6"), +&"hover": SubResource("Animation_ksc6e") +} + +[node name="PlayerHand" type="Node3D" node_paths=PackedStringArray("card_container", "name_label", "rank_label", "top_arrow_container", "bottom_arrow_container")] script = ExtResource("1_ank64") card_scene = ExtResource("2_11xsc") card_container = NodePath("CardContainer") card_angle = 0.125664 name_label = NodePath("NameLabel") rank_label = NodePath("RankLabel") +top_arrow_container = NodePath("TopArrow") +bottom_arrow_container = NodePath("BottomArrow") [node name="NameLabel" type="Label3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.513717, 0) @@ -23,3 +110,35 @@ text = "name goes here" transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.283052, 0) billboard = 1 double_sided = false + +[node name="TopArrow" type="Node3D" parent="."] +transform = Transform3D(-1, 8.74228e-08, 0, -8.74228e-08, -1, 0, 0, 0, 1, 0, 0, 0) + +[node name="arrow" parent="TopArrow" instance=ExtResource("3_ksc6e")] +transform = Transform3D(0.35, 0, 0, 0, 0.35, 0, 0, 0, 0.35, 0, 0, 0) + +[node name="Cylinder" parent="TopArrow/arrow" index="0"] +surface_material_override/0 = SubResource("StandardMaterial3D_ksc6e") + +[node name="AnimationPlayer" type="AnimationPlayer" parent="TopArrow/arrow"] +libraries = { +&"": SubResource("AnimationLibrary_v6rd7") +} +autoplay = "hover" + +[node name="BottomArrow" type="Node3D" parent="."] + +[node name="arrow" parent="BottomArrow" instance=ExtResource("3_ksc6e")] +transform = Transform3D(0.35, 0, 0, 0, 0.35, 0, 0, 0, 0.35, 0, 0, 0) + +[node name="Cylinder" parent="BottomArrow/arrow" index="0"] +surface_material_override/0 = SubResource("StandardMaterial3D_ksc6e") + +[node name="AnimationPlayer" type="AnimationPlayer" parent="BottomArrow/arrow"] +libraries = { +&"": SubResource("AnimationLibrary_v6rd7") +} +autoplay = "hover" + +[editable path="TopArrow/arrow"] +[editable path="BottomArrow/arrow"] diff --git a/environment_manager.gd b/environment_manager.gd index 9889197..b7b867b 100644 --- a/environment_manager.gd +++ b/environment_manager.gd @@ -32,6 +32,8 @@ var _bets: Dictionary[String, Array] # Array[BetResult] var _plays: Array[Play] var _trump_id: int = -1 +var _current_turn_client_id: String = "" + func _on_web_client_tcp_client_order_received(playing_order: Array[ClientData]) -> void: var marker_positions: Array[Marker3D] var client_ids: Array[String] = [] @@ -146,3 +148,12 @@ func _on_web_client_tcp_received_end_game_request() -> void: func _on_web_client_connected_to_lobby(lobby_id: String, client_id: String) -> void: _own_client_id = client_id + + +func _on_web_client_notify_player_turn(client_id: String, is_self: bool) -> void: + if _current_turn_client_id: + hand_associations[_current_turn_client_id].set_turn(false, is_self) + + _current_turn_client_id = client_id + if _current_turn_client_id: + hand_associations[_current_turn_client_id].set_turn(true, is_self) diff --git a/game.tscn b/game.tscn index bf19356..bab3603 100644 --- a/game.tscn +++ b/game.tscn @@ -379,6 +379,7 @@ playing_card_scene = ExtResource("6_eow3j") [connection signal="connection_status_changed" from="WebClient" to="Interface/ConnectionOverlay" method="_on_web_client_connection_status_changed"] [connection signal="new_round_started" from="WebClient" to="EnvironmentManager" method="_on_web_client_tcp_new_round_started"] [connection signal="notify_play_card_request" from="WebClient" to="HBoxContainer/GameUI" method="_on_web_client_tcp_notify_play_card_request"] +[connection signal="notify_player_turn" from="WebClient" to="EnvironmentManager" method="_on_web_client_notify_player_turn"] [connection signal="received_bet_request" from="WebClient" to="HBoxContainer/GameUI" method="_on_web_client_tcp_received_bet_request"] [connection signal="received_bet_request" from="WebClient" to="HBoxContainer/GameUI/BetContainer/BetInput" method="_on_web_client_tcp_received_bet_request"] [connection signal="received_chat_message" from="WebClient" to="Interface/ClientInterface" method="_on_web_client_tcp_received_chat_message"] diff --git a/server_tcp.py b/server_tcp.py index 6056a27..1d95164 100644 --- a/server_tcp.py +++ b/server_tcp.py @@ -177,25 +177,21 @@ class LobbyManager: #region gameplay async def spread_cards(self, lobby_id, round, cards, playing_order) -> None: - client_ids = self.get_lobby_client_ids(lobby_id) - - trump = None + trump = -1 if cards["trump"]: trump = cards["trump"] cards.pop("trump") - for client_id in client_ids: - await self.send_message( - lobby_id, - client_id, - json.dumps({ - "response": "round_started", - "current_round": round, - "cards": cards, - "trump": trump, - "playing_order": playing_order, - }) - ) + await self.broadcast_message( + lobby_id, + json.dumps({ + "response": "round_started", + "current_round": round, + "cards": cards, + "trump": trump, + "playing_order": playing_order, + }) + ) async def request_bet(self, lobby_id, client_id, disallowed_bet) -> None: await self.broadcast_message( @@ -455,11 +451,11 @@ async def process_input(message: str, websocket) -> None: "playing_order": lobby_manager.get_lobby(lobby_id).current_playing_order, }), ) - await lobby_manager.send_message( + await lobby_manager.broadcast_message( lobby_id, - lobby_manager.get_lobby(lobby_id).current_playing_order[0], json.dumps({ "response": "request_card", + "client_id": lobby_manager.get_lobby(lobby_id).current_playing_order[0], }), ) @@ -517,11 +513,11 @@ async def process_input(message: str, websocket) -> None: playing_client_id = lobby_manager.get_lobby(lobby_id).current_playing_order[0] - await lobby_manager.send_message( + await lobby_manager.broadcast_message( lobby_id, - playing_client_id, json.dumps({ "response": "request_card", + "client_id": playing_client_id, "round": lobby_manager.get_lobby(lobby_id).current_round, }), ) @@ -569,11 +565,11 @@ async def process_input(message: str, websocket) -> None: # not all clients have played a card yet; continue playing_client_id = playing_order[client_index + 1] - await lobby_manager.send_message( + await lobby_manager.broadcast_message( lobby_id, - playing_client_id, json.dumps({ "response": "request_card", + "client_id": playing_client_id, }), )