Files
godot-demo-projects/networking/webrtc_signaling/client/ws_webrtc_client.gd
Hugo Locurcio bac1e69164 Use static typing in all demos (#1063)
This leads to code that is easier to understand and runs
faster thanks to GDScript's typed instructions.

The untyped declaration warning is now enabled on all projects
where type hints were added. All projects currently run without
any untyped declration warnings.

Dodge the Creeps and Squash the Creeps demos intentionally don't
use type hints to match the documentation, where type hints haven't
been adopted yet (given its beginner focus).
2024-06-01 12:12:18 +02:00

131 lines
3.3 KiB
GDScript

extends Node
enum Message {
JOIN,
ID,
PEER_CONNECT,
PEER_DISCONNECT,
OFFER,
ANSWER,
CANDIDATE,
SEAL,
}
@export var autojoin := true
@export var lobby := "" # Will create a new lobby if empty.
@export var mesh := true # Will use the lobby host as relay otherwise.
var ws := WebSocketPeer.new()
var code := 1000
var reason := "Unknown"
var old_state := WebSocketPeer.STATE_CLOSED
signal lobby_joined(lobby: String)
signal connected(id: int, use_mesh: bool)
signal disconnected()
signal peer_connected(id: int)
signal peer_disconnected(id: int)
signal offer_received(id: int, offer: int)
signal answer_received(id: int, answer: int)
signal candidate_received(id: int, mid: String, index: int, sdp: String)
signal lobby_sealed()
func connect_to_url(url: String) -> void:
close()
code = 1000
reason = "Unknown"
ws.connect_to_url(url)
func close() -> void:
ws.close()
func _process(_delta: float) -> void:
ws.poll()
var state := ws.get_ready_state()
if state != old_state and state == WebSocketPeer.STATE_OPEN and autojoin:
join_lobby(lobby)
while state == WebSocketPeer.STATE_OPEN and ws.get_available_packet_count():
if not _parse_msg():
print("Error parsing message from server.")
if state != old_state and state == WebSocketPeer.STATE_CLOSED:
code = ws.get_close_code()
reason = ws.get_close_reason()
disconnected.emit()
old_state = state
func _parse_msg() -> bool:
var parsed: Dictionary = JSON.parse_string(ws.get_packet().get_string_from_utf8())
if typeof(parsed) != TYPE_DICTIONARY or not parsed.has("type") or not parsed.has("id") or \
typeof(parsed.get("data")) != TYPE_STRING:
return false
var msg := parsed as Dictionary
if not str(msg.type).is_valid_int() or not str(msg.id).is_valid_int():
return false
var type := str(msg.type).to_int()
var src_id := str(msg.id).to_int()
if type == Message.ID:
connected.emit(src_id, msg.data == "true")
elif type == Message.JOIN:
lobby_joined.emit(msg.data)
elif type == Message.SEAL:
lobby_sealed.emit()
elif type == Message.PEER_CONNECT:
# Client connected.
peer_connected.emit(src_id)
elif type == Message.PEER_DISCONNECT:
# Client connected.
peer_disconnected.emit(src_id)
elif type == Message.OFFER:
# Offer received.
offer_received.emit(src_id, msg.data)
elif type == Message.ANSWER:
# Answer received.
answer_received.emit(src_id, msg.data)
elif type == Message.CANDIDATE:
# Candidate received.
var candidate: PackedStringArray = msg.data.split("\n", false)
if candidate.size() != 3:
return false
if not candidate[1].is_valid_int():
return false
candidate_received.emit(src_id, candidate[0], candidate[1].to_int(), candidate[2])
else:
return false
return true # Parsed.
func join_lobby(lobby: String) -> Error:
return _send_msg(Message.JOIN, 0 if mesh else 1, lobby)
func seal_lobby() -> Error:
return _send_msg(Message.SEAL, 0)
func send_candidate(id: int, mid: String, index: int, sdp: String) -> Error:
return _send_msg(Message.CANDIDATE, id, "\n%s\n%d\n%s" % [mid, index, sdp])
func send_offer(id: int, offer: String) -> Error:
return _send_msg(Message.OFFER, id, offer)
func send_answer(id: int, answer: String) -> Error:
return _send_msg(Message.ANSWER, id, answer)
func _send_msg(type: int, id: int, data: String = "") -> Error:
return ws.send_text(JSON.stringify({
"type": type,
"id": id,
"data": data,
}))