diff --git a/networking/websocket_minimal/Main.tscn b/networking/websocket_minimal/Main.tscn index 37761d1fbd..c5f5f41b39 100644 --- a/networking/websocket_minimal/Main.tscn +++ b/networking/websocket_minimal/Main.tscn @@ -6,7 +6,74 @@ [node name="Main" type="Node"] [node name="Server" type="Node" parent="."] -script = ExtResource( "1" ) +script = ExtResource("1") [node name="Client" type="Node" parent="."] -script = ExtResource( "2" ) +script = ExtResource("2") + +[node name="Control" type="Control" parent="."] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="Control"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="ServerContainer" type="VBoxContainer" parent="Control/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="LabelServer" type="Label" parent="Control/HBoxContainer/ServerContainer"] +layout_mode = 2 +size_flags_horizontal = 4 +theme_override_colors/font_color = Color(0.666667, 0.666667, 0.666667, 1) +theme_override_font_sizes/font_size = 30 +text = "Server" + +[node name="ButtonPong" type="Button" parent="Control/HBoxContainer/ServerContainer"] +layout_mode = 2 +size_flags_horizontal = 4 +theme_override_font_sizes/font_size = 30 +text = "Send Pong" + +[node name="TextServer" type="RichTextLabel" parent="Control/HBoxContainer/ServerContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +bbcode_enabled = true +scroll_following = true + +[node name="ClientContainer" type="VBoxContainer" parent="Control/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="LabelClient" type="Label" parent="Control/HBoxContainer/ClientContainer"] +layout_mode = 2 +size_flags_horizontal = 4 +theme_override_colors/font_color = Color(0.666667, 0.666667, 0.666667, 1) +theme_override_font_sizes/font_size = 30 +text = "Client" + +[node name="ButtonPing" type="Button" parent="Control/HBoxContainer/ClientContainer"] +layout_mode = 2 +size_flags_horizontal = 4 +theme_override_font_sizes/font_size = 30 +text = "Send Ping" + +[node name="TextClient" type="RichTextLabel" parent="Control/HBoxContainer/ClientContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +bbcode_enabled = true +scroll_following = true + +[connection signal="pressed" from="Control/HBoxContainer/ServerContainer/ButtonPong" to="Server" method="_on_button_pong_pressed"] +[connection signal="pressed" from="Control/HBoxContainer/ClientContainer/ButtonPing" to="Client" method="_on_button_ping_pressed"] diff --git a/networking/websocket_minimal/README.md b/networking/websocket_minimal/README.md index 5e1954b0ef..4405102d8f 100644 --- a/networking/websocket_minimal/README.md +++ b/networking/websocket_minimal/README.md @@ -4,6 +4,6 @@ This is a minimal sample of connecting two peers to each other using websockets. Language: GDScript -Renderer: GLES 2 +Renderer: Forward+ Check out this demo on the asset library: https://godotengine.org/asset-library/asset/539 diff --git a/networking/websocket_minimal/client.gd b/networking/websocket_minimal/client.gd index 2ea6fc0b26..12bbe0f429 100644 --- a/networking/websocket_minimal/client.gd +++ b/networking/websocket_minimal/client.gd @@ -1,56 +1,32 @@ extends Node # The URL we will connect to. -@export var websocket_url = "ws://localhost:9080" +var websocket_url = "ws://localhost:9080" +var socket := WebSocketPeer.new() -# Our WebSocketClient instance. -var _client = WebSocketClient.new() - -func _ready(): - # Connect base signals to get notified of connection open, close, and errors. - _client.connection_closed.connect(self._closed) - _client.connection_error.connect(self._closed) - _client.connection_established.connect(self._connected) - # This signal is emitted when not using the Multiplayer API every time - # a full packet is received. - # Alternatively, you could check get_peer(1).get_available_packets() in a loop. - _client.data_received.connect(self._on_data) - - # Initiate connection to the given URL. - var err = _client.connect_to_url(websocket_url) - if err != OK: - push_error("Unable to connect.") - set_process(false) +func log_message(message): + var time = "[color=#aaaaaa] %s [/color]" % Time.get_time_string_from_system() + %TextClient.text += time + message + "\n" -func _closed(was_clean = false): - # was_clean will tell you if the disconnection was correctly notified - # by the remote peer before closing the socket. - print("Closed, clean: ", was_clean) - set_process(false) +func _ready(): + if socket.connect_to_url(websocket_url) != OK: + log_message("Unable to connect.") + set_process(false) -func _connected(proto = ""): - # This is called on connection, "proto" will be the selected WebSocket - # sub-protocol (which is optional) - print("Connected with protocol: ", proto) - # You MUST always use get_peer(1).put_packet to send data to server, - # and not put_packet directly when not using the MultiplayerAPI. - _client.get_peer(1).put_packet("Test packet".to_utf8_buffer()) +func _process(_delta): + socket.poll() -func _on_data(): - # Print the received packet, you MUST always use get_peer(1).get_packet - # to receive data from server, and not get_packet directly when not - # using the MultiplayerAPI. - print("Got data from server: ", _client.get_peer(1).get_packet().get_string_from_utf8()) + if socket.get_ready_state() == WebSocketPeer.STATE_OPEN: + while socket.get_available_packet_count(): + log_message(socket.get_packet().get_string_from_ascii()) -func _process(_delta): - # Call this in _process or _physics_process. Data transfer, and signals - # emission will only happen when calling this function. - _client.poll() +func _exit_tree(): + socket.close() -func _exit_tree(): - _client.disconnect_from_host() +func _on_button_ping_pressed(): + socket.send_text("Ping") diff --git a/networking/websocket_minimal/project.godot b/networking/websocket_minimal/project.godot index 038393fa7a..5b5064746d 100644 --- a/networking/websocket_minimal/project.godot +++ b/networking/websocket_minimal/project.godot @@ -12,9 +12,14 @@ config_version=5 config/name="WebSocket Minimal Demo" config/description="This is a minimal sample of connecting two peers to each other using websockets." -run/main_scene="res://Main.tscn" -config/features=PackedStringArray("4.0") config/tags=PackedStringArray("demo", "network", "official") +run/main_scene="res://Main.tscn" +config/features=PackedStringArray("4.1") + +[display] + +window/size/viewport_width=600 +window/size/viewport_height=300 [rendering] diff --git a/networking/websocket_minimal/server.gd b/networking/websocket_minimal/server.gd index 10615ad41a..3338082135 100644 --- a/networking/websocket_minimal/server.gd +++ b/networking/websocket_minimal/server.gd @@ -2,59 +2,38 @@ extends Node # The port we will listen to. const PORT = 9080 -# Our WebSocketServer instance. -var _server = WebSocketServer.new() - -func _ready(): - # Connect base signals to get notified of new client connections, - # disconnections, and disconnect requests. - _server.client_connected.connect(self._connected) - _server.client_disconnected.connect(self._disconnected) - _server.client_close_request.connect(self._close_request) - # This signal is emitted when not using the Multiplayer API every time a - # full packet is received. - # Alternatively, you could check get_peer(PEER_ID).get_available_packets() - # in a loop for each connected peer. - _server.data_received.connect(self._on_data) - # Start listening on the given port. - var err = _server.listen(PORT) - if err != OK: - push_error("Unable to start server.") - set_process(false) +var tcp_server := TCPServer.new() +var socket := WebSocketPeer.new() -func _connected(id, proto, rname): - # This is called when a new peer connects, "id" will be the assigned peer id, - # "proto" will be the selected WebSocket sub-protocol (which is optional) - print_rich("Client [b]%d[/b] [color=green]connected[/color] with protocol [b]%s[/b] and resource name [b]%s[/b]" % [id, proto, rname]) +func log_message(message): + var time = "[color=#aaaaaa] %s [/color]" % Time.get_time_string_from_system() + %TextServer.text += time + message + "\n" -func _close_request(id, code, reason): - # This is called when a client notifies that it wishes to close the connection, - # providing a reason string and close code. - print_rich("Client [b]%d[/b] [color=yellow]disconnecting[/color] with code: [b]%d[/b], reason: [b]%s[/b]" % [id, code, reason]) +func _ready(): + if tcp_server.listen(PORT) != OK: + log_message("Unable to start server.") + set_process(false) -func _disconnected(id, was_clean = false): - # This is called when a client disconnects, "id" will be the one of the - # disconnecting client, "was_clean" will tell you if the disconnection - # was correctly notified by the remote peer before closing the socket. - print_rich("Client [b]%d[/b] [color=red]disconnected[/color], clean: [b]%s[/b]" % [id, str(was_clean)]) +func _process(_delta): + while tcp_server.is_connection_available(): + var conn: StreamPeerTCP = tcp_server.take_connection() + assert(conn != null) + socket.accept_stream(conn) + socket.poll() -func _on_data(id): - # Print the received packet, you MUST always use get_peer(id).get_packet to receive data, - # and not get_packet directly when not using the MultiplayerAPI. - var pkt = _server.get_peer(id).get_packet() - print("Got data from client [b]%d[/b]: [b]%s[/b] ... echoing" % [id, pkt.get_string_from_utf8()]) - _server.get_peer(id).put_packet(pkt) + if socket.get_ready_state() == WebSocketPeer.STATE_OPEN: + while socket.get_available_packet_count(): + log_message(socket.get_packet().get_string_from_ascii()) -func _process(_delta): - # Call this in _process or _physics_process. - # Data transfer, and signals emission will only happen when calling this function. - _server.poll() +func _exit_tree(): + socket.close() + tcp_server.stop() -func _exit_tree(): - _server.stop() +func _on_button_pong_pressed(): + socket.send_text("Pong")