mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2025-12-31 09:49:06 +03:00
Merge pull request #781 from Faless/update/ws
This commit is contained in:
85
networking/websocket_chat/chat.tscn
Normal file
85
networking/websocket_chat/chat.tscn
Normal file
@@ -0,0 +1,85 @@
|
||||
[gd_scene format=3 uid="uid://cyvrywci15kev"]
|
||||
|
||||
[node name="Chat" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Listen" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_right = 1152.0
|
||||
|
||||
[node name="Connect" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_top = 4.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 35.0
|
||||
|
||||
[node name="Host" type="LineEdit" parent="Panel/VBoxContainer/Connect"]
|
||||
offset_right = 930.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
text = "ws://localhost:8000/test/"
|
||||
placeholder_text = "ws://my.server/path/"
|
||||
|
||||
[node name="Connect" type="Button" parent="Panel/VBoxContainer/Connect"]
|
||||
offset_left = 934.0
|
||||
offset_right = 1006.0
|
||||
offset_bottom = 31.0
|
||||
toggle_mode = true
|
||||
text = "Connect"
|
||||
|
||||
[node name="Port" type="SpinBox" parent="Panel/VBoxContainer/Connect"]
|
||||
offset_left = 1010.0
|
||||
offset_right = 1093.0
|
||||
offset_bottom = 31.0
|
||||
min_value = 1.0
|
||||
max_value = 65535.0
|
||||
value = 8000.0
|
||||
|
||||
[node name="Listen" type="Button" parent="Panel/VBoxContainer/Connect"]
|
||||
offset_left = 1097.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 31.0
|
||||
toggle_mode = true
|
||||
text = "Listen"
|
||||
|
||||
[node name="Send" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_top = 39.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 70.0
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="Panel/VBoxContainer/Send"]
|
||||
offset_right = 1101.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
placeholder_text = "Enter some text to send..."
|
||||
|
||||
[node name="Send" type="Button" parent="Panel/VBoxContainer/Send"]
|
||||
offset_left = 1105.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 31.0
|
||||
text = "Send"
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="Panel/VBoxContainer"]
|
||||
offset_top = 74.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 648.0
|
||||
size_flags_vertical = 3
|
||||
47
networking/websocket_chat/client.gd
Normal file
47
networking/websocket_chat/client.gd
Normal file
@@ -0,0 +1,47 @@
|
||||
extends Control
|
||||
|
||||
@onready var _client : WebSocketClient = $WebSocketClient
|
||||
@onready var _log_dest = $Panel/VBoxContainer/RichTextLabel
|
||||
@onready var _line_edit = $Panel/VBoxContainer/Send/LineEdit
|
||||
@onready var _host = $Panel/VBoxContainer/Connect/Host
|
||||
|
||||
func info(msg):
|
||||
print(msg)
|
||||
_log_dest.add_text(str(msg) + "\n")
|
||||
|
||||
|
||||
# Client signals
|
||||
func _on_web_socket_client_connection_closed():
|
||||
var ws = _client.get_socket()
|
||||
info("Client just disconnected with code: %s, reson: %s" % [ws.get_close_code(), ws.get_close_reason()])
|
||||
|
||||
|
||||
func _on_web_socket_client_connected_to_server():
|
||||
info("Client just connected with protocol: %s" % _client.get_socket().get_selected_protocol())
|
||||
|
||||
|
||||
func _on_web_socket_client_message_received(message):
|
||||
info("%s" % message)
|
||||
|
||||
|
||||
# UI signals.
|
||||
func _on_send_pressed():
|
||||
if _line_edit.text == "":
|
||||
return
|
||||
|
||||
info("Sending message: %s" % [_line_edit.text])
|
||||
_client.send(_line_edit.text)
|
||||
_line_edit.text = ""
|
||||
|
||||
|
||||
func _on_connect_toggled(pressed):
|
||||
if not pressed:
|
||||
_client.close()
|
||||
return
|
||||
if _host.text == "":
|
||||
return
|
||||
info("Connecting to host: %s." % [_host.text])
|
||||
var err = _client.connect_to_url(_host.text)
|
||||
if err != OK:
|
||||
info("Error connecting to host: %s" % [_host.text])
|
||||
return
|
||||
59
networking/websocket_chat/client.tscn
Normal file
59
networking/websocket_chat/client.tscn
Normal file
@@ -0,0 +1,59 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://ph5ghsflqegf"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cyvrywci15kev" path="res://chat.tscn" id="1_cfcun"]
|
||||
[ext_resource type="Script" path="res://websocket/WebSocketClient.gd" id="2_m4g4y"]
|
||||
[ext_resource type="Script" path="res://client.gd" id="2_opbid"]
|
||||
|
||||
[node name="Client" instance=ExtResource("1_cfcun")]
|
||||
script = ExtResource("2_opbid")
|
||||
|
||||
[node name="WebSocketClient" type="Node" parent="." index="0"]
|
||||
script = ExtResource("2_m4g4y")
|
||||
supported_protocols = PackedStringArray("demo-chat")
|
||||
|
||||
[node name="Panel" parent="." index="1"]
|
||||
layout_mode = 1
|
||||
|
||||
[node name="VBoxContainer" parent="Panel" index="0"]
|
||||
layout_mode = 1
|
||||
|
||||
[node name="Listen" parent="Panel/VBoxContainer" index="0"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Connect" parent="Panel/VBoxContainer" index="1"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Host" parent="Panel/VBoxContainer/Connect" index="0"]
|
||||
layout_mode = 2
|
||||
offset_right = 1076.0
|
||||
|
||||
[node name="Connect" parent="Panel/VBoxContainer/Connect" index="1"]
|
||||
layout_mode = 2
|
||||
offset_left = 1080.0
|
||||
offset_right = 1152.0
|
||||
|
||||
[node name="Port" parent="Panel/VBoxContainer/Connect" index="2"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Listen" parent="Panel/VBoxContainer/Connect" index="3"]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Send" parent="Panel/VBoxContainer" index="2"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="LineEdit" parent="Panel/VBoxContainer/Send" index="0"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="Send" parent="Panel/VBoxContainer/Send" index="1"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="RichTextLabel" parent="Panel/VBoxContainer" index="3"]
|
||||
layout_mode = 2
|
||||
|
||||
[connection signal="connected_to_server" from="WebSocketClient" to="." method="_on_web_socket_client_connected_to_server"]
|
||||
[connection signal="connection_closed" from="WebSocketClient" to="." method="_on_web_socket_client_connection_closed"]
|
||||
[connection signal="message_received" from="WebSocketClient" to="." method="_on_web_socket_client_message_received"]
|
||||
[connection signal="toggled" from="Panel/VBoxContainer/Connect/Connect" to="." method="_on_connect_toggled"]
|
||||
[connection signal="pressed" from="Panel/VBoxContainer/Send/Send" to="." method="_on_send_pressed"]
|
||||
@@ -1,84 +0,0 @@
|
||||
extends Node
|
||||
|
||||
@onready var _log_dest = get_parent().get_node(^"Panel/VBoxContainer/RichTextLabel")
|
||||
|
||||
var _client = WebSocketClient.new()
|
||||
var _write_mode = WebSocketPeer.WRITE_MODE_BINARY
|
||||
var _use_multiplayer = true
|
||||
var last_connected_client = 0
|
||||
|
||||
func _init():
|
||||
_client.connect(&"connection_established", self._client_connected)
|
||||
_client.connect(&"connection_error", self._client_disconnected)
|
||||
_client.connect(&"connection_closed", self._client_disconnected)
|
||||
_client.connect(&"server_close_request", self._client_close_request)
|
||||
_client.connect(&"data_received", self._client_received)
|
||||
|
||||
_client.connect(&"peer_packet", self._client_received)
|
||||
_client.connect(&"peer_connected", self._peer_connected)
|
||||
_client.connect(&"connection_succeeded", self._client_connected, ["multiplayer_protocol"])
|
||||
_client.connect(&"connection_failed", self._client_disconnected)
|
||||
|
||||
|
||||
func _client_close_request(code, reason):
|
||||
Utils._log(_log_dest, "Close code: %d, reason: %s" % [code, reason])
|
||||
|
||||
|
||||
func _peer_connected(id):
|
||||
Utils._log(_log_dest, "%s: Client just connected" % id)
|
||||
last_connected_client = id
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
_client.disconnect_from_host(1001, "Bye bye!")
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
if _client.get_connection_status() == WebSocketClient.CONNECTION_DISCONNECTED:
|
||||
return
|
||||
|
||||
_client.poll()
|
||||
|
||||
|
||||
func _client_connected(protocol):
|
||||
Utils._log(_log_dest, "Client just connected with protocol: %s" % protocol)
|
||||
_client.get_peer(1).set_write_mode(_write_mode)
|
||||
|
||||
|
||||
func _client_disconnected(clean=true):
|
||||
Utils._log(_log_dest, "Client just disconnected. Was clean: %s" % clean)
|
||||
|
||||
|
||||
func _client_received(_p_id = 1):
|
||||
if _use_multiplayer:
|
||||
var peer_id = _client.get_packet_peer()
|
||||
var packet = _client.get_packet()
|
||||
Utils._log(_log_dest, "MPAPI: From %s Data: %s" % [str(peer_id), Utils.decode_data(packet, false)])
|
||||
else:
|
||||
var packet = _client.get_peer(1).get_packet()
|
||||
var is_string = _client.get_peer(1).was_string_packet()
|
||||
Utils._log(_log_dest, "Received data. BINARY: %s: %s" % [not is_string, Utils.decode_data(packet, is_string)])
|
||||
|
||||
|
||||
func connect_to_url(host, protocols, multiplayer):
|
||||
_use_multiplayer = multiplayer
|
||||
if _use_multiplayer:
|
||||
_write_mode = WebSocketPeer.WRITE_MODE_BINARY
|
||||
return _client.connect_to_url(host, protocols, multiplayer)
|
||||
|
||||
|
||||
func disconnect_from_host():
|
||||
_client.disconnect_from_host(1000, "Bye bye!")
|
||||
|
||||
|
||||
func send_data(data, dest):
|
||||
_client.get_peer(1).set_write_mode(_write_mode)
|
||||
if _use_multiplayer:
|
||||
_client.set_target_peer(dest)
|
||||
_client.put_packet(Utils.encode_data(data, _write_mode))
|
||||
else:
|
||||
_client.get_peer(1).put_packet(Utils.encode_data(data, _write_mode))
|
||||
|
||||
|
||||
func set_write_mode(mode):
|
||||
_write_mode = mode
|
||||
@@ -1,89 +0,0 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://client/client_ui.gd" type="Script" id=1]
|
||||
[ext_resource path="res://client/client.gd" type="Script" id=2]
|
||||
|
||||
[node name="Client" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="Connect" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 24.0
|
||||
|
||||
[node name="Host" type="LineEdit" parent="Panel/VBoxContainer/Connect"]
|
||||
offset_right = 956.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
text = "ws://localhost:8000/test/"
|
||||
placeholder_text = "ws://my.server/path/"
|
||||
|
||||
[node name="Connect" type="Button" parent="Panel/VBoxContainer/Connect"]
|
||||
offset_left = 960.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 24.0
|
||||
toggle_mode = true
|
||||
text = "Connect"
|
||||
|
||||
[node name="Settings" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_top = 28.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 52.0
|
||||
|
||||
[node name="Mode" type="OptionButton" parent="Panel/VBoxContainer/Settings"]
|
||||
offset_right = 29.0
|
||||
offset_bottom = 24.0
|
||||
|
||||
[node name="Multiplayer" type="CheckBox" parent="Panel/VBoxContainer/Settings"]
|
||||
offset_left = 33.0
|
||||
offset_right = 159.0
|
||||
offset_bottom = 24.0
|
||||
pressed = true
|
||||
text = "Multiplayer API"
|
||||
|
||||
[node name="Destination" type="OptionButton" parent="Panel/VBoxContainer/Settings"]
|
||||
offset_left = 163.0
|
||||
offset_right = 192.0
|
||||
offset_bottom = 24.0
|
||||
|
||||
[node name="Send" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_top = 56.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 80.0
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="Panel/VBoxContainer/Send"]
|
||||
offset_right = 977.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
placeholder_text = "Enter some text to send..."
|
||||
|
||||
[node name="Send" type="Button" parent="Panel/VBoxContainer/Send"]
|
||||
offset_left = 981.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 24.0
|
||||
text = "Send"
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="Panel/VBoxContainer"]
|
||||
offset_top = 84.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 600.0
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Client" type="Node" parent="."]
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[connection signal="toggled" from="Panel/VBoxContainer/Connect/Connect" to="." method="_on_Connect_toggled"]
|
||||
[connection signal="item_selected" from="Panel/VBoxContainer/Settings/Mode" to="." method="_on_Mode_item_selected"]
|
||||
[connection signal="pressed" from="Panel/VBoxContainer/Send/Send" to="." method="_on_Send_pressed"]
|
||||
@@ -1,62 +0,0 @@
|
||||
extends Control
|
||||
|
||||
@onready var _client = $Client
|
||||
@onready var _log_dest = $Panel/VBoxContainer/RichTextLabel
|
||||
@onready var _line_edit = $Panel/VBoxContainer/Send/LineEdit
|
||||
@onready var _host = $Panel/VBoxContainer/Connect/Host
|
||||
@onready var _multiplayer = $Panel/VBoxContainer/Settings/Multiplayer
|
||||
@onready var _write_mode = $Panel/VBoxContainer/Settings/Mode
|
||||
@onready var _destination = $Panel/VBoxContainer/Settings/Destination
|
||||
|
||||
func _ready():
|
||||
_write_mode.clear()
|
||||
_write_mode.add_item("BINARY")
|
||||
_write_mode.set_item_metadata(0, WebSocketPeer.WRITE_MODE_BINARY)
|
||||
_write_mode.add_item("TEXT")
|
||||
_write_mode.set_item_metadata(1, WebSocketPeer.WRITE_MODE_TEXT)
|
||||
|
||||
_destination.add_item("Broadcast")
|
||||
_destination.set_item_metadata(0, 0)
|
||||
_destination.add_item("Last connected")
|
||||
_destination.set_item_metadata(1, 1)
|
||||
_destination.add_item("All But last connected")
|
||||
_destination.set_item_metadata(2, -1)
|
||||
_destination.select(0)
|
||||
|
||||
|
||||
func _on_Mode_item_selected(_id):
|
||||
_client.set_write_mode(_write_mode.get_selected_metadata())
|
||||
|
||||
|
||||
func _on_Send_pressed():
|
||||
if _line_edit.text == "":
|
||||
return
|
||||
|
||||
var dest = _destination.get_selected_metadata()
|
||||
if dest > 0:
|
||||
dest = _client.last_connected_client
|
||||
elif dest < 0:
|
||||
dest = -_client.last_connected_client
|
||||
|
||||
Utils._log(_log_dest, "Sending data %s to %s" % [_line_edit.text, dest])
|
||||
_client.send_data(_line_edit.text, dest)
|
||||
_line_edit.text = ""
|
||||
|
||||
|
||||
func _on_Connect_toggled( pressed ):
|
||||
if pressed:
|
||||
var multiplayer = _multiplayer.pressed
|
||||
if multiplayer:
|
||||
_write_mode.disabled = true
|
||||
else:
|
||||
_destination.disabled = true
|
||||
_multiplayer.disabled = true
|
||||
if _host.text != "":
|
||||
Utils._log(_log_dest, "Connecting to host: %s" % [_host.text])
|
||||
var supported_protocols = PackedStringArray(["my-protocol2", "my-protocol", "binary"])
|
||||
_client.connect_to_url(_host.text, supported_protocols, multiplayer)
|
||||
else:
|
||||
_destination.disabled = false
|
||||
_write_mode.disabled = false
|
||||
_multiplayer.disabled = false
|
||||
_client.disconnect_from_host()
|
||||
56
networking/websocket_chat/combo.tscn
Normal file
56
networking/websocket_chat/combo.tscn
Normal file
@@ -0,0 +1,56 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://dye16x7udqrxg"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://qvg4q16blgx5" path="res://server.tscn" id="1_0srxc"]
|
||||
[ext_resource type="PackedScene" uid="uid://ph5ghsflqegf" path="res://client.tscn" id="2_percb"]
|
||||
|
||||
[node name="Combo" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 1
|
||||
|
||||
[node name="Box" type="HBoxContainer" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Server" parent="Box" instance=ExtResource("1_0srxc")]
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_right = 574.0
|
||||
offset_bottom = 648.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Box"]
|
||||
offset_left = 578.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 648.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Client" parent="Box/VBoxContainer" instance=ExtResource("2_percb")]
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_right = 574.0
|
||||
offset_bottom = 213.0
|
||||
|
||||
[node name="Client2" parent="Box/VBoxContainer" instance=ExtResource("2_percb")]
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_top = 217.0
|
||||
offset_right = 574.0
|
||||
offset_bottom = 430.0
|
||||
|
||||
[node name="Client3" parent="Box/VBoxContainer" instance=ExtResource("2_percb")]
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_top = 434.0
|
||||
offset_right = 574.0
|
||||
offset_bottom = 648.0
|
||||
@@ -1,53 +0,0 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://server/server.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://client/client.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="Combo" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 1
|
||||
|
||||
[node name="Box" type="HBoxContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
custom_constants/separation = 20
|
||||
|
||||
[node name="ServerControl" parent="Box" instance=ExtResource( 1 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_right = 502.0
|
||||
offset_bottom = 600.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Box"]
|
||||
offset_left = 522.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 600.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Client" parent="Box/VBoxContainer" instance=ExtResource( 2 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_right = 502.0
|
||||
offset_bottom = 197.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Client2" parent="Box/VBoxContainer" instance=ExtResource( 2 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_top = 201.0
|
||||
offset_right = 502.0
|
||||
offset_bottom = 398.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Client3" parent="Box/VBoxContainer" instance=ExtResource( 2 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_top = 402.0
|
||||
offset_right = 502.0
|
||||
offset_bottom = 600.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
@@ -1,8 +1,9 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture2D"
|
||||
path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://db0a1leye11ap"
|
||||
path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
@@ -10,26 +11,24 @@ metadata={
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"]
|
||||
dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/hdr_compression=1
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
|
||||
@@ -6,19 +6,32 @@
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=4
|
||||
config_version=5
|
||||
|
||||
_global_script_classes=[{
|
||||
"base": "Node",
|
||||
"class": &"WebSocketClient",
|
||||
"language": &"GDScript",
|
||||
"path": "res://websocket/WebSocketClient.gd"
|
||||
}, {
|
||||
"base": "Node",
|
||||
"class": &"WebSocketServer",
|
||||
"language": &"GDScript",
|
||||
"path": "res://websocket/WebSocketServer.gd"
|
||||
}]
|
||||
_global_script_class_icons={
|
||||
"WebSocketClient": "",
|
||||
"WebSocketServer": ""
|
||||
}
|
||||
|
||||
[application]
|
||||
|
||||
config/name="WebSocket Chat Demo"
|
||||
config/description="This is a demo of a simple chat implemented using WebSockets, showing both how to host a websocket server from Godot and how to connect to it."
|
||||
run/main_scene="res://combo/combo.tscn"
|
||||
run/main_scene="res://combo.tscn"
|
||||
config/features=PackedStringArray("4.0")
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[autoload]
|
||||
|
||||
Utils="*res://utils.gd"
|
||||
|
||||
[gdnative]
|
||||
|
||||
singletons=[]
|
||||
|
||||
51
networking/websocket_chat/server.gd
Normal file
51
networking/websocket_chat/server.gd
Normal file
@@ -0,0 +1,51 @@
|
||||
extends Control
|
||||
|
||||
@onready var _server : WebSocketServer = $WebSocketServer
|
||||
@onready var _log_dest = $Panel/VBoxContainer/RichTextLabel
|
||||
@onready var _line_edit = $Panel/VBoxContainer/Send/LineEdit
|
||||
@onready var _listen_port = $Panel/VBoxContainer/Connect/Port
|
||||
|
||||
func info(msg):
|
||||
print(msg)
|
||||
_log_dest.add_text(str(msg) + "\n")
|
||||
|
||||
|
||||
# Server signals
|
||||
func _on_web_socket_server_client_connected(peer_id):
|
||||
var peer : WebSocketPeer = _server.peers[peer_id]
|
||||
info("Remote client connected: %d. Protocol: %s" % [peer_id, peer.get_selected_protocol()])
|
||||
_server.send(-peer_id, "[%d] connected" % peer_id)
|
||||
|
||||
|
||||
func _on_web_socket_server_client_disconnected(peer_id):
|
||||
var peer : WebSocketPeer = _server.peers[peer_id]
|
||||
info("Remote client disconnected: %d. Code: %d, Reason: %s" % [peer_id, peer.get_close_code(), peer.get_close_reason()])
|
||||
_server.send(-peer_id, "[%d] disconnected" % peer_id)
|
||||
|
||||
|
||||
func _on_web_socket_server_message_received(peer_id, message):
|
||||
info("Server received data from peer %d: %s" % [peer_id, message])
|
||||
_server.send(-peer_id, "[%d] Says: %s" % [peer_id, message])
|
||||
|
||||
|
||||
# UI signals.
|
||||
func _on_send_pressed():
|
||||
if _line_edit.text == "":
|
||||
return
|
||||
|
||||
info("Sending message: %s" % [_line_edit.text])
|
||||
_server.send(0, "Server says: %s" % _line_edit.text)
|
||||
_line_edit.text = ""
|
||||
|
||||
|
||||
func _on_listen_toggled(pressed):
|
||||
if not pressed:
|
||||
_server.stop()
|
||||
info("Server stopped")
|
||||
return
|
||||
var port = int(_listen_port.value)
|
||||
var err = _server.listen(port)
|
||||
if err != OK:
|
||||
info("Error listing on port %s" % port)
|
||||
return
|
||||
info("Listing on port %s, supported protocols: %s" % [port, _server.supported_protocols])
|
||||
61
networking/websocket_chat/server.tscn
Normal file
61
networking/websocket_chat/server.tscn
Normal file
@@ -0,0 +1,61 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://qvg4q16blgx5"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cyvrywci15kev" path="res://chat.tscn" id="1_i673i"]
|
||||
[ext_resource type="Script" path="res://server.gd" id="1_urpfw"]
|
||||
[ext_resource type="Script" path="res://websocket/WebSocketServer.gd" id="3_0eqsy"]
|
||||
|
||||
[node name="Server" instance=ExtResource("1_i673i")]
|
||||
script = ExtResource("1_urpfw")
|
||||
|
||||
[node name="WebSocketServer" type="Node" parent="." index="0"]
|
||||
script = ExtResource("3_0eqsy")
|
||||
supported_protocols = PackedStringArray("demo-chat")
|
||||
|
||||
[node name="Panel" parent="." index="1"]
|
||||
layout_mode = 3
|
||||
|
||||
[node name="VBoxContainer" parent="Panel" index="0"]
|
||||
layout_mode = 3
|
||||
|
||||
[node name="Listen" parent="Panel/VBoxContainer" index="0"]
|
||||
layout_mode = 3
|
||||
|
||||
[node name="Connect" parent="Panel/VBoxContainer" index="1"]
|
||||
layout_mode = 3
|
||||
|
||||
[node name="Host" parent="Panel/VBoxContainer/Connect" index="0"]
|
||||
visible = false
|
||||
layout_mode = 3
|
||||
offset_right = 1006.0
|
||||
|
||||
[node name="Connect" parent="Panel/VBoxContainer/Connect" index="1"]
|
||||
visible = false
|
||||
layout_mode = 3
|
||||
|
||||
[node name="Port" parent="Panel/VBoxContainer/Connect" index="2"]
|
||||
layout_mode = 3
|
||||
offset_left = 0.0
|
||||
offset_right = 83.0
|
||||
|
||||
[node name="Listen" parent="Panel/VBoxContainer/Connect" index="3"]
|
||||
layout_mode = 3
|
||||
offset_left = 87.0
|
||||
offset_right = 142.0
|
||||
|
||||
[node name="Send" parent="Panel/VBoxContainer" index="2"]
|
||||
layout_mode = 3
|
||||
|
||||
[node name="LineEdit" parent="Panel/VBoxContainer/Send" index="0"]
|
||||
layout_mode = 3
|
||||
|
||||
[node name="Send" parent="Panel/VBoxContainer/Send" index="1"]
|
||||
layout_mode = 3
|
||||
|
||||
[node name="RichTextLabel" parent="Panel/VBoxContainer" index="3"]
|
||||
layout_mode = 3
|
||||
|
||||
[connection signal="client_connected" from="WebSocketServer" to="." method="_on_web_socket_server_client_connected"]
|
||||
[connection signal="client_disconnected" from="WebSocketServer" to="." method="_on_web_socket_server_client_disconnected"]
|
||||
[connection signal="message_received" from="WebSocketServer" to="." method="_on_web_socket_server_message_received"]
|
||||
[connection signal="toggled" from="Panel/VBoxContainer/Connect/Listen" to="." method="_on_listen_toggled"]
|
||||
[connection signal="pressed" from="Panel/VBoxContainer/Send/Send" to="." method="_on_send_pressed"]
|
||||
@@ -1,84 +0,0 @@
|
||||
extends Node
|
||||
|
||||
@onready var _log_dest = get_parent().get_node(^"Panel/VBoxContainer/RichTextLabel")
|
||||
|
||||
var _server = WebSocketServer.new()
|
||||
var _clients = {}
|
||||
var _write_mode = WebSocketPeer.WRITE_MODE_BINARY
|
||||
var _use_multiplayer = true
|
||||
var last_connected_client = 0
|
||||
|
||||
func _init():
|
||||
_server.connect(&"client_connected", self._client_connected)
|
||||
_server.connect(&"client_disconnected", self._client_disconnected)
|
||||
_server.connect(&"client_close_request", self._client_close_request)
|
||||
_server.connect(&"data_received", self._client_receive)
|
||||
|
||||
_server.connect(&"peer_packet", self._client_receive)
|
||||
_server.connect(&"peer_connected", self._client_connected, ["multiplayer_protocol"])
|
||||
_server.connect(&"peer_disconnected", self._client_disconnected)
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
_clients.clear()
|
||||
_server.stop()
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
if _server.is_listening():
|
||||
_server.poll()
|
||||
|
||||
|
||||
func _client_close_request(id, code, reason):
|
||||
print(reason == "Bye bye!")
|
||||
Utils._log(_log_dest, "Client %s close code: %d, reason: %s" % [id, code, reason])
|
||||
|
||||
|
||||
func _client_connected(id, protocol):
|
||||
_clients[id] = _server.get_peer(id)
|
||||
_clients[id].set_write_mode(_write_mode)
|
||||
last_connected_client = id
|
||||
Utils._log(_log_dest, "%s: Client connected with protocol %s" % [id, protocol])
|
||||
|
||||
|
||||
func _client_disconnected(id, clean = true):
|
||||
Utils._log(_log_dest, "Client %s disconnected. Was clean: %s" % [id, clean])
|
||||
if _clients.has(id):
|
||||
_clients.erase(id)
|
||||
|
||||
|
||||
func _client_receive(id):
|
||||
if _use_multiplayer:
|
||||
var peer_id = _server.get_packet_peer()
|
||||
var packet = _server.get_packet()
|
||||
Utils._log(_log_dest, "MPAPI: From %s data: %s" % [peer_id, Utils.decode_data(packet, false)])
|
||||
else:
|
||||
var packet = _server.get_peer(id).get_packet()
|
||||
var is_string = _server.get_peer(id).was_string_packet()
|
||||
Utils._log(_log_dest, "Data from %s BINARY: %s: %s" % [id, not is_string, Utils.decode_data(packet, is_string)])
|
||||
|
||||
|
||||
func send_data(data, dest):
|
||||
if _use_multiplayer:
|
||||
_server.set_target_peer(dest)
|
||||
_server.put_packet(Utils.encode_data(data, _write_mode))
|
||||
else:
|
||||
for id in _clients:
|
||||
_server.get_peer(id).put_packet(Utils.encode_data(data, _write_mode))
|
||||
|
||||
|
||||
func listen(port, supported_protocols, multiplayer):
|
||||
_use_multiplayer = multiplayer
|
||||
if _use_multiplayer:
|
||||
set_write_mode(WebSocketPeer.WRITE_MODE_BINARY)
|
||||
return _server.listen(port, supported_protocols, multiplayer)
|
||||
|
||||
|
||||
func stop():
|
||||
_server.stop()
|
||||
|
||||
|
||||
func set_write_mode(mode):
|
||||
_write_mode = mode
|
||||
for c in _clients:
|
||||
_clients[c].set_write_mode(_write_mode)
|
||||
@@ -1,88 +0,0 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://server/server_ui.gd" type="Script" id=1]
|
||||
[ext_resource path="res://server/server.gd" type="Script" id=2]
|
||||
|
||||
[node name="ServerControl" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Server" type="Node" parent="."]
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 24.0
|
||||
|
||||
[node name="Port" type="SpinBox" parent="Panel/VBoxContainer/HBoxContainer"]
|
||||
offset_right = 74.0
|
||||
offset_bottom = 24.0
|
||||
min_value = 1.0
|
||||
max_value = 65535.0
|
||||
value = 8000.0
|
||||
|
||||
[node name="Listen" type="Button" parent="Panel/VBoxContainer/HBoxContainer"]
|
||||
offset_left = 78.0
|
||||
offset_right = 129.0
|
||||
offset_bottom = 24.0
|
||||
toggle_mode = true
|
||||
text = "Listen"
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_top = 28.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 52.0
|
||||
|
||||
[node name="WriteMode" type="OptionButton" parent="Panel/VBoxContainer/HBoxContainer2"]
|
||||
offset_right = 29.0
|
||||
offset_bottom = 24.0
|
||||
|
||||
[node name="MPAPI" type="CheckBox" parent="Panel/VBoxContainer/HBoxContainer2"]
|
||||
offset_left = 33.0
|
||||
offset_right = 159.0
|
||||
offset_bottom = 24.0
|
||||
pressed = true
|
||||
text = "Multiplayer API"
|
||||
|
||||
[node name="Destination" type="OptionButton" parent="Panel/VBoxContainer/HBoxContainer2"]
|
||||
offset_left = 163.0
|
||||
offset_right = 192.0
|
||||
offset_bottom = 24.0
|
||||
|
||||
[node name="HBoxContainer3" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_top = 56.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 80.0
|
||||
|
||||
[node name="LineEdit" type="LineEdit" parent="Panel/VBoxContainer/HBoxContainer3"]
|
||||
offset_right = 977.0
|
||||
offset_bottom = 24.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Send" type="Button" parent="Panel/VBoxContainer/HBoxContainer3"]
|
||||
offset_left = 981.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 24.0
|
||||
text = "Send"
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="Panel/VBoxContainer"]
|
||||
offset_top = 84.0
|
||||
offset_right = 1024.0
|
||||
offset_bottom = 600.0
|
||||
size_flags_vertical = 3
|
||||
|
||||
[connection signal="toggled" from="Panel/VBoxContainer/HBoxContainer/Listen" to="." method="_on_Listen_toggled"]
|
||||
[connection signal="item_selected" from="Panel/VBoxContainer/HBoxContainer2/WriteMode" to="." method="_on_WriteMode_item_selected"]
|
||||
[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer3/Send" to="." method="_on_Send_pressed"]
|
||||
@@ -1,70 +0,0 @@
|
||||
extends Control
|
||||
|
||||
@onready var _server = $Server
|
||||
@onready var _port = $Panel/VBoxContainer/HBoxContainer/Port
|
||||
@onready var _line_edit = $Panel/VBoxContainer/HBoxContainer3/LineEdit
|
||||
@onready var _write_mode = $Panel/VBoxContainer/HBoxContainer2/WriteMode
|
||||
@onready var _log_dest = $Panel/VBoxContainer/RichTextLabel
|
||||
@onready var _multiplayer = $Panel/VBoxContainer/HBoxContainer2/MPAPI
|
||||
@onready var _destination = $Panel/VBoxContainer/HBoxContainer2/Destination
|
||||
|
||||
func _ready():
|
||||
_write_mode.clear()
|
||||
_write_mode.add_item("BINARY")
|
||||
_write_mode.set_item_metadata(0, WebSocketPeer.WRITE_MODE_BINARY)
|
||||
_write_mode.add_item("TEXT")
|
||||
_write_mode.set_item_metadata(1, WebSocketPeer.WRITE_MODE_TEXT)
|
||||
_write_mode.select(0)
|
||||
|
||||
_destination.add_item("Broadcast")
|
||||
_destination.set_item_metadata(0, 0)
|
||||
_destination.add_item("Last connected")
|
||||
_destination.set_item_metadata(1, 1)
|
||||
_destination.add_item("All But last connected")
|
||||
_destination.set_item_metadata(2, -1)
|
||||
_destination.select(0)
|
||||
|
||||
|
||||
func _on_Listen_toggled(pressed):
|
||||
if pressed:
|
||||
var use_multiplayer = _multiplayer.pressed
|
||||
_multiplayer.disabled = true
|
||||
var supported_protocols = PackedStringArray(["my-protocol", "binary"])
|
||||
var port = int(_port.value)
|
||||
if use_multiplayer:
|
||||
_write_mode.disabled = true
|
||||
_write_mode.select(0)
|
||||
else:
|
||||
_destination.disabled = true
|
||||
_destination.select(0)
|
||||
if _server.listen(port, supported_protocols, use_multiplayer) == OK:
|
||||
Utils._log(_log_dest, "Listing on port %s" % port)
|
||||
if not use_multiplayer:
|
||||
Utils._log(_log_dest, "Supported protocols: %s" % supported_protocols)
|
||||
else:
|
||||
Utils._log(_log_dest, "Error listening on port %s" % port)
|
||||
else:
|
||||
_server.stop()
|
||||
_multiplayer.disabled = false
|
||||
_write_mode.disabled = false
|
||||
_destination.disabled = false
|
||||
Utils._log(_log_dest, "Server stopped")
|
||||
|
||||
|
||||
func _on_Send_pressed():
|
||||
if _line_edit.text == "":
|
||||
return
|
||||
|
||||
var dest = _destination.get_selected_metadata()
|
||||
if dest > 0:
|
||||
dest = _server.last_connected_client
|
||||
elif dest < 0:
|
||||
dest = -_server.last_connected_client
|
||||
|
||||
Utils._log(_log_dest, "Sending data %s to %s" % [_line_edit.text, dest])
|
||||
_server.send_data(_line_edit.text, dest)
|
||||
_line_edit.text = ""
|
||||
|
||||
|
||||
func _on_WriteMode_item_selected(_id):
|
||||
_server.set_write_mode(_write_mode.get_selected_metadata())
|
||||
@@ -1,17 +0,0 @@
|
||||
extends Node
|
||||
|
||||
func encode_data(data, mode):
|
||||
if mode == WebSocketPeer.WRITE_MODE_TEXT:
|
||||
return data.to_utf8()
|
||||
return var2bytes(data)
|
||||
|
||||
|
||||
func decode_data(data, is_string):
|
||||
if is_string:
|
||||
return data.get_string_from_utf8()
|
||||
return bytes2var(data)
|
||||
|
||||
|
||||
func _log(node, msg):
|
||||
print(msg)
|
||||
node.add_text(str(msg) + "\n")
|
||||
73
networking/websocket_chat/websocket/WebSocketClient.gd
Normal file
73
networking/websocket_chat/websocket/WebSocketClient.gd
Normal file
@@ -0,0 +1,73 @@
|
||||
extends Node
|
||||
class_name WebSocketClient
|
||||
|
||||
@export var handshake_headers : PackedStringArray
|
||||
@export var supported_protocols : PackedStringArray
|
||||
@export var tls_trusted_certificate : X509Certificate
|
||||
@export var tls_verify := true
|
||||
|
||||
|
||||
var socket = WebSocketPeer.new()
|
||||
var last_state = WebSocketPeer.STATE_CLOSED
|
||||
|
||||
|
||||
signal connected_to_server()
|
||||
signal connection_closed()
|
||||
signal message_received(message: Variant)
|
||||
|
||||
|
||||
func connect_to_url(url) -> int:
|
||||
socket.supported_protocols = supported_protocols
|
||||
socket.handshake_headers = handshake_headers
|
||||
var err = socket.connect_to_url(url, tls_verify, tls_trusted_certificate)
|
||||
if err != OK:
|
||||
return err
|
||||
last_state = socket.get_ready_state()
|
||||
return OK
|
||||
|
||||
|
||||
func send(message) -> int:
|
||||
if typeof(message) == TYPE_STRING:
|
||||
return socket.send_text(message)
|
||||
return socket.send(var_to_bytes(message))
|
||||
|
||||
|
||||
func get_message() -> Variant:
|
||||
if socket.get_available_packet_count() < 1:
|
||||
return null
|
||||
var pkt = socket.get_packet()
|
||||
if socket.was_string_packet():
|
||||
return pkt.get_string_from_utf8()
|
||||
return bytes_to_var(pkt)
|
||||
|
||||
|
||||
func close(code := 1000, reason := "") -> void:
|
||||
socket.close(code, reason)
|
||||
last_state = socket.get_ready_state()
|
||||
|
||||
|
||||
func clear() -> void:
|
||||
socket = WebSocketPeer.new()
|
||||
last_state = socket.get_ready_state()
|
||||
|
||||
|
||||
func get_socket() -> WebSocketPeer:
|
||||
return socket
|
||||
|
||||
|
||||
func poll() -> void:
|
||||
if socket.get_ready_state() != socket.STATE_CLOSED:
|
||||
socket.poll()
|
||||
var state = socket.get_ready_state()
|
||||
if last_state != state:
|
||||
last_state = state
|
||||
if state == socket.STATE_OPEN:
|
||||
connected_to_server.emit()
|
||||
elif state == socket.STATE_CLOSED:
|
||||
connection_closed.emit()
|
||||
while socket.get_ready_state() == socket.STATE_OPEN and socket.get_available_packet_count():
|
||||
message_received.emit(get_message())
|
||||
|
||||
|
||||
func _process(delta):
|
||||
poll()
|
||||
162
networking/websocket_chat/websocket/WebSocketServer.gd
Normal file
162
networking/websocket_chat/websocket/WebSocketServer.gd
Normal file
@@ -0,0 +1,162 @@
|
||||
extends Node
|
||||
class_name WebSocketServer
|
||||
|
||||
signal message_received(peer_id : int, message)
|
||||
signal client_connected(peer_id : int)
|
||||
signal client_disconnected(peer_id : int)
|
||||
|
||||
@export var handshake_headers := PackedStringArray()
|
||||
@export var supported_protocols : PackedStringArray
|
||||
@export var handshake_timout := 3000
|
||||
@export var use_tls := false
|
||||
@export var tls_cert : X509Certificate
|
||||
@export var tls_key : CryptoKey
|
||||
@export var refuse_new_connections := false :
|
||||
set(refuse):
|
||||
if refuse:
|
||||
pending_peers.clear()
|
||||
|
||||
|
||||
class PendingPeer:
|
||||
var connect_time : int
|
||||
var tcp : StreamPeerTCP
|
||||
var connection : StreamPeer
|
||||
var ws : WebSocketPeer
|
||||
|
||||
func _init(p_tcp: StreamPeerTCP):
|
||||
tcp = p_tcp
|
||||
connection = p_tcp
|
||||
connect_time = Time.get_ticks_msec()
|
||||
|
||||
|
||||
var tcp_server := TCPServer.new()
|
||||
var pending_peers : Array[PendingPeer] = []
|
||||
var peers : Dictionary
|
||||
|
||||
|
||||
func listen(port : int) -> int:
|
||||
assert(not tcp_server.is_listening())
|
||||
return tcp_server.listen(port)
|
||||
|
||||
|
||||
func stop():
|
||||
tcp_server.stop()
|
||||
pending_peers.clear()
|
||||
peers.clear()
|
||||
|
||||
|
||||
func send(peer_id, message) -> int:
|
||||
var type = typeof(message)
|
||||
if peer_id <= 0:
|
||||
# Send to multiple peers, (zero = brodcast, negative = exclude one)
|
||||
for id in peers:
|
||||
if id == -peer_id:
|
||||
continue
|
||||
if type == TYPE_STRING:
|
||||
peers[id].send_text(message)
|
||||
else:
|
||||
peers[id].put_packet(message)
|
||||
return OK
|
||||
|
||||
assert(peers.has(peer_id))
|
||||
var socket = peers[peer_id]
|
||||
if type == TYPE_STRING:
|
||||
return socket.send_text(message)
|
||||
return socket.send(var_to_bytes(message))
|
||||
|
||||
|
||||
func get_message(peer_id) -> Variant:
|
||||
assert(peers.has(peer_id))
|
||||
var socket = peers[peer_id]
|
||||
if socket.get_available_packet_count() < 1:
|
||||
return null
|
||||
var pkt = socket.get_packet()
|
||||
if socket.was_string_packet():
|
||||
return pkt.get_string_from_utf8()
|
||||
return bytes_to_var(pkt)
|
||||
|
||||
|
||||
func has_message(peer_id) -> bool:
|
||||
assert(peers.has(peer_id))
|
||||
return peers[peer_id].get_available_packet_count() > 0
|
||||
|
||||
|
||||
func _create_peer() -> WebSocketPeer:
|
||||
var ws = WebSocketPeer.new()
|
||||
ws.supported_protocols = supported_protocols
|
||||
ws.handshake_headers = handshake_headers
|
||||
return ws
|
||||
|
||||
|
||||
func poll() -> void:
|
||||
if not tcp_server.is_listening():
|
||||
return
|
||||
while not refuse_new_connections and tcp_server.is_connection_available():
|
||||
var conn = tcp_server.take_connection()
|
||||
assert(conn != null)
|
||||
pending_peers.append(PendingPeer.new(conn))
|
||||
var to_remove := []
|
||||
for p in pending_peers:
|
||||
if not _connect_pending(p):
|
||||
if p.connect_time + handshake_timout < Time.get_ticks_msec():
|
||||
# Timeout
|
||||
to_remove.append(p)
|
||||
continue # Still pending
|
||||
to_remove.append(p)
|
||||
for r in to_remove:
|
||||
pending_peers.erase(r)
|
||||
to_remove.clear()
|
||||
for id in peers:
|
||||
var p : WebSocketPeer = peers[id]
|
||||
var packets = p.get_available_packet_count()
|
||||
p.poll()
|
||||
if p.get_ready_state() != WebSocketPeer.STATE_OPEN:
|
||||
client_disconnected.emit(id)
|
||||
to_remove.append(id)
|
||||
continue
|
||||
while p.get_available_packet_count():
|
||||
message_received.emit(id, get_message(id))
|
||||
for r in to_remove:
|
||||
peers.erase(r)
|
||||
to_remove.clear()
|
||||
|
||||
|
||||
func _connect_pending(p: PendingPeer) -> bool:
|
||||
if p.ws != null:
|
||||
# Poll websocket client if doing handshake
|
||||
p.ws.poll()
|
||||
var state = p.ws.get_ready_state()
|
||||
if state == WebSocketPeer.STATE_OPEN:
|
||||
var id = randi_range(2, 1 << 30)
|
||||
peers[id] = p.ws
|
||||
client_connected.emit(id)
|
||||
return true # Success.
|
||||
elif state != WebSocketPeer.STATE_CONNECTING:
|
||||
return true # Failure.
|
||||
return false # Still connecting.
|
||||
elif p.tcp.get_status() != StreamPeerTCP.STATUS_CONNECTED:
|
||||
return true # TCP disconnected.
|
||||
elif not use_tls:
|
||||
# TCP is ready, create WS peer
|
||||
p.ws = _create_peer()
|
||||
p.ws.accept_stream(p.tcp)
|
||||
return false # WebSocketPeer connection is pending.
|
||||
else:
|
||||
if p.connection == p.tcp:
|
||||
assert(tls_key != null and tls_cert != null)
|
||||
var tls = StreamPeerTLS.new()
|
||||
tls.accept_stream(p.tcp, tls_key, tls_cert)
|
||||
p.connection = tls
|
||||
p.connection.poll()
|
||||
var status = p.connection.get_status()
|
||||
if status == StreamPeerTLS.STATUS_CONNECTED:
|
||||
p.ws = _create_peer()
|
||||
p.ws.accept_stream(p.connection)
|
||||
return false # WebSocketPeer connection is pending.
|
||||
if status != StreamPeerTLS.STATUS_HANDSHAKING:
|
||||
return true # Failure.
|
||||
return false
|
||||
|
||||
|
||||
func _process(delta):
|
||||
poll()
|
||||
@@ -6,13 +6,14 @@
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=4
|
||||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="WebSocket Multiplayer Demo"
|
||||
config/description="This is a sample showing how the use WebSockets along with the Multiplayer API in Godot."
|
||||
run/main_scene="res://scene/main.tscn"
|
||||
run/main_scene="res://scene/combo.tscn"
|
||||
config/features=PackedStringArray("4.0")
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[rendering]
|
||||
|
||||
66
networking/websocket_multiplayer/scene/combo.tscn
Normal file
66
networking/websocket_multiplayer/scene/combo.tscn
Normal file
@@ -0,0 +1,66 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://cwmhra3pt1h83"]
|
||||
|
||||
[ext_resource type="Script" path="res://script/combo.gd" id="1_8i0ov"]
|
||||
[ext_resource type="PackedScene" uid="uid://c240icwf4uov8" path="res://scene/main.tscn" id="2_reiiv"]
|
||||
|
||||
[node name="Combo" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_8i0ov")
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
columns = 2
|
||||
|
||||
[node name="Main" parent="GridContainer" instance=ExtResource("2_reiiv")]
|
||||
layout_mode = 2
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_right = 574.0
|
||||
offset_bottom = 322.0
|
||||
grow_horizontal = 1
|
||||
grow_vertical = 1
|
||||
|
||||
[node name="Main2" parent="GridContainer" instance=ExtResource("2_reiiv")]
|
||||
layout_mode = 2
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 578.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 322.0
|
||||
grow_horizontal = 1
|
||||
grow_vertical = 1
|
||||
|
||||
[node name="Main3" parent="GridContainer" instance=ExtResource("2_reiiv")]
|
||||
layout_mode = 2
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_top = 326.0
|
||||
offset_right = 574.0
|
||||
offset_bottom = 648.0
|
||||
grow_horizontal = 1
|
||||
grow_vertical = 1
|
||||
|
||||
[node name="Main4" parent="GridContainer" instance=ExtResource("2_reiiv")]
|
||||
layout_mode = 2
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_left = 578.0
|
||||
offset_top = 326.0
|
||||
offset_right = 1152.0
|
||||
offset_bottom = 648.0
|
||||
grow_horizontal = 1
|
||||
grow_vertical = 1
|
||||
@@ -1,72 +1,83 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
[gd_scene load_steps=3 format=3 uid="uid://c240icwf4uov8"]
|
||||
|
||||
[ext_resource path="res://script/main.gd" type="Script" id=1]
|
||||
[ext_resource path="res://scene/game.tscn" type="PackedScene" id=2]
|
||||
[ext_resource type="Script" path="res://script/main.gd" id="1"]
|
||||
[ext_resource type="PackedScene" path="res://scene/game.tscn" id="2"]
|
||||
|
||||
[node name="Main" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 20.0
|
||||
offset_top = 20.0
|
||||
offset_right = -20.0
|
||||
offset_bottom = -20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_right = 984.0
|
||||
offset_bottom = 24.0
|
||||
offset_right = 1112.0
|
||||
offset_bottom = 31.0
|
||||
|
||||
[node name="Label" type="Label" parent="Panel/VBoxContainer/HBoxContainer"]
|
||||
offset_top = 5.0
|
||||
offset_right = 326.0
|
||||
offset_bottom = 19.0
|
||||
offset_top = 2.0
|
||||
offset_right = 369.0
|
||||
offset_bottom = 28.0
|
||||
size_flags_horizontal = 3
|
||||
text = "Name"
|
||||
|
||||
[node name="NameEdit" type="LineEdit" parent="Panel/VBoxContainer/HBoxContainer"]
|
||||
offset_left = 330.0
|
||||
offset_right = 984.0
|
||||
offset_bottom = 24.0
|
||||
offset_left = 373.0
|
||||
offset_right = 1112.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 2.0
|
||||
text = "A Godot User"
|
||||
|
||||
[node name="HBoxContainer2" type="HBoxContainer" parent="Panel/VBoxContainer"]
|
||||
offset_top = 28.0
|
||||
offset_right = 984.0
|
||||
offset_bottom = 52.0
|
||||
offset_top = 35.0
|
||||
offset_right = 1112.0
|
||||
offset_bottom = 66.0
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer/HBoxContainer2"]
|
||||
offset_right = 326.0
|
||||
offset_bottom = 24.0
|
||||
offset_right = 369.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Host" type="Button" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"]
|
||||
offset_right = 42.0
|
||||
offset_bottom = 24.0
|
||||
offset_right = 44.0
|
||||
offset_bottom = 31.0
|
||||
text = "Host"
|
||||
|
||||
[node name="Control" type="Control" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"]
|
||||
offset_left = 46.0
|
||||
offset_right = 241.0
|
||||
offset_bottom = 24.0
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
offset_left = 48.0
|
||||
offset_right = 273.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="Connect" type="Button" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"]
|
||||
offset_left = 245.0
|
||||
offset_right = 326.0
|
||||
offset_bottom = 24.0
|
||||
offset_left = 277.0
|
||||
offset_right = 369.0
|
||||
offset_bottom = 31.0
|
||||
text = "Connect to"
|
||||
|
||||
[node name="Disconnect" type="Button" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"]
|
||||
@@ -77,36 +88,31 @@ offset_bottom = 24.0
|
||||
text = "Disconnect"
|
||||
|
||||
[node name="Hostname" type="LineEdit" parent="Panel/VBoxContainer/HBoxContainer2"]
|
||||
offset_left = 330.0
|
||||
offset_right = 984.0
|
||||
offset_bottom = 24.0
|
||||
offset_left = 373.0
|
||||
offset_right = 1112.0
|
||||
offset_bottom = 31.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_stretch_ratio = 2.0
|
||||
text = "localhost"
|
||||
placeholder_text = "localhost"
|
||||
|
||||
[node name="Control" type="Control" parent="Panel/VBoxContainer"]
|
||||
offset_top = 56.0
|
||||
offset_right = 984.0
|
||||
offset_bottom = 76.0
|
||||
rect_min_size = Vector2(0, 20)
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
offset_top = 70.0
|
||||
offset_right = 1112.0
|
||||
offset_bottom = 70.0
|
||||
|
||||
[node name="Game" parent="Panel/VBoxContainer" instance=ExtResource( 2 )]
|
||||
[node name="Game" parent="Panel/VBoxContainer" instance=ExtResource("2")]
|
||||
layout_mode = 3
|
||||
anchors_preset = 0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
offset_top = 80.0
|
||||
offset_right = 984.0
|
||||
offset_bottom = 560.0
|
||||
offset_top = 74.0
|
||||
offset_right = 1112.0
|
||||
offset_bottom = 608.0
|
||||
|
||||
[node name="AcceptDialog" type="AcceptDialog" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -200.0
|
||||
offset_top = -100.0
|
||||
offset_right = 200.0
|
||||
offset_bottom = 100.0
|
||||
dialog_text = "Connection closed"
|
||||
|
||||
[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer2/HBoxContainer/Host" to="." method="_on_Host_pressed"]
|
||||
|
||||
16
networking/websocket_multiplayer/script/combo.gd
Normal file
16
networking/websocket_multiplayer/script/combo.gd
Normal file
@@ -0,0 +1,16 @@
|
||||
extends Control
|
||||
|
||||
var paths := []
|
||||
|
||||
func _enter_tree():
|
||||
for ch in $GridContainer.get_children():
|
||||
paths.append(NodePath(str(get_path()) + "/GridContainer/" + str(ch.name)))
|
||||
# Sets a dedicated Multiplayer API for each branch.
|
||||
for path in paths:
|
||||
get_tree().set_multiplayer(MultiplayerAPI.create_default_interface(), path)
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
# Clear the branch-specific Multiplayer API.
|
||||
for path in paths:
|
||||
get_tree().set_multiplayer(null, path)
|
||||
@@ -5,36 +5,50 @@ const _crown = preload("res://img/crown.png")
|
||||
@onready var _list = $HBoxContainer/VBoxContainer/ItemList
|
||||
@onready var _action = $HBoxContainer/VBoxContainer/Action
|
||||
|
||||
const ACTIONS = ["roll", "pass"]
|
||||
|
||||
var _players = []
|
||||
var _turn = -1
|
||||
|
||||
master func set_player_name(name):
|
||||
var sender = get_tree().get_rpc_sender_id()
|
||||
rpc("update_player_name", sender, name)
|
||||
@rpc func _log(what):
|
||||
$HBoxContainer/RichTextLabel.add_text(what + "\n")
|
||||
|
||||
|
||||
remotesync func update_player_name(player, name):
|
||||
@rpc(any_peer) func set_player_name(name):
|
||||
if not is_multiplayer_authority():
|
||||
return
|
||||
var sender = multiplayer.get_remote_sender_id()
|
||||
update_player_name.rpc(sender, name)
|
||||
|
||||
|
||||
@rpc(call_local) func update_player_name(player, name):
|
||||
var pos = _players.find(player)
|
||||
if pos != -1:
|
||||
_list.set_item_text(pos, name)
|
||||
|
||||
|
||||
master func request_action(action):
|
||||
var sender = get_tree().get_rpc_sender_id()
|
||||
if _players[_turn] != get_tree().get_rpc_sender_id():
|
||||
rpc("_log", "Someone is trying to cheat! %s" % str(sender))
|
||||
@rpc(any_peer) func request_action(action):
|
||||
if not is_multiplayer_authority():
|
||||
return
|
||||
var sender = multiplayer.get_remote_sender_id()
|
||||
if _players[_turn] != sender:
|
||||
_log.rpc("Someone is trying to cheat! %s" % str(sender))
|
||||
return
|
||||
if action not in ACTIONS:
|
||||
_log.rpc("Invalid action: %s" % action)
|
||||
return
|
||||
|
||||
do_action(action)
|
||||
next_turn()
|
||||
|
||||
|
||||
remotesync func do_action(action):
|
||||
var name = _list.get_item_text(_turn)
|
||||
func do_action(action):
|
||||
var player_name = _list.get_item_text(_turn)
|
||||
var val = randi() % 100
|
||||
rpc("_log", "%s: %ss %d" % [name, action, val])
|
||||
_log.rpc("%s: %ss %d" % [player_name, action, val])
|
||||
|
||||
|
||||
remotesync func set_turn(turn):
|
||||
@rpc(call_local) func set_turn(turn):
|
||||
_turn = turn
|
||||
if turn >= _players.size():
|
||||
return
|
||||
@@ -43,27 +57,27 @@ remotesync func set_turn(turn):
|
||||
_list.set_item_icon(i, _crown)
|
||||
else:
|
||||
_list.set_item_icon(i, null)
|
||||
_action.disabled = _players[turn] != get_tree().get_network_unique_id()
|
||||
_action.disabled = _players[turn] != multiplayer.get_unique_id()
|
||||
|
||||
|
||||
remotesync func del_player(id):
|
||||
@rpc(call_local) func del_player(id):
|
||||
var pos = _players.find(id)
|
||||
if pos == -1:
|
||||
return
|
||||
_players.remove(pos)
|
||||
_players.erase(pos)
|
||||
_list.remove_item(pos)
|
||||
if _turn > pos:
|
||||
_turn -= 1
|
||||
if get_tree().is_network_server():
|
||||
rpc("set_turn", _turn)
|
||||
if multiplayer.is_server():
|
||||
set_turn.rpc(_turn)
|
||||
|
||||
|
||||
remotesync func add_player(id, name=""):
|
||||
@rpc(call_local) func add_player(id, pname=""):
|
||||
_players.append(id)
|
||||
if name == "":
|
||||
if pname == "":
|
||||
_list.add_item("... connecting ...", null, false)
|
||||
else:
|
||||
_list.add_item(name, null, false)
|
||||
_list.add_item(pname, null, false)
|
||||
|
||||
|
||||
func get_player_name(pos):
|
||||
@@ -77,7 +91,7 @@ func next_turn():
|
||||
_turn += 1
|
||||
if _turn >= _players.size():
|
||||
_turn = 0
|
||||
rpc("set_turn", _turn)
|
||||
set_turn.rpc(_turn)
|
||||
|
||||
|
||||
func start():
|
||||
@@ -92,27 +106,25 @@ func stop():
|
||||
|
||||
|
||||
func on_peer_add(id):
|
||||
if not get_tree().is_network_server():
|
||||
if not multiplayer.is_server():
|
||||
return
|
||||
for i in range(0, _players.size()):
|
||||
rpc_id(id, "add_player", _players[i], get_player_name(i))
|
||||
rpc("add_player", id)
|
||||
rpc_id(id, "set_turn", _turn)
|
||||
add_player.rpc_id(id, _players[i], get_player_name(i))
|
||||
add_player.rpc(id)
|
||||
set_turn.rpc_id(id, _turn)
|
||||
|
||||
|
||||
func on_peer_del(id):
|
||||
if not get_tree().is_network_server():
|
||||
if not multiplayer.is_server():
|
||||
return
|
||||
rpc("del_player", id)
|
||||
|
||||
|
||||
remotesync func _log(what):
|
||||
$HBoxContainer/RichTextLabel.add_text(what + "\n")
|
||||
del_player.rpc(id)
|
||||
|
||||
|
||||
func _on_Action_pressed():
|
||||
if get_tree().is_network_server():
|
||||
if multiplayer.is_server():
|
||||
if _turn != 0:
|
||||
return
|
||||
do_action("roll")
|
||||
next_turn()
|
||||
else:
|
||||
rpc_id(1, "request_action", "roll")
|
||||
request_action.rpc_id(1, "roll")
|
||||
|
||||
@@ -10,14 +10,22 @@ const PROTO_NAME = "ludus"
|
||||
@onready var _host_edit = $Panel/VBoxContainer/HBoxContainer2/Hostname
|
||||
@onready var _game = $Panel/VBoxContainer/Game
|
||||
|
||||
var peer = null
|
||||
var peer = WebSocketMultiplayerPeer.new()
|
||||
|
||||
|
||||
func _init():
|
||||
peer.supported_protocols = ["ludus"]
|
||||
|
||||
|
||||
func _ready():
|
||||
#warning-ignore-all:return_value_discarded
|
||||
get_tree().connect(&"network_peer_disconnected", self._peer_disconnected)
|
||||
get_tree().connect(&"network_peer_connected", self._peer_connected)
|
||||
$AcceptDialog.get_label().align = Label.ALIGN_CENTER
|
||||
$AcceptDialog.get_label().valign = Label.VALIGN_CENTER
|
||||
multiplayer.peer_connected.connect(_peer_connected)
|
||||
multiplayer.peer_disconnected.connect(_peer_disconnected)
|
||||
multiplayer.server_disconnected.connect(_close_network)
|
||||
multiplayer.connection_failed.connect(_close_network)
|
||||
multiplayer.connected_to_server.connect(_connected)
|
||||
|
||||
$AcceptDialog.get_label().horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
$AcceptDialog.get_label().vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
# Set the player name according to the system username. Fallback to the path.
|
||||
if OS.has_environment("USERNAME"):
|
||||
_name_edit.text = OS.get_environment("USERNAME")
|
||||
@@ -45,20 +53,15 @@ func stop_game():
|
||||
|
||||
|
||||
func _close_network():
|
||||
if get_tree().is_connected("server_disconnected", self, "_close_network"):
|
||||
get_tree().disconnect(&"server_disconnected", self._close_network)
|
||||
if get_tree().is_connected("connection_failed", self, "_close_network"):
|
||||
get_tree().disconnect(&"connection_failed", self._close_network)
|
||||
if get_tree().is_connected("connected_to_server", self, "_connected"):
|
||||
get_tree().disconnect(&"connected_to_server", self._connected)
|
||||
stop_game()
|
||||
$AcceptDialog.show_modal()
|
||||
$AcceptDialog.get_close_button().grab_focus()
|
||||
get_tree().set_network_peer(null)
|
||||
$AcceptDialog.popup_centered()
|
||||
$AcceptDialog.get_ok_button().grab_focus()
|
||||
multiplayer.multiplayer_peer = null
|
||||
peer.close()
|
||||
|
||||
|
||||
func _connected():
|
||||
_game.rpc("set_player_name", _name_edit.text)
|
||||
_game.set_player_name.rpc(_name_edit.text)
|
||||
|
||||
|
||||
func _peer_connected(id):
|
||||
@@ -66,14 +69,14 @@ func _peer_connected(id):
|
||||
|
||||
|
||||
func _peer_disconnected(id):
|
||||
print("Disconnected %d" % id)
|
||||
_game.on_peer_del(id)
|
||||
|
||||
|
||||
func _on_Host_pressed():
|
||||
peer = WebSocketServer.new()
|
||||
peer.listen(DEF_PORT, PackedStringArray(["ludus"]), true)
|
||||
get_tree().connect(&"server_disconnected", self._close_network)
|
||||
get_tree().set_network_peer(peer)
|
||||
multiplayer.multiplayer_peer = null
|
||||
peer.create_server(DEF_PORT)
|
||||
multiplayer.multiplayer_peer = peer
|
||||
_game.add_player(1, _name_edit.text)
|
||||
start_game()
|
||||
|
||||
@@ -83,9 +86,7 @@ func _on_Disconnect_pressed():
|
||||
|
||||
|
||||
func _on_Connect_pressed():
|
||||
peer = WebSocketClient.new()
|
||||
peer.connect_to_url("ws://" + _host_edit.text + ":" + str(DEF_PORT), PackedStringArray([PROTO_NAME]), true)
|
||||
get_tree().connect(&"connection_failed", self._close_network)
|
||||
get_tree().connect(&"connected_to_server", self._connected)
|
||||
get_tree().set_network_peer(peer)
|
||||
multiplayer.multiplayer_peer = null
|
||||
peer.create_client("ws://" + _host_edit.text + ":" + str(DEF_PORT))
|
||||
multiplayer.multiplayer_peer = peer
|
||||
start_game()
|
||||
|
||||
Reference in New Issue
Block a user