Browse Source

Update WebSocket Minimal demo for Godot 4.1 (#990)

Alex 1 year ago
parent
commit
7af99c55ef

+ 69 - 2
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"]

+ 1 - 1
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

+ 18 - 42
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")

+ 7 - 2
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]
 

+ 23 - 44
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")