Update other networking demos, with style fixes

This commit is contained in:
Aaron Franke
2020-02-19 17:48:36 -05:00
parent 984a731502
commit b310877037
26 changed files with 275 additions and 266 deletions

View File

@@ -1,35 +1,39 @@
# An example p2p chat client
extends Node extends Node
# An example p2p chat client.
var peer = WebRTCPeerConnection.new() var peer = WebRTCPeerConnection.new()
# Create negotiated data channel # Create negotiated data channel.
var channel = peer.create_data_channel("chat", {"negotiated": true, "id": 1}) var channel = peer.create_data_channel("chat", {"negotiated": true, "id": 1})
func _ready(): func _ready():
# Connect all functions # Connect all functions.
peer.connect("ice_candidate_created", self, "_on_ice_candidate") peer.connect("ice_candidate_created", self, "_on_ice_candidate")
peer.connect("session_description_created", self, "_on_session") peer.connect("session_description_created", self, "_on_session")
# Register to the local signaling server (see below for the implementation) # Register to the local signaling server (see below for the implementation).
Signaling.register(get_path()) Signaling.register(get_path())
func _on_ice_candidate(mid, index, sdp): func _on_ice_candidate(mid, index, sdp):
# Send the ICE candidate to the other peer via signaling server # Send the ICE candidate to the other peer via signaling server.
Signaling.send_candidate(get_path(), mid, index, sdp) Signaling.send_candidate(get_path(), mid, index, sdp)
func _on_session(type, sdp): func _on_session(type, sdp):
# Send the session to other peer via signaling server # Send the session to other peer via signaling server.
Signaling.send_session(get_path(), type, sdp) Signaling.send_session(get_path(), type, sdp)
# Set generated description as local # Set generated description as local.
peer.set_local_description(type, sdp) peer.set_local_description(type, sdp)
func _process(delta): func _process(delta):
# Always poll the connection frequently # Always poll the connection frequently.
peer.poll() peer.poll()
if channel.get_ready_state() == WebRTCDataChannel.STATE_OPEN: if channel.get_ready_state() == WebRTCDataChannel.STATE_OPEN:
while channel.get_available_packet_count() > 0: while channel.get_available_packet_count() > 0:
print(get_path(), " received: ", channel.get_packet().get_string_from_utf8()) print(get_path(), " received: ", channel.get_packet().get_string_from_utf8())
func send_message(message): func send_message(message):
channel.put_packet(message.to_utf8()) channel.put_packet(message.to_utf8())

View File

@@ -10,10 +10,10 @@ func _on_LinkButton_pressed():
OS.shell_open(\"https://github.com/godotengine/webrtc-native/releases\") OS.shell_open(\"https://github.com/godotengine/webrtc-native/releases\")
" "
[node name="main" type="Node"] [node name="Main" type="Node"]
script = ExtResource( 2 ) script = ExtResource( 2 )
[node name="minimal" parent="." instance=ExtResource( 1 )] [node name="Minimal" parent="." instance=ExtResource( 1 )]
[node name="CenterContainer" type="CenterContainer" parent="."] [node name="CenterContainer" type="CenterContainer" parent="."]
anchor_right = 1.0 anchor_right = 1.0

View File

@@ -1,35 +1,37 @@
# Main scene
extends Node extends Node
# Main scene.
# Create the two peers # Create the two peers.
var p1 = WebRTCPeerConnection.new() var p1 = WebRTCPeerConnection.new()
var p2 = WebRTCPeerConnection.new() var p2 = WebRTCPeerConnection.new()
var ch1 = p1.create_data_channel("chat", {"id": 1, "negotiated": true}) var ch1 = p1.create_data_channel("chat", {"id": 1, "negotiated": true})
var ch2 = p2.create_data_channel("chat", {"id": 1, "negotiated": true}) var ch2 = p2.create_data_channel("chat", {"id": 1, "negotiated": true})
func _ready(): func _ready():
# Connect P1 session created to itself to set local description print(p1.create_data_channel("chat", {"id": 1, "negotiated": true}))
# Connect P1 session created to itself to set local description.
p1.connect("session_description_created", p1, "set_local_description") p1.connect("session_description_created", p1, "set_local_description")
# Connect P1 session and ICE created to p2 set remote description and candidates # Connect P1 session and ICE created to p2 set remote description and candidates.
p1.connect("session_description_created", p2, "set_remote_description") p1.connect("session_description_created", p2, "set_remote_description")
p1.connect("ice_candidate_created", p2, "add_ice_candidate") p1.connect("ice_candidate_created", p2, "add_ice_candidate")
# Same for P2 # Same for P2.
p2.connect("session_description_created", p2, "set_local_description") p2.connect("session_description_created", p2, "set_local_description")
p2.connect("session_description_created", p1, "set_remote_description") p2.connect("session_description_created", p1, "set_remote_description")
p2.connect("ice_candidate_created", p1, "add_ice_candidate") p2.connect("ice_candidate_created", p1, "add_ice_candidate")
# Let P1 create the offer # Let P1 create the offer.
p1.create_offer() p1.create_offer()
# Wait a second and send message from P1 # Wait a second and send message from P1.
yield(get_tree().create_timer(1), "timeout") yield(get_tree().create_timer(1), "timeout")
ch1.put_packet("Hi from P1".to_utf8()) ch1.put_packet("Hi from P1".to_utf8())
# Wait a second and send message from P2 # Wait a second and send message from P2.
yield(get_tree().create_timer(1), "timeout") yield(get_tree().create_timer(1), "timeout")
ch2.put_packet("Hi from P2".to_utf8()) ch2.put_packet("Hi from P2".to_utf8())
func _process(delta): func _process(delta):
p1.poll() p1.poll()
p2.poll() p2.poll()

View File

@@ -2,5 +2,5 @@
[ext_resource path="res://minimal.gd" type="Script" id=1] [ext_resource path="res://minimal.gd" type="Script" id=1]
[node name="minimal" type="Node"] [node name="Minimal" type="Node"]
script = ExtResource( 1 ) script = ExtResource( 1 )

View File

@@ -1,6 +1,6 @@
extends "ws_webrtc_client.gd" extends "ws_webrtc_client.gd"
var rtc_mp : WebRTCMultiplayer = WebRTCMultiplayer.new() var rtc_mp: WebRTCMultiplayer = WebRTCMultiplayer.new()
var sealed = false var sealed = false
func _init(): func _init():
@@ -16,17 +16,20 @@ func _init():
connect("peer_connected", self, "peer_connected") connect("peer_connected", self, "peer_connected")
connect("peer_disconnected", self, "peer_disconnected") connect("peer_disconnected", self, "peer_disconnected")
func start(url, lobby = ""): func start(url, lobby = ""):
stop() stop()
sealed = false sealed = false
self.lobby = lobby self.lobby = lobby
connect_to_url(url) connect_to_url(url)
func stop(): func stop():
rtc_mp.close() rtc_mp.close()
close() close()
func _create_peer(id : int):
func _create_peer(id):
var peer : WebRTCPeerConnection = WebRTCPeerConnection.new() var peer : WebRTCPeerConnection = WebRTCPeerConnection.new()
peer.initialize({ peer.initialize({
"iceServers": [ { "urls": ["stun:stun.l.google.com:19302"] } ] "iceServers": [ { "urls": ["stun:stun.l.google.com:19302"] } ]
@@ -38,10 +41,12 @@ func _create_peer(id : int):
peer.create_offer() peer.create_offer()
return peer return peer
func _new_ice_candidate(mid_name : String, index_name : int, sdp_name : String, id : int):
func _new_ice_candidate(mid_name, index_name, sdp_name, id):
send_candidate(id, mid_name, index_name, sdp_name) send_candidate(id, mid_name, index_name, sdp_name)
func _offer_created(type : String, data : String, id : int):
func _offer_created(type, data, id):
if not rtc_mp.has_peer(id): if not rtc_mp.has_peer(id):
return return
print("created", type) print("created", type)
@@ -49,38 +54,47 @@ func _offer_created(type : String, data : String, id : int):
if type == "offer": send_offer(id, data) if type == "offer": send_offer(id, data)
else: send_answer(id, data) else: send_answer(id, data)
func connected(id : int):
func connected(id):
print("Connected %d" % id) print("Connected %d" % id)
rtc_mp.initialize(id, true) rtc_mp.initialize(id, true)
func lobby_joined(lobby : String):
func lobby_joined(lobby):
self.lobby = lobby self.lobby = lobby
func lobby_sealed(): func lobby_sealed():
sealed = true sealed = true
func disconnected(): func disconnected():
print("Disconnected: %d: %s" % [code, reason]) print("Disconnected: %d: %s" % [code, reason])
if not sealed: if not sealed:
stop() # Unexpected disconnect stop() # Unexpected disconnect
func peer_connected(id : int):
func peer_connected(id):
print("Peer connected %d" % id) print("Peer connected %d" % id)
_create_peer(id) _create_peer(id)
func peer_disconnected(id : int):
func peer_disconnected(id):
if rtc_mp.has_peer(id): rtc_mp.remove_peer(id) if rtc_mp.has_peer(id): rtc_mp.remove_peer(id)
func offer_received(id : int, offer : String):
func offer_received(id, offer):
print("Got offer: %d" % id) print("Got offer: %d" % id)
if rtc_mp.has_peer(id): if rtc_mp.has_peer(id):
rtc_mp.get_peer(id).connection.set_remote_description("offer", offer) rtc_mp.get_peer(id).connection.set_remote_description("offer", offer)
func answer_received(id : int, answer : String):
func answer_received(id, answer):
print("Got answer: %d" % id) print("Got answer: %d" % id)
if rtc_mp.has_peer(id): if rtc_mp.has_peer(id):
rtc_mp.get_peer(id).connection.set_remote_description("answer", answer) rtc_mp.get_peer(id).connection.set_remote_description("answer", answer)
func candidate_received(id : int, mid : String, index : int, sdp : String):
func candidate_received(id, mid, index, sdp):
if rtc_mp.has_peer(id): if rtc_mp.has_peer(id):
rtc_mp.get_peer(id).connection.add_ice_candidate(mid, index, sdp) rtc_mp.get_peer(id).connection.add_ice_candidate(mid, index, sdp)

View File

@@ -1,9 +1,9 @@
extends Node extends Node
export var autojoin = true export var autojoin = true
export var lobby = "" # Will create a new lobby if empty export var lobby = "" # Will create a new lobby if empty.
var client : WebSocketClient = WebSocketClient.new() var client: WebSocketClient = WebSocketClient.new()
var code = 1000 var code = 1000
var reason = "Unknown" var reason = "Unknown"
@@ -24,27 +24,33 @@ func _init():
client.connect("connection_error", self, "_closed") client.connect("connection_error", self, "_closed")
client.connect("server_close_request", self, "_close_request") client.connect("server_close_request", self, "_close_request")
func connect_to_url(url : String):
func connect_to_url(url):
close() close()
code = 1000 code = 1000
reason = "Unknown" reason = "Unknown"
client.connect_to_url(url) client.connect_to_url(url)
func close(): func close():
client.disconnect_from_host() client.disconnect_from_host()
func _closed(was_clean : bool = false):
func _closed(was_clean = false):
emit_signal("disconnected") emit_signal("disconnected")
func _close_request(code : int, reason : String):
func _close_request(code, reason):
self.code = code self.code = code
self.reason = reason self.reason = reason
func _connected(protocol = ""): func _connected(protocol = ""):
client.get_peer(1).set_write_mode(WebSocketPeer.WRITE_MODE_TEXT) client.get_peer(1).set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
if autojoin: if autojoin:
join_lobby(lobby) join_lobby(lobby)
func _parse_msg(): func _parse_msg():
var pkt_str : String = client.get_peer(1).get_packet().get_string_from_utf8() var pkt_str : String = client.get_peer(1).get_packet().get_string_from_utf8()
@@ -92,25 +98,32 @@ func _parse_msg():
return return
emit_signal("candidate_received", src_id, candidate[0], int(candidate[1]), candidate[2]) emit_signal("candidate_received", src_id, candidate[0], int(candidate[1]), candidate[2])
func join_lobby(lobby : String):
func join_lobby(lobby):
return client.get_peer(1).put_packet(("J: %s\n" % lobby).to_utf8()) return client.get_peer(1).put_packet(("J: %s\n" % lobby).to_utf8())
func seal_lobby(): func seal_lobby():
return client.get_peer(1).put_packet("S: \n".to_utf8()) return client.get_peer(1).put_packet("S: \n".to_utf8())
func send_candidate(id : int, mid : String, index : int, sdp : String) -> int:
func send_candidate(id, mid, index, sdp) -> int:
return _send_msg("C", id, "\n%s\n%d\n%s" % [mid, index, sdp]) return _send_msg("C", id, "\n%s\n%d\n%s" % [mid, index, sdp])
func send_offer(id : int, offer : String) -> int:
func send_offer(id, offer) -> int:
return _send_msg("O", id, offer) return _send_msg("O", id, offer)
func send_answer(id : int, answer : String) -> int:
func send_answer(id, answer) -> int:
return _send_msg("A", id, answer) return _send_msg("A", id, answer)
func _send_msg(type : String, id : int, data : String) -> int:
func _send_msg(type, id, data) -> int:
return client.get_peer(1).put_packet(("%s: %d\n%s" % [type, id, data]).to_utf8()) return client.get_peer(1).put_packet(("%s: %d\n%s" % [type, id, data]).to_utf8())
func _process(delta): func _process(delta):
var status : int = client.get_connection_status() var status : int = client.get_connection_status()
if status == WebSocketClient.CONNECTION_CONNECTING or status == WebSocketClient.CONNECTION_CONNECTED: if status == WebSocketClient.CONNECTION_CONNECTING or status == WebSocketClient.CONNECTION_CONNECTED:
client.poll() client.poll()

View File

@@ -12,53 +12,68 @@ func _ready():
client.rtc_mp.connect("server_disconnected", self, "_mp_server_disconnect") client.rtc_mp.connect("server_disconnected", self, "_mp_server_disconnect")
client.rtc_mp.connect("connection_succeeded", self, "_mp_connected") client.rtc_mp.connect("connection_succeeded", self, "_mp_connected")
func _process(delta): func _process(delta):
client.rtc_mp.poll() client.rtc_mp.poll()
while client.rtc_mp.get_available_packet_count() > 0: while client.rtc_mp.get_available_packet_count() > 0:
_log(client.rtc_mp.get_packet().get_string_from_utf8()) _log(client.rtc_mp.get_packet().get_string_from_utf8())
func _connected(id): func _connected(id):
_log("Signaling server connected with ID: %d" % id) _log("Signaling server connected with ID: %d" % id)
func _disconnected(): func _disconnected():
_log("Signaling server disconnected: %d - %s" % [client.code, client.reason]) _log("Signaling server disconnected: %d - %s" % [client.code, client.reason])
func _lobby_joined(lobby): func _lobby_joined(lobby):
_log("Joined lobby %s" % lobby) _log("Joined lobby %s" % lobby)
func _lobby_sealed(): func _lobby_sealed():
_log("Lobby has been sealed") _log("Lobby has been sealed")
func _mp_connected(): func _mp_connected():
_log("Multiplayer is connected (I am %d)" % client.rtc_mp.get_unique_id()) _log("Multiplayer is connected (I am %d)" % client.rtc_mp.get_unique_id())
func _mp_server_disconnect(): func _mp_server_disconnect():
_log("Multiplayer is disconnected (I am %d)" % client.rtc_mp.get_unique_id()) _log("Multiplayer is disconnected (I am %d)" % client.rtc_mp.get_unique_id())
func _mp_peer_connected(id : int): func _mp_peer_connected(id : int):
_log("Multiplayer peer %d connected" % id) _log("Multiplayer peer %d connected" % id)
func _mp_peer_disconnected(id : int): func _mp_peer_disconnected(id : int):
_log("Multiplayer peer %d disconnected" % id) _log("Multiplayer peer %d disconnected" % id)
func _log(msg): func _log(msg):
print(msg) print(msg)
$vbox/TextEdit.text += str(msg) + "\n" $VBoxContainer/TextEdit.text += str(msg) + "\n"
func ping(): func ping():
_log(client.rtc_mp.put_packet("ping".to_utf8())) _log(client.rtc_mp.put_packet("ping".to_utf8()))
func _on_Peers_pressed(): func _on_Peers_pressed():
var d = client.rtc_mp.get_peers() var d = client.rtc_mp.get_peers()
_log(d) _log(d)
for k in d: for k in d:
_log(client.rtc_mp.get_peer(k)) _log(client.rtc_mp.get_peer(k))
func start(): func start():
client.start($vbox/connect/host.text, $vbox/connect/RoomSecret.text) client.start($VBoxContainer/Connect/Host.text, $VBoxContainer/Connect/RoomSecret.text)
func _on_Seal_pressed(): func _on_Seal_pressed():
client.seal_lobby() client.seal_lobby()
func stop(): func stop():
client.stop() client.stop()

View File

@@ -16,7 +16,7 @@ __meta__ = {
[node name="Client" type="Node" parent="."] [node name="Client" type="Node" parent="."]
script = ExtResource( 2 ) script = ExtResource( 2 )
[node name="vbox" type="VBoxContainer" parent="."] [node name="VBoxContainer" type="VBoxContainer" parent="."]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
custom_constants/separation = 8 custom_constants/separation = 8
@@ -24,24 +24,24 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="connect" type="HBoxContainer" parent="vbox"] [node name="Connect" type="HBoxContainer" parent="VBoxContainer"]
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 24.0 margin_bottom = 24.0
[node name="Label" type="Label" parent="vbox/connect"] [node name="Label" type="Label" parent="VBoxContainer/Connect"]
margin_top = 5.0 margin_top = 5.0
margin_right = 73.0 margin_right = 73.0
margin_bottom = 19.0 margin_bottom = 19.0
text = "Connect to:" text = "Connect to:"
[node name="host" type="LineEdit" parent="vbox/connect"] [node name="Host" type="LineEdit" parent="VBoxContainer/Connect"]
margin_left = 77.0 margin_left = 77.0
margin_right = 921.0 margin_right = 921.0
margin_bottom = 24.0 margin_bottom = 24.0
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "ws://localhost:9080" text = "ws://localhost:9080"
[node name="Room" type="Label" parent="vbox/connect"] [node name="Room" type="Label" parent="VBoxContainer/Connect"]
margin_left = 925.0 margin_left = 925.0
margin_right = 962.0 margin_right = 962.0
margin_bottom = 24.0 margin_bottom = 24.0
@@ -49,13 +49,13 @@ size_flags_vertical = 5
text = "Room" text = "Room"
valign = 1 valign = 1
[node name="RoomSecret" type="LineEdit" parent="vbox/connect"] [node name="RoomSecret" type="LineEdit" parent="VBoxContainer/Connect"]
margin_left = 966.0 margin_left = 966.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 24.0 margin_bottom = 24.0
placeholder_text = "secret" placeholder_text = "secret"
[node name="HBoxContainer" type="HBoxContainer" parent="vbox"] [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 32.0 margin_top = 32.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 52.0 margin_bottom = 52.0
@@ -64,43 +64,43 @@ __meta__ = {
"_edit_use_anchors_": false "_edit_use_anchors_": false
} }
[node name="Start" type="Button" parent="vbox/HBoxContainer"] [node name="Start" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_right = 41.0 margin_right = 41.0
margin_bottom = 20.0 margin_bottom = 20.0
text = "Start" text = "Start"
[node name="Stop" type="Button" parent="vbox/HBoxContainer"] [node name="Stop" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_left = 51.0 margin_left = 51.0
margin_right = 91.0 margin_right = 91.0
margin_bottom = 20.0 margin_bottom = 20.0
text = "Stop" text = "Stop"
[node name="Seal" type="Button" parent="vbox/HBoxContainer"] [node name="Seal" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_left = 101.0 margin_left = 101.0
margin_right = 139.0 margin_right = 139.0
margin_bottom = 20.0 margin_bottom = 20.0
text = "Seal" text = "Seal"
[node name="Ping" type="Button" parent="vbox/HBoxContainer"] [node name="Ping" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_left = 149.0 margin_left = 149.0
margin_right = 188.0 margin_right = 188.0
margin_bottom = 20.0 margin_bottom = 20.0
text = "Ping" text = "Ping"
[node name="Peers" type="Button" parent="vbox/HBoxContainer"] [node name="Peers" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_left = 198.0 margin_left = 198.0
margin_right = 280.0 margin_right = 280.0
margin_bottom = 20.0 margin_bottom = 20.0
text = "Print peers" text = "Print peers"
[node name="TextEdit" type="TextEdit" parent="vbox"] [node name="TextEdit" type="TextEdit" parent="VBoxContainer"]
margin_top = 60.0 margin_top = 60.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 600.0 margin_bottom = 600.0
size_flags_vertical = 3 size_flags_vertical = 3
readonly = true readonly = true
[connection signal="pressed" from="vbox/HBoxContainer/Start" to="." method="start"] [connection signal="pressed" from="VBoxContainer/HBoxContainer/Start" to="." method="start"]
[connection signal="pressed" from="vbox/HBoxContainer/Stop" to="." method="stop"] [connection signal="pressed" from="VBoxContainer/HBoxContainer/Stop" to="." method="stop"]
[connection signal="pressed" from="vbox/HBoxContainer/Seal" to="." method="_on_Seal_pressed"] [connection signal="pressed" from="VBoxContainer/HBoxContainer/Seal" to="." method="_on_Seal_pressed"]
[connection signal="pressed" from="vbox/HBoxContainer/Ping" to="." method="ping"] [connection signal="pressed" from="VBoxContainer/HBoxContainer/Ping" to="." method="ping"]
[connection signal="pressed" from="vbox/HBoxContainer/Peers" to="." method="_on_Peers_pressed"] [connection signal="pressed" from="VBoxContainer/HBoxContainer/Peers" to="." method="_on_Peers_pressed"]

View File

@@ -2,13 +2,15 @@ extends Control
func _ready(): func _ready():
if OS.get_name() == "HTML5": if OS.get_name() == "HTML5":
$vbox/Signaling.hide() $VBoxContainer/Signaling.hide()
func _on_listen_toggled(button_pressed): func _on_listen_toggled(button_pressed):
if button_pressed: if button_pressed:
$Server.listen(int($vbox/Signaling/port.value)) $Server.listen(int($VBoxContainer/Signaling/Port.value))
else: else:
$Server.stop() $Server.stop()
func _on_LinkButton_pressed(): func _on_LinkButton_pressed():
OS.shell_open("https://github.com/godotengine/webrtc-native/releases") OS.shell_open("https://github.com/godotengine/webrtc-native/releases")

View File

@@ -16,7 +16,7 @@ __meta__ = {
"_edit_use_anchors_": true "_edit_use_anchors_": true
} }
[node name="vbox" type="VBoxContainer" parent="."] [node name="VBoxContainer" type="VBoxContainer" parent="."]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
custom_constants/separation = 50 custom_constants/separation = 50
@@ -24,17 +24,17 @@ __meta__ = {
"_edit_use_anchors_": true "_edit_use_anchors_": true
} }
[node name="Signaling" type="HBoxContainer" parent="vbox"] [node name="Signaling" type="HBoxContainer" parent="VBoxContainer"]
margin_right = 996.0 margin_right = 995.0
margin_bottom = 24.0 margin_bottom = 24.0
[node name="Label" type="Label" parent="vbox/Signaling"] [node name="Label" type="Label" parent="VBoxContainer/Signaling"]
margin_top = 5.0 margin_top = 5.0
margin_right = 104.0 margin_right = 104.0
margin_bottom = 19.0 margin_bottom = 19.0
text = "Signaling server:" text = "Signaling server:"
[node name="port" type="SpinBox" parent="vbox/Signaling"] [node name="Port" type="SpinBox" parent="VBoxContainer/Signaling"]
margin_left = 108.0 margin_left = 108.0
margin_right = 182.0 margin_right = 182.0
margin_bottom = 24.0 margin_bottom = 24.0
@@ -42,52 +42,52 @@ min_value = 1025.0
max_value = 65535.0 max_value = 65535.0
value = 9080.0 value = 9080.0
[node name="listen" type="Button" parent="vbox/Signaling"] [node name="ListenButton" type="Button" parent="VBoxContainer/Signaling"]
margin_left = 186.0 margin_left = 186.0
margin_right = 237.0 margin_right = 237.0
margin_bottom = 24.0 margin_bottom = 24.0
toggle_mode = true toggle_mode = true
text = "Listen" text = "Listen"
[node name="CenterContainer" type="CenterContainer" parent="vbox/Signaling"] [node name="CenterContainer" type="CenterContainer" parent="VBoxContainer/Signaling"]
margin_left = 241.0 margin_left = 241.0
margin_right = 996.0 margin_right = 995.0
margin_bottom = 24.0 margin_bottom = 24.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
[node name="LinkButton" type="LinkButton" parent="vbox/Signaling/CenterContainer"] [node name="LinkButton" type="LinkButton" parent="VBoxContainer/Signaling/CenterContainer"]
margin_left = 104.0 margin_left = 104.0
margin_top = 5.0 margin_top = 5.0
margin_right = 650.0 margin_right = 650.0
margin_bottom = 19.0 margin_bottom = 19.0
text = "Make sure to download the GDNative WebRTC Plugin and place it in the project folder" text = "Make sure to download the GDNative WebRTC Plugin and place it in the project folder"
[node name="Clients" type="GridContainer" parent="vbox"] [node name="Clients" type="GridContainer" parent="VBoxContainer"]
margin_top = 74.0 margin_top = 74.0
margin_right = 996.0 margin_right = 995.0
margin_bottom = 580.0 margin_bottom = 579.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
custom_constants/vseparation = 15 custom_constants/vseparation = 15
custom_constants/hseparation = 15 custom_constants/hseparation = 15
columns = 2 columns = 2
[node name="ClientUI" parent="vbox/Clients" instance=ExtResource( 2 )] [node name="ClientUI" parent="VBoxContainer/Clients" instance=ExtResource( 2 )]
margin_right = 490.0 margin_right = 490.0
margin_bottom = 245.0 margin_bottom = 245.0
[node name="ClientUI2" parent="vbox/Clients" instance=ExtResource( 2 )] [node name="ClientUI2" parent="VBoxContainer/Clients" instance=ExtResource( 2 )]
margin_left = 505.0 margin_left = 505.0
margin_right = 995.0 margin_right = 995.0
margin_bottom = 245.0 margin_bottom = 245.0
[node name="ClientUI3" parent="vbox/Clients" instance=ExtResource( 2 )] [node name="ClientUI3" parent="VBoxContainer/Clients" instance=ExtResource( 2 )]
margin_top = 260.0 margin_top = 260.0
margin_right = 490.0 margin_right = 490.0
margin_bottom = 505.0 margin_bottom = 505.0
[node name="ClientUI4" parent="vbox/Clients" instance=ExtResource( 2 )] [node name="ClientUI4" parent="VBoxContainer/Clients" instance=ExtResource( 2 )]
margin_left = 505.0 margin_left = 505.0
margin_top = 260.0 margin_top = 260.0
margin_right = 995.0 margin_right = 995.0
@@ -95,5 +95,5 @@ margin_bottom = 505.0
[node name="Server" type="Node" parent="."] [node name="Server" type="Node" parent="."]
script = ExtResource( 3 ) script = ExtResource( 3 )
[connection signal="toggled" from="vbox/Signaling/listen" to="." method="_on_listen_toggled"] [connection signal="toggled" from="VBoxContainer/Signaling/ListenButton" to="." method="_on_listen_toggled"]
[connection signal="pressed" from="vbox/Signaling/CenterContainer/LinkButton" to="." method="_on_LinkButton_pressed"] [connection signal="pressed" from="VBoxContainer/Signaling/CenterContainer/LinkButton" to="." method="_on_LinkButton_pressed"]

View File

@@ -6,6 +6,11 @@ const ALFNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
var _alfnum = ALFNUM.to_ascii() var _alfnum = ALFNUM.to_ascii()
var rand: RandomNumberGenerator = RandomNumberGenerator.new()
var lobbies: Dictionary = {}
var server: WebSocketServer = WebSocketServer.new()
var peers: Dictionary = {}
class Peer extends Reference: class Peer extends Reference:
var id = -1 var id = -1
var lobby = "" var lobby = ""
@@ -14,6 +19,8 @@ class Peer extends Reference:
func _init(peer_id): func _init(peer_id):
id = peer_id id = peer_id
class Lobby extends Reference: class Lobby extends Reference:
var peers : Array = [] var peers : Array = []
var host : int = -1 var host : int = -1
@@ -23,7 +30,7 @@ class Lobby extends Reference:
func _init(host_id : int): func _init(host_id : int):
host = host_id host = host_id
func join(peer_id : int, server : WebSocketServer) -> bool: func join(peer_id, server) -> bool:
if sealed: return false if sealed: return false
if not server.has_peer(peer_id): return false if not server.has_peer(peer_id): return false
var new_peer : WebSocketPeer = server.get_peer(peer_id) var new_peer : WebSocketPeer = server.get_peer(peer_id)
@@ -36,27 +43,29 @@ class Lobby extends Reference:
peers.push_back(peer_id) peers.push_back(peer_id)
return true return true
func leave(peer_id : int, server : WebSocketServer) -> bool:
func leave(peer_id, server) -> bool:
if not peers.has(peer_id): return false if not peers.has(peer_id): return false
peers.erase(peer_id) peers.erase(peer_id)
var close = false var close = false
if peer_id == host: if peer_id == host:
# The room host disconnected, will disconnect all peers # The room host disconnected, will disconnect all peers.
close = true close = true
if sealed: return close if sealed: return close
# Notify other peers # Notify other peers.
for p in peers: for p in peers:
if not server.has_peer(p): return close if not server.has_peer(p): return close
if close: if close:
# Disconnect peers # Disconnect peers.
server.disconnect_peer(p) server.disconnect_peer(p)
else: else:
# Notify disconnection # Notify disconnection.
server.get_peer(p).put_packet(("D: %d\n" % peer_id).to_utf8()) server.get_peer(p).put_packet(("D: %d\n" % peer_id).to_utf8())
return close return close
func seal(peer_id : int, server : WebSocketServer) -> bool:
# Only host can seal the room func seal(peer_id, server) -> bool:
# Only host can seal the room.
if host != peer_id: return false if host != peer_id: return false
sealed = true sealed = true
for p in peers: for p in peers:
@@ -64,51 +73,54 @@ class Lobby extends Reference:
time = OS.get_ticks_msec() time = OS.get_ticks_msec()
return true return true
var rand : RandomNumberGenerator = RandomNumberGenerator.new()
var lobbies : Dictionary = {}
var server : WebSocketServer = WebSocketServer.new()
var peers : Dictionary = {}
func _init(): func _init():
server.connect("data_received", self, "_on_data") server.connect("data_received", self, "_on_data")
server.connect("client_connected", self, "_peer_connected") server.connect("client_connected", self, "_peer_connected")
server.connect("client_disconnected", self, "_peer_disconnected") server.connect("client_disconnected", self, "_peer_disconnected")
func _process(delta): func _process(delta):
poll() poll()
func listen(port : int):
func listen(port):
stop() stop()
rand.seed = OS.get_unix_time() rand.seed = OS.get_unix_time()
server.listen(port) server.listen(port)
func stop(): func stop():
server.stop() server.stop()
peers.clear() peers.clear()
func poll(): func poll():
if not server.is_listening(): if not server.is_listening():
return return
server.poll() server.poll()
# Peers timeout # Peers timeout.
for p in peers.values(): for p in peers.values():
if p.lobby == "" and OS.get_ticks_msec() - p.time > TIMEOUT: if p.lobby == "" and OS.get_ticks_msec() - p.time > TIMEOUT:
server.disconnect_peer(p.id) server.disconnect_peer(p.id)
# Lobby seal # Lobby seal.
for k in lobbies: for k in lobbies:
if not lobbies[k].sealed: if not lobbies[k].sealed:
continue continue
if lobbies[k].time + SEAL_TIME < OS.get_ticks_msec(): if lobbies[k].time + SEAL_TIME < OS.get_ticks_msec():
# Close lobby # Close lobby.
for p in lobbies[k].peers: for p in lobbies[k].peers:
server.disconnect_peer(p) server.disconnect_peer(p)
func _peer_connected(id : int, protocol = ""):
func _peer_connected(id, protocol = ""):
peers[id] = Peer.new(id) peers[id] = Peer.new(id)
func _peer_disconnected(id : int, was_clean : bool = false):
func _peer_disconnected(id, was_clean = false):
var lobby = peers[id].lobby var lobby = peers[id].lobby
print("Peer %d disconnected from lobby: '%s'" % [id, lobby]) print("Peer %d disconnected from lobby: '%s'" % [id, lobby])
if lobby and lobbies.has(lobby): if lobby and lobbies.has(lobby):
@@ -119,9 +131,10 @@ func _peer_disconnected(id : int, was_clean : bool = false):
lobbies.erase(lobby) lobbies.erase(lobby)
peers.erase(id) peers.erase(id)
func _join_lobby(peer, lobby : String) -> bool:
func _join_lobby(peer, lobby) -> bool:
if lobby == "": if lobby == "":
for i in range(0, 32): for _i in range(0, 32):
lobby += char(_alfnum[rand.randi_range(0, ALFNUM.length()-1)]) lobby += char(_alfnum[rand.randi_range(0, ALFNUM.length()-1)])
lobbies[lobby] = Lobby.new(peer.id) lobbies[lobby] = Lobby.new(peer.id)
elif not lobbies.has(lobby): elif not lobbies.has(lobby):
@@ -133,19 +146,21 @@ func _join_lobby(peer, lobby : String) -> bool:
print("Peer %d joined lobby: '%s'" % [peer.id, lobby]) print("Peer %d joined lobby: '%s'" % [peer.id, lobby])
return true return true
func _on_data(id : int):
func _on_data(id):
if not _parse_msg(id): if not _parse_msg(id):
print("Parse message failed from peer %d" % id) print("Parse message failed from peer %d" % id)
server.disconnect_peer(id) server.disconnect_peer(id)
func _parse_msg(id : int) -> bool:
var pkt_str : String = server.get_peer(id).get_packet().get_string_from_utf8()
var req : PoolStringArray = pkt_str.split('\n', true, 1) func _parse_msg(id) -> bool:
var pkt_str: String = server.get_peer(id).get_packet().get_string_from_utf8()
var req = pkt_str.split('\n', true, 1)
if req.size() != 2: # Invalid request size if req.size() != 2: # Invalid request size
return false return false
var type : String = req[0] var type = req[0]
if type.length() < 3: # Invalid type size if type.length() < 3: # Invalid type size
return false return false
@@ -192,4 +207,4 @@ func _parse_msg(id : int) -> bool:
elif type.begins_with("C: "): elif type.begins_with("C: "):
# Client is making an answer # Client is making an answer
server.get_peer(dest_id).put_packet(("C: %d\n%s" % [id, req[1]]).to_utf8()) server.get_peer(dest_id).put_packet(("C: %d\n%s" % [id, req[1]]).to_utf8())
return true return true

View File

@@ -19,30 +19,37 @@ func _init():
_client.connect("connection_succeeded", self, "_client_connected", ["multiplayer_protocol"]) _client.connect("connection_succeeded", self, "_client_connected", ["multiplayer_protocol"])
_client.connect("connection_failed", self, "_client_disconnected") _client.connect("connection_failed", self, "_client_disconnected")
func _client_close_request(code, reason): func _client_close_request(code, reason):
Utils._log(_log_dest, "Close code: %d, reason: %s" % [code, reason]) Utils._log(_log_dest, "Close code: %d, reason: %s" % [code, reason])
func _peer_connected(id): func _peer_connected(id):
Utils._log(_log_dest, "%s: Client just connected" % id) Utils._log(_log_dest, "%s: Client just connected" % id)
last_connected_client = id last_connected_client = id
func _exit_tree(): func _exit_tree():
_client.disconnect_from_host(1001, "Bye bye!") _client.disconnect_from_host(1001, "Bye bye!")
func _process(delta):
func _process(_delta):
if _client.get_connection_status() == WebSocketClient.CONNECTION_DISCONNECTED: if _client.get_connection_status() == WebSocketClient.CONNECTION_DISCONNECTED:
return return
_client.poll() _client.poll()
func _client_connected(protocol): func _client_connected(protocol):
Utils._log(_log_dest, "Client just connected with protocol: %s" % protocol) Utils._log(_log_dest, "Client just connected with protocol: %s" % protocol)
_client.get_peer(1).set_write_mode(_write_mode) _client.get_peer(1).set_write_mode(_write_mode)
func _client_disconnected(clean=true): func _client_disconnected(clean=true):
Utils._log(_log_dest, "Client just disconnected. Was clean: %s" % clean) Utils._log(_log_dest, "Client just disconnected. Was clean: %s" % clean)
func _client_received(p_id = 1):
func _client_received(_p_id = 1):
if _use_multiplayer: if _use_multiplayer:
var peer_id = _client.get_packet_peer() var peer_id = _client.get_packet_peer()
var packet = _client.get_packet() var packet = _client.get_packet()
@@ -52,15 +59,18 @@ func _client_received(p_id = 1):
var is_string = _client.get_peer(1).was_string_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)]) 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): func connect_to_url(host, protocols, multiplayer):
_use_multiplayer = multiplayer _use_multiplayer = multiplayer
if _use_multiplayer: if _use_multiplayer:
_write_mode = WebSocketPeer.WRITE_MODE_BINARY _write_mode = WebSocketPeer.WRITE_MODE_BINARY
return _client.connect_to_url(host, protocols, multiplayer) return _client.connect_to_url(host, protocols, multiplayer)
func disconnect_from_host(): func disconnect_from_host():
_client.disconnect_from_host(1000, "Bye bye!") _client.disconnect_from_host(1000, "Bye bye!")
func send_data(data, dest): func send_data(data, dest):
_client.get_peer(1).set_write_mode(_write_mode) _client.get_peer(1).set_write_mode(_write_mode)
if _use_multiplayer: if _use_multiplayer:
@@ -69,5 +79,6 @@ func send_data(data, dest):
else: else:
_client.get_peer(1).put_packet(Utils.encode_data(data, _write_mode)) _client.get_peer(1).put_packet(Utils.encode_data(data, _write_mode))
func set_write_mode(mode): func set_write_mode(mode):
_write_mode = mode _write_mode = mode

View File

@@ -14,23 +14,14 @@ __meta__ = {
[node name="Panel" type="Panel" parent="."] [node name="Panel" type="Panel" parent="."]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
__meta__ = {
}
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"] [node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
__meta__ = {
}
[node name="Connect" type="HBoxContainer" parent="Panel/VBoxContainer"] [node name="Connect" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 24.0 margin_bottom = 24.0
__meta__ = {
}
[node name="Host" type="LineEdit" parent="Panel/VBoxContainer/Connect"] [node name="Host" type="LineEdit" parent="Panel/VBoxContainer/Connect"]
margin_right = 956.0 margin_right = 956.0
@@ -38,9 +29,6 @@ margin_bottom = 24.0
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "ws://localhost:8000/test/" text = "ws://localhost:8000/test/"
placeholder_text = "ws://my.server/path/" placeholder_text = "ws://my.server/path/"
__meta__ = {
}
[node name="Connect" type="Button" parent="Panel/VBoxContainer/Connect"] [node name="Connect" type="Button" parent="Panel/VBoxContainer/Connect"]
margin_left = 960.0 margin_left = 960.0
@@ -48,83 +36,53 @@ margin_right = 1024.0
margin_bottom = 24.0 margin_bottom = 24.0
toggle_mode = true toggle_mode = true
text = "Connect" text = "Connect"
__meta__ = {
}
[node name="Settings" type="HBoxContainer" parent="Panel/VBoxContainer"] [node name="Settings" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_top = 28.0 margin_top = 28.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 52.0 margin_bottom = 52.0
__meta__ = {
}
[node name="Mode" type="OptionButton" parent="Panel/VBoxContainer/Settings"] [node name="Mode" type="OptionButton" parent="Panel/VBoxContainer/Settings"]
margin_right = 41.0 margin_right = 29.0
margin_bottom = 24.0 margin_bottom = 24.0
__meta__ = {
}
[node name="Multiplayer" type="CheckBox" parent="Panel/VBoxContainer/Settings"] [node name="Multiplayer" type="CheckBox" parent="Panel/VBoxContainer/Settings"]
margin_left = 45.0 margin_left = 33.0
margin_right = 171.0 margin_right = 159.0
margin_bottom = 24.0 margin_bottom = 24.0
pressed = true pressed = true
text = "Multiplayer API" text = "Multiplayer API"
__meta__ = {
}
[node name="Destination" type="OptionButton" parent="Panel/VBoxContainer/Settings"] [node name="Destination" type="OptionButton" parent="Panel/VBoxContainer/Settings"]
margin_left = 175.0 margin_left = 163.0
margin_right = 216.0 margin_right = 192.0
margin_bottom = 24.0 margin_bottom = 24.0
__meta__ = {
}
[node name="Send" type="HBoxContainer" parent="Panel/VBoxContainer"] [node name="Send" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_top = 56.0 margin_top = 56.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 80.0 margin_bottom = 80.0
__meta__ = {
}
[node name="LineEdit" type="LineEdit" parent="Panel/VBoxContainer/Send"] [node name="LineEdit" type="LineEdit" parent="Panel/VBoxContainer/Send"]
margin_right = 977.0 margin_right = 977.0
margin_bottom = 24.0 margin_bottom = 24.0
size_flags_horizontal = 3 size_flags_horizontal = 3
placeholder_text = "Enter some text to send..." placeholder_text = "Enter some text to send..."
__meta__ = {
}
[node name="Send" type="Button" parent="Panel/VBoxContainer/Send"] [node name="Send" type="Button" parent="Panel/VBoxContainer/Send"]
margin_left = 981.0 margin_left = 981.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 24.0 margin_bottom = 24.0
text = "Send" text = "Send"
__meta__ = {
}
[node name="RichTextLabel" type="RichTextLabel" parent="Panel/VBoxContainer"] [node name="RichTextLabel" type="RichTextLabel" parent="Panel/VBoxContainer"]
margin_top = 84.0 margin_top = 84.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 600.0 margin_bottom = 600.0
size_flags_vertical = 3 size_flags_vertical = 3
__meta__ = {
}
[node name="Client" type="Node" parent="."] [node name="Client" type="Node" parent="."]
script = ExtResource( 2 ) script = ExtResource( 2 )
__meta__ = {
}
[connection signal="toggled" from="Panel/VBoxContainer/Connect/Connect" to="." method="_on_Connect_toggled"] [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="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"] [connection signal="pressed" from="Panel/VBoxContainer/Send/Send" to="." method="_on_Send_pressed"]

View File

@@ -1,12 +1,12 @@
extends Control extends Control
onready var _client = get_node("Client") onready var _client = $Client
onready var _log_dest = get_node("Panel/VBoxContainer/RichTextLabel") onready var _log_dest = $Panel/VBoxContainer/RichTextLabel
onready var _line_edit = get_node("Panel/VBoxContainer/Send/LineEdit") onready var _line_edit = $Panel/VBoxContainer/Send/LineEdit
onready var _host = get_node("Panel/VBoxContainer/Connect/Host") onready var _host = $Panel/VBoxContainer/Connect/Host
onready var _multiplayer = get_node("Panel/VBoxContainer/Settings/Multiplayer") onready var _multiplayer = $Panel/VBoxContainer/Settings/Multiplayer
onready var _write_mode = get_node("Panel/VBoxContainer/Settings/Mode") onready var _write_mode = $Panel/VBoxContainer/Settings/Mode
onready var _destination = get_node("Panel/VBoxContainer/Settings/Destination") onready var _destination = $Panel/VBoxContainer/Settings/Destination
func _ready(): func _ready():
_write_mode.clear() _write_mode.clear()
@@ -23,9 +23,11 @@ func _ready():
_destination.set_item_metadata(2, -1) _destination.set_item_metadata(2, -1)
_destination.select(0) _destination.select(0)
func _on_Mode_item_selected( ID ):
func _on_Mode_item_selected(_id):
_client.set_write_mode(_write_mode.get_selected_metadata()) _client.set_write_mode(_write_mode.get_selected_metadata())
func _on_Send_pressed(): func _on_Send_pressed():
if _line_edit.text == "": if _line_edit.text == "":
return return
@@ -40,6 +42,7 @@ func _on_Send_pressed():
_client.send_data(_line_edit.text, dest) _client.send_data(_line_edit.text, dest)
_line_edit.text = "" _line_edit.text = ""
func _on_Connect_toggled( pressed ): func _on_Connect_toggled( pressed ):
if pressed: if pressed:
var multiplayer = _multiplayer.pressed var multiplayer = _multiplayer.pressed

View File

@@ -7,17 +7,11 @@
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
mouse_filter = 1 mouse_filter = 1
__meta__ = {
}
[node name="Box" type="HBoxContainer" parent="."] [node name="Box" type="HBoxContainer" parent="."]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
custom_constants/separation = 20 custom_constants/separation = 20
__meta__ = {
}
[node name="ServerControl" parent="Box" instance=ExtResource( 1 )] [node name="ServerControl" parent="Box" instance=ExtResource( 1 )]
anchor_right = 0.0 anchor_right = 0.0
@@ -31,9 +25,6 @@ margin_left = 522.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 600.0 margin_bottom = 600.0
size_flags_horizontal = 3 size_flags_horizontal = 3
__meta__ = {
}
[node name="Client" parent="Box/VBoxContainer" instance=ExtResource( 2 )] [node name="Client" parent="Box/VBoxContainer" instance=ExtResource( 2 )]
anchor_right = 0.0 anchor_right = 0.0

View File

@@ -18,29 +18,35 @@ func _init():
_server.connect("peer_connected", self, "_client_connected", ["multiplayer_protocol"]) _server.connect("peer_connected", self, "_client_connected", ["multiplayer_protocol"])
_server.connect("peer_disconnected", self, "_client_disconnected") _server.connect("peer_disconnected", self, "_client_disconnected")
func _exit_tree(): func _exit_tree():
_clients.clear() _clients.clear()
_server.stop() _server.stop()
func _process(delta):
func _process(_delta):
if _server.is_listening(): if _server.is_listening():
_server.poll() _server.poll()
func _client_close_request(id, code, reason): func _client_close_request(id, code, reason):
print(reason == "Bye bye!") print(reason == "Bye bye!")
Utils._log(_log_dest, "Client %s close code: %d, reason: %s" % [id, code, reason]) Utils._log(_log_dest, "Client %s close code: %d, reason: %s" % [id, code, reason])
func _client_connected(id, protocol): func _client_connected(id, protocol):
_clients[id] = _server.get_peer(id) _clients[id] = _server.get_peer(id)
_clients[id].set_write_mode(_write_mode) _clients[id].set_write_mode(_write_mode)
last_connected_client = id last_connected_client = id
Utils._log(_log_dest, "%s: Client connected with protocol %s" % [id, protocol]) Utils._log(_log_dest, "%s: Client connected with protocol %s" % [id, protocol])
func _client_disconnected(id, clean = true): func _client_disconnected(id, clean = true):
Utils._log(_log_dest, "Client %s disconnected. Was clean: %s" % [id, clean]) Utils._log(_log_dest, "Client %s disconnected. Was clean: %s" % [id, clean])
if _clients.has(id): if _clients.has(id):
_clients.erase(id) _clients.erase(id)
func _client_receive(id): func _client_receive(id):
if _use_multiplayer: if _use_multiplayer:
var peer_id = _server.get_packet_peer() var peer_id = _server.get_packet_peer()
@@ -51,6 +57,7 @@ func _client_receive(id):
var is_string = _server.get_peer(id).was_string_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)]) 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): func send_data(data, dest):
if _use_multiplayer: if _use_multiplayer:
_server.set_target_peer(dest) _server.set_target_peer(dest)
@@ -59,15 +66,18 @@ func send_data(data, dest):
for id in _clients: for id in _clients:
_server.get_peer(id).put_packet(Utils.encode_data(data, _write_mode)) _server.get_peer(id).put_packet(Utils.encode_data(data, _write_mode))
func listen(port, supported_protocols, multiplayer): func listen(port, supported_protocols, multiplayer):
_use_multiplayer = multiplayer _use_multiplayer = multiplayer
if _use_multiplayer: if _use_multiplayer:
set_write_mode(WebSocketPeer.WRITE_MODE_BINARY) set_write_mode(WebSocketPeer.WRITE_MODE_BINARY)
return _server.listen(port, supported_protocols, multiplayer) return _server.listen(port, supported_protocols, multiplayer)
func stop(): func stop():
_server.stop() _server.stop()
func set_write_mode(mode): func set_write_mode(mode):
_write_mode = mode _write_mode = mode
for c in _clients: for c in _clients:

View File

@@ -1,12 +1,12 @@
extends Control extends Control
onready var _server = get_node("Server") onready var _server = $Server
onready var _port = get_node("Panel/VBoxContainer/HBoxContainer/Port") onready var _port = $Panel/VBoxContainer/HBoxContainer/Port
onready var _line_edit = get_node("Panel/VBoxContainer/HBoxContainer3/LineEdit") onready var _line_edit = $Panel/VBoxContainer/HBoxContainer3/LineEdit
onready var _write_mode = get_node("Panel/VBoxContainer/HBoxContainer2/WriteMode") onready var _write_mode = $Panel/VBoxContainer/HBoxContainer2/WriteMode
onready var _log_dest = get_node("Panel/VBoxContainer/RichTextLabel") onready var _log_dest = $Panel/VBoxContainer/RichTextLabel
onready var _multiplayer = get_node("Panel/VBoxContainer/HBoxContainer2/MPAPI") onready var _multiplayer = $Panel/VBoxContainer/HBoxContainer2/MPAPI
onready var _destination = get_node("Panel/VBoxContainer/HBoxContainer2/Destination") onready var _destination = $Panel/VBoxContainer/HBoxContainer2/Destination
func _ready(): func _ready():
_write_mode.clear() _write_mode.clear()
@@ -24,7 +24,8 @@ func _ready():
_destination.set_item_metadata(2, -1) _destination.set_item_metadata(2, -1)
_destination.select(0) _destination.select(0)
func _on_Listen_toggled( pressed ):
func _on_Listen_toggled(pressed):
if pressed: if pressed:
var use_multiplayer = _multiplayer.pressed var use_multiplayer = _multiplayer.pressed
_multiplayer.disabled = true _multiplayer.disabled = true
@@ -49,6 +50,7 @@ func _on_Listen_toggled( pressed ):
_destination.disabled = false _destination.disabled = false
Utils._log(_log_dest, "Server stopped") Utils._log(_log_dest, "Server stopped")
func _on_Send_pressed(): func _on_Send_pressed():
if _line_edit.text == "": if _line_edit.text == "":
return return
@@ -63,5 +65,6 @@ func _on_Send_pressed():
_server.send_data(_line_edit.text, dest) _server.send_data(_line_edit.text, dest)
_line_edit.text = "" _line_edit.text = ""
func _on_WriteMode_item_selected( ID ):
func _on_WriteMode_item_selected(_id):
_server.set_write_mode(_write_mode.get_selected_metadata()) _server.set_write_mode(_write_mode.get_selected_metadata())

View File

@@ -3,9 +3,11 @@ extends Node
func encode_data(data, mode): func encode_data(data, mode):
return data.to_utf8() if mode == WebSocketPeer.WRITE_MODE_TEXT else var2bytes(data) return data.to_utf8() if mode == WebSocketPeer.WRITE_MODE_TEXT else var2bytes(data)
func decode_data(data, is_string): func decode_data(data, is_string):
return data.get_string_from_utf8() if is_string else bytes2var(data) return data.get_string_from_utf8() if is_string else bytes2var(data)
func _log(node, msg): func _log(node, msg):
print(msg) print(msg)
node.add_text(str(msg) + "\n") node.add_text(str(msg) + "\n")

View File

@@ -4,18 +4,9 @@
[ext_resource path="res://client.gd" type="Script" id=2] [ext_resource path="res://client.gd" type="Script" id=2]
[node name="Main" type="Node"] [node name="Main" type="Node"]
__meta__ = {
}
[node name="Server" type="Node" parent="."] [node name="Server" type="Node" parent="."]
script = ExtResource( 1 ) script = ExtResource( 1 )
__meta__ = {
}
[node name="Client" type="Node" parent="."] [node name="Client" type="Node" parent="."]
script = ExtResource( 2 ) script = ExtResource( 2 )
__meta__ = {
}

View File

@@ -1,9 +1,9 @@
extends Node extends Node
# The URL we will connect to # The URL we will connect to.
export var websocket_url = "ws://localhost:9080" export var websocket_url = "ws://localhost:9080"
# Our WebSocketClient instance # Our WebSocketClient instance.
var _client = WebSocketClient.new() var _client = WebSocketClient.new()
func _ready(): func _ready():
@@ -22,12 +22,14 @@ func _ready():
print("Unable to connect") print("Unable to connect")
set_process(false) set_process(false)
func _closed(was_clean = false): func _closed(was_clean = false):
# was_clean will tell you if the disconnection was correctly notified # was_clean will tell you if the disconnection was correctly notified
# by the remote peer before closing the socket. # by the remote peer before closing the socket.
print("Closed, clean: ", was_clean) print("Closed, clean: ", was_clean)
set_process(false) set_process(false)
func _connected(proto = ""): func _connected(proto = ""):
# This is called on connection, "proto" will be the selected WebSocket # This is called on connection, "proto" will be the selected WebSocket
# sub-protocol (which is optional) # sub-protocol (which is optional)
@@ -36,16 +38,19 @@ func _connected(proto = ""):
# and not put_packet directly when not using the MultiplayerAPI. # and not put_packet directly when not using the MultiplayerAPI.
_client.get_peer(1).put_packet("Test packet".to_utf8()) _client.get_peer(1).put_packet("Test packet".to_utf8())
func _on_data(): func _on_data():
# Print the received packet, you MUST always use get_peer(1).get_packet # 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 # to receive data from server, and not get_packet directly when not
# using the MultiplayerAPI. # using the MultiplayerAPI.
print("Got data from server: ", _client.get_peer(1).get_packet().get_string_from_utf8()) print("Got data from server: ", _client.get_peer(1).get_packet().get_string_from_utf8())
func _process(delta): func _process(delta):
# Call this in _process or _physics_process. Data transfer, and signals # Call this in _process or _physics_process. Data transfer, and signals
# emission will only happen when calling this function. # emission will only happen when calling this function.
_client.poll() _client.poll()
func _exit_tree(): func _exit_tree():
_client.disconnect_from_host() _client.disconnect_from_host()

View File

@@ -1,8 +1,8 @@
extends Node extends Node
# The port we will listen to # The port we will listen to.
const PORT = 9080 const PORT = 9080
# Our WebSocketServer instance # Our WebSocketServer instance.
var _server = WebSocketServer.new() var _server = WebSocketServer.new()
func _ready(): func _ready():
@@ -22,22 +22,26 @@ func _ready():
print("Unable to start server") print("Unable to start server")
set_process(false) set_process(false)
func _connected(id, proto): func _connected(id, proto):
# This is called when a new peer connects, "id" will be the assigned peer id, # 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) # "proto" will be the selected WebSocket sub-protocol (which is optional)
print("Client %d connected with protocol: %s" % [id, proto]) print("Client %d connected with protocol: %s" % [id, proto])
func _close_request(id, code, reason): func _close_request(id, code, reason):
# This is called when a client notifies that it wishes to close the connection, # This is called when a client notifies that it wishes to close the connection,
# providing a reason string and close code. # providing a reason string and close code.
print("Client %d disconnecting with code: %d, reason: %s" % [id, code, reason]) print("Client %d disconnecting with code: %d, reason: %s" % [id, code, reason])
func _disconnected(id, was_clean = false): func _disconnected(id, was_clean = false):
# This is called when a client disconnects, "id" will be the one of the # This is called when a client disconnects, "id" will be the one of the
# disconnecting client, "was_clean" will tell you if the disconnection # disconnecting client, "was_clean" will tell you if the disconnection
# was correctly notified by the remote peer before closing the socket. # was correctly notified by the remote peer before closing the socket.
print("Client %d disconnected, clean: %s" % [id, str(was_clean)]) print("Client %d disconnected, clean: %s" % [id, str(was_clean)])
func _on_data(id): func _on_data(id):
# Print the received packet, you MUST always use get_peer(id).get_packet to receive data, # 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. # and not get_packet directly when not using the MultiplayerAPI.
@@ -45,10 +49,12 @@ func _on_data(id):
print("Got data from client %d: %s ... echoing" % [id, pkt.get_string_from_utf8()]) print("Got data from client %d: %s ... echoing" % [id, pkt.get_string_from_utf8()])
_server.get_peer(id).put_packet(pkt) _server.get_peer(id).put_packet(pkt)
func _process(delta): func _process(delta):
# Call this in _process or _physics_process. # Call this in _process or _physics_process.
# Data transfer, and signals emission will only happen when calling this function. # Data transfer, and signals emission will only happen when calling this function.
_server.poll() _server.poll()
func _exit_tree(): func _exit_tree():
_server.stop() _server.stop()

View File

@@ -8,13 +8,7 @@ ground_bottom_color = Color( 0.101961, 0.145098, 0.188235, 1 )
ground_horizon_color = Color( 0.482353, 0.788235, 0.952941, 1 ) ground_horizon_color = Color( 0.482353, 0.788235, 0.952941, 1 )
ground_curve = 0.01 ground_curve = 0.01
sun_energy = 16.0 sun_energy = 16.0
__meta__ = {
}
[resource] [resource]
background_mode = 2 background_mode = 2
background_sky = SubResource( 1 ) background_sky = SubResource( 1 )
__meta__ = {
}

View File

@@ -16,34 +16,22 @@ __meta__ = {
[node name="HBoxContainer" type="HBoxContainer" parent="."] [node name="HBoxContainer" type="HBoxContainer" parent="."]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
__meta__ = {
}
[node name="RichTextLabel" type="RichTextLabel" parent="HBoxContainer"] [node name="RichTextLabel" type="RichTextLabel" parent="HBoxContainer"]
margin_right = 510.0 margin_right = 510.0
margin_bottom = 600.0 margin_bottom = 600.0
size_flags_horizontal = 3 size_flags_horizontal = 3
__meta__ = {
}
[node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="HBoxContainer"]
margin_left = 514.0 margin_left = 514.0
margin_right = 1024.0 margin_right = 1024.0
margin_bottom = 600.0 margin_bottom = 600.0
size_flags_horizontal = 3 size_flags_horizontal = 3
__meta__ = {
}
[node name="Label" type="Label" parent="HBoxContainer/VBoxContainer"] [node name="Label" type="Label" parent="HBoxContainer/VBoxContainer"]
margin_right = 510.0 margin_right = 510.0
margin_bottom = 14.0 margin_bottom = 14.0
text = "Players:" text = "Players:"
__meta__ = {
}
[node name="ItemList" type="ItemList" parent="HBoxContainer/VBoxContainer"] [node name="ItemList" type="ItemList" parent="HBoxContainer/VBoxContainer"]
margin_top = 18.0 margin_top = 18.0
@@ -52,9 +40,6 @@ margin_bottom = 576.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
same_column_width = true same_column_width = true
__meta__ = {
}
[node name="Action" type="Button" parent="HBoxContainer/VBoxContainer"] [node name="Action" type="Button" parent="HBoxContainer/VBoxContainer"]
margin_top = 580.0 margin_top = 580.0
@@ -62,7 +47,4 @@ margin_right = 510.0
margin_bottom = 600.0 margin_bottom = 600.0
disabled = true disabled = true
text = "Do Action!" text = "Do Action!"
__meta__ = {
}
[connection signal="pressed" from="HBoxContainer/VBoxContainer/Action" to="." method="_on_Action_pressed"] [connection signal="pressed" from="HBoxContainer/VBoxContainer/Action" to="." method="_on_Action_pressed"]

View File

@@ -3,20 +3,17 @@
[ext_resource path="res://script/main.gd" type="Script" id=1] [ext_resource path="res://script/main.gd" type="Script" id=1]
[ext_resource path="res://scene/game.tscn" type="PackedScene" id=2] [ext_resource path="res://scene/game.tscn" type="PackedScene" id=2]
[node name="Control" type="Control"] [node name="Main" type="Control"]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
script = ExtResource( 1 ) script = ExtResource( 1 )
__meta__ = { __meta__ = {
"_edit_use_anchors_": false
} }
[node name="Panel" type="Panel" parent="."] [node name="Panel" type="Panel" parent="."]
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
__meta__ = {
}
[node name="VBoxContainer" type="VBoxContainer" parent="Panel"] [node name="VBoxContainer" type="VBoxContainer" parent="Panel"]
anchor_right = 1.0 anchor_right = 1.0
@@ -25,16 +22,10 @@ margin_left = 20.0
margin_top = 20.0 margin_top = 20.0
margin_right = -20.0 margin_right = -20.0
margin_bottom = -20.0 margin_bottom = -20.0
__meta__ = {
}
[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer"] [node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_right = 984.0 margin_right = 984.0
margin_bottom = 24.0 margin_bottom = 24.0
__meta__ = {
}
[node name="Label" type="Label" parent="Panel/VBoxContainer/HBoxContainer"] [node name="Label" type="Label" parent="Panel/VBoxContainer/HBoxContainer"]
margin_top = 5.0 margin_top = 5.0
@@ -42,9 +33,6 @@ margin_right = 326.0
margin_bottom = 19.0 margin_bottom = 19.0
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "Name" text = "Name"
__meta__ = {
}
[node name="NameEdit" type="LineEdit" parent="Panel/VBoxContainer/HBoxContainer"] [node name="NameEdit" type="LineEdit" parent="Panel/VBoxContainer/HBoxContainer"]
margin_left = 330.0 margin_left = 330.0
@@ -53,51 +41,33 @@ margin_bottom = 24.0
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_stretch_ratio = 2.0 size_flags_stretch_ratio = 2.0
text = "A Godot User" text = "A Godot User"
__meta__ = {
}
[node name="HBoxContainer2" type="HBoxContainer" parent="Panel/VBoxContainer"] [node name="HBoxContainer2" type="HBoxContainer" parent="Panel/VBoxContainer"]
margin_top = 28.0 margin_top = 28.0
margin_right = 984.0 margin_right = 984.0
margin_bottom = 52.0 margin_bottom = 52.0
__meta__ = {
}
[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer/HBoxContainer2"] [node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBoxContainer/HBoxContainer2"]
margin_right = 326.0 margin_right = 326.0
margin_bottom = 24.0 margin_bottom = 24.0
size_flags_horizontal = 3 size_flags_horizontal = 3
__meta__ = {
}
[node name="Host" type="Button" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"] [node name="Host" type="Button" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"]
margin_right = 42.0 margin_right = 42.0
margin_bottom = 24.0 margin_bottom = 24.0
text = "Host" text = "Host"
__meta__ = {
}
[node name="Control" type="Control" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"] [node name="Control" type="Control" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"]
margin_left = 46.0 margin_left = 46.0
margin_right = 241.0 margin_right = 241.0
margin_bottom = 24.0 margin_bottom = 24.0
size_flags_horizontal = 3 size_flags_horizontal = 3
__meta__ = {
}
[node name="Connect" type="Button" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"] [node name="Connect" type="Button" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"]
margin_left = 245.0 margin_left = 245.0
margin_right = 326.0 margin_right = 326.0
margin_bottom = 24.0 margin_bottom = 24.0
text = "Connect to" text = "Connect to"
__meta__ = {
}
[node name="Disconnect" type="Button" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"] [node name="Disconnect" type="Button" parent="Panel/VBoxContainer/HBoxContainer2/HBoxContainer"]
visible = false visible = false
@@ -105,9 +75,6 @@ margin_left = 68.0
margin_right = 152.0 margin_right = 152.0
margin_bottom = 24.0 margin_bottom = 24.0
text = "Disconnect" text = "Disconnect"
__meta__ = {
}
[node name="Hostname" type="LineEdit" parent="Panel/VBoxContainer/HBoxContainer2"] [node name="Hostname" type="LineEdit" parent="Panel/VBoxContainer/HBoxContainer2"]
margin_left = 330.0 margin_left = 330.0
@@ -117,18 +84,12 @@ size_flags_horizontal = 3
size_flags_stretch_ratio = 2.0 size_flags_stretch_ratio = 2.0
text = "localhost" text = "localhost"
placeholder_text = "localhost" placeholder_text = "localhost"
__meta__ = {
}
[node name="Control" type="Control" parent="Panel/VBoxContainer"] [node name="Control" type="Control" parent="Panel/VBoxContainer"]
margin_top = 56.0 margin_top = 56.0
margin_right = 984.0 margin_right = 984.0
margin_bottom = 76.0 margin_bottom = 76.0
rect_min_size = Vector2( 0, 20 ) rect_min_size = Vector2( 0, 20 )
__meta__ = {
}
[node name="Game" parent="Panel/VBoxContainer" instance=ExtResource( 2 )] [node name="Game" parent="Panel/VBoxContainer" instance=ExtResource( 2 )]
anchor_right = 0.0 anchor_right = 0.0
@@ -147,9 +108,6 @@ margin_top = -100.0
margin_right = 200.0 margin_right = 200.0
margin_bottom = 100.0 margin_bottom = 100.0
dialog_text = "Connection closed" dialog_text = "Connection closed"
__meta__ = {
}
[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer2/HBoxContainer/Host" to="." method="_on_Host_pressed"] [connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer2/HBoxContainer/Host" to="." method="_on_Host_pressed"]
[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer2/HBoxContainer/Connect" to="." method="_on_Connect_pressed"] [connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer2/HBoxContainer/Connect" to="." method="_on_Connect_pressed"]
[connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer2/HBoxContainer/Disconnect" to="." method="_on_Disconnect_pressed"] [connection signal="pressed" from="Panel/VBoxContainer/HBoxContainer2/HBoxContainer/Disconnect" to="." method="_on_Disconnect_pressed"]

View File

@@ -12,11 +12,13 @@ master func set_player_name(name):
var sender = get_tree().get_rpc_sender_id() var sender = get_tree().get_rpc_sender_id()
rpc("update_player_name", sender, name) rpc("update_player_name", sender, name)
sync func update_player_name(player, name): sync func update_player_name(player, name):
var pos = _players.find(player) var pos = _players.find(player)
if pos != -1: if pos != -1:
_list.set_item_text(pos, name) _list.set_item_text(pos, name)
master func request_action(action): master func request_action(action):
var sender = get_tree().get_rpc_sender_id() var sender = get_tree().get_rpc_sender_id()
if _players[_turn] != get_tree().get_rpc_sender_id(): if _players[_turn] != get_tree().get_rpc_sender_id():
@@ -25,11 +27,13 @@ master func request_action(action):
do_action(action) do_action(action)
next_turn() next_turn()
sync func do_action(action): sync func do_action(action):
var name = _list.get_item_text(_turn) var name = _list.get_item_text(_turn)
var val = randi() % 100 var val = randi() % 100
rpc("_log", "%s: %ss %d" % [name, action, val]) rpc("_log", "%s: %ss %d" % [name, action, val])
sync func set_turn(turn): sync func set_turn(turn):
_turn = turn _turn = turn
if turn >= _players.size(): if turn >= _players.size():
@@ -41,6 +45,7 @@ sync func set_turn(turn):
_list.set_item_icon(i, null) _list.set_item_icon(i, null)
_action.disabled = _players[turn] != get_tree().get_network_unique_id() _action.disabled = _players[turn] != get_tree().get_network_unique_id()
sync func del_player(id): sync func del_player(id):
var pos = _players.find(id) var pos = _players.find(id)
if pos == -1: if pos == -1:
@@ -52,6 +57,7 @@ sync func del_player(id):
if get_tree().is_network_server(): if get_tree().is_network_server():
rpc("set_turn", _turn) rpc("set_turn", _turn)
sync func add_player(id, name=""): sync func add_player(id, name=""):
_players.append(id) _players.append(id)
if name == "": if name == "":
@@ -59,27 +65,32 @@ sync func add_player(id, name=""):
else: else:
_list.add_item(name, null, false) _list.add_item(name, null, false)
func get_player_name(pos): func get_player_name(pos):
if pos < _list.get_item_count(): if pos < _list.get_item_count():
return _list.get_item_text(pos) return _list.get_item_text(pos)
else: else:
return "Error!" return "Error!"
func next_turn(): func next_turn():
_turn += 1 _turn += 1
if _turn >= _players.size(): if _turn >= _players.size():
_turn = 0 _turn = 0
rpc("set_turn", _turn) rpc("set_turn", _turn)
func start(): func start():
set_turn(0) set_turn(0)
func stop(): func stop():
_players.clear() _players.clear()
_list.clear() _list.clear()
_turn = 0 _turn = 0
_action.disabled = true _action.disabled = true
func on_peer_add(id): func on_peer_add(id):
if not get_tree().is_network_server(): if not get_tree().is_network_server():
return return
@@ -88,14 +99,17 @@ func on_peer_add(id):
rpc("add_player", id) rpc("add_player", id)
rpc_id(id, "set_turn", _turn) rpc_id(id, "set_turn", _turn)
func on_peer_del(id): func on_peer_del(id):
if not get_tree().is_network_server(): if not get_tree().is_network_server():
return return
rpc("del_player", id) rpc("del_player", id)
sync func _log(what): sync func _log(what):
$HBoxContainer/RichTextLabel.add_text(what + "\n") $HBoxContainer/RichTextLabel.add_text(what + "\n")
func _on_Action_pressed(): func _on_Action_pressed():
if get_tree().is_network_server(): if get_tree().is_network_server():
do_action("roll") do_action("roll")

View File

@@ -11,10 +11,18 @@ onready var _host_edit = $Panel/VBoxContainer/HBoxContainer2/Hostname
onready var _game = $Panel/VBoxContainer/Game onready var _game = $Panel/VBoxContainer/Game
func _ready(): func _ready():
#warning-ignore-all:return_value_discarded
get_tree().connect("network_peer_disconnected", self, "_peer_disconnected") get_tree().connect("network_peer_disconnected", self, "_peer_disconnected")
get_tree().connect("network_peer_connected", self, "_peer_connected") get_tree().connect("network_peer_connected", self, "_peer_connected")
$AcceptDialog.get_label().align = Label.ALIGN_CENTER $AcceptDialog.get_label().align = Label.ALIGN_CENTER
$AcceptDialog.get_label().valign = Label.VALIGN_CENTER $AcceptDialog.get_label().valign = Label.VALIGN_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")
else:
var desktop_path = OS.get_system_dir(0).replace("\\", "/").split("/")
_name_edit.text = desktop_path[desktop_path.size() - 2]
func start_game(): func start_game():
_host_btn.disabled = true _host_btn.disabled = true
@@ -24,6 +32,7 @@ func start_game():
_disconnect_btn.show() _disconnect_btn.show()
_game.start() _game.start()
func stop_game(): func stop_game():
_host_btn.disabled = false _host_btn.disabled = false
_name_edit.editable = true _name_edit.editable = true
@@ -32,6 +41,7 @@ func stop_game():
_connect_btn.show() _connect_btn.show()
_game.stop() _game.stop()
func _close_network(): func _close_network():
if get_tree().is_connected("server_disconnected", self, "_close_network"): if get_tree().is_connected("server_disconnected", self, "_close_network"):
get_tree().disconnect("server_disconnected", self, "_close_network") get_tree().disconnect("server_disconnected", self, "_close_network")
@@ -44,15 +54,19 @@ func _close_network():
$AcceptDialog.get_close_button().grab_focus() $AcceptDialog.get_close_button().grab_focus()
get_tree().set_network_peer(null) get_tree().set_network_peer(null)
func _connected(): func _connected():
_game.rpc("set_player_name", _name_edit.text) _game.rpc("set_player_name", _name_edit.text)
func _peer_connected(id): func _peer_connected(id):
_game.on_peer_add(id) _game.on_peer_add(id)
func _peer_disconnected(id): func _peer_disconnected(id):
_game.on_peer_del(id) _game.on_peer_del(id)
func _on_Host_pressed(): func _on_Host_pressed():
var host = WebSocketServer.new() var host = WebSocketServer.new()
host.listen(DEF_PORT, PoolStringArray(["ludus"]), true) host.listen(DEF_PORT, PoolStringArray(["ludus"]), true)
@@ -61,9 +75,11 @@ func _on_Host_pressed():
_game.add_player(1, _name_edit.text) _game.add_player(1, _name_edit.text)
start_game() start_game()
func _on_Disconnect_pressed(): func _on_Disconnect_pressed():
_close_network() _close_network()
func _on_Connect_pressed(): func _on_Connect_pressed():
var host = WebSocketClient.new() var host = WebSocketClient.new()
host.connect_to_url("ws://" + _host_edit.text + ":" + str(DEF_PORT), PoolStringArray([PROTO_NAME]), true) host.connect_to_url("ws://" + _host_edit.text + ":" + str(DEF_PORT), PoolStringArray([PROTO_NAME]), true)