WIP
This commit is contained in:
parent
25b93a9f2b
commit
d2abbb69f2
|
@ -1,29 +0,0 @@
|
||||||
[remap]
|
|
||||||
|
|
||||||
importer="font_data_dynamic"
|
|
||||||
type="FontData"
|
|
||||||
uid="uid://cklw0gsblqjmg"
|
|
||||||
path="res://.godot/imported/iosevkalyte-regular.ttf-a2a88ad4f5b4e12dda9997dfa2756a6e.fontdata"
|
|
||||||
|
|
||||||
[deps]
|
|
||||||
|
|
||||||
source_file="res://assets/fonts/iosevkalyte/iosevkalyte-regular.ttf"
|
|
||||||
dest_files=["res://.godot/imported/iosevkalyte-regular.ttf-a2a88ad4f5b4e12dda9997dfa2756a6e.fontdata"]
|
|
||||||
|
|
||||||
[params]
|
|
||||||
|
|
||||||
antialiased=true
|
|
||||||
multichannel_signed_distance_field=false
|
|
||||||
msdf_pixel_range=8
|
|
||||||
msdf_size=48
|
|
||||||
force_autohinter=false
|
|
||||||
hinting=1
|
|
||||||
oversampling=0.0
|
|
||||||
compress=true
|
|
||||||
preload/char_ranges=PackedStringArray()
|
|
||||||
preload/glyph_ranges=PackedStringArray()
|
|
||||||
preload/configurations=PackedStringArray()
|
|
||||||
support_overrides/language_enabled=PackedStringArray()
|
|
||||||
support_overrides/language_disabled=PackedStringArray()
|
|
||||||
support_overrides/script_enabled=PackedStringArray()
|
|
||||||
support_overrides/script_disabled=PackedStringArray()
|
|
|
@ -3,7 +3,7 @@
|
||||||
[ext_resource path="res://assets/fonts/iosevkalyte/iosevkalyte.tres" type="DynamicFont" id=1]
|
[ext_resource path="res://assets/fonts/iosevkalyte/iosevkalyte.tres" type="DynamicFont" id=1]
|
||||||
[ext_resource path="res://assets/img/panel.png" type="Texture" id=2]
|
[ext_resource path="res://assets/img/panel.png" type="Texture" id=2]
|
||||||
|
|
||||||
[sub_resource type="Image" id=1]
|
[sub_resource type="Image" id=5]
|
||||||
data = {
|
data = {
|
||||||
"data": PoolByteArray( 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42 ),
|
"data": PoolByteArray( 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42, 37, 37, 42 ),
|
||||||
"format": "RGB8",
|
"format": "RGB8",
|
||||||
|
@ -15,7 +15,7 @@ data = {
|
||||||
[sub_resource type="ImageTexture" id=2]
|
[sub_resource type="ImageTexture" id=2]
|
||||||
flags = 4
|
flags = 4
|
||||||
flags = 4
|
flags = 4
|
||||||
image = SubResource( 1 )
|
image = SubResource( 5 )
|
||||||
size = Vector2( 8, 8 )
|
size = Vector2( 8, 8 )
|
||||||
|
|
||||||
[sub_resource type="StyleBoxTexture" id=3]
|
[sub_resource type="StyleBoxTexture" id=3]
|
||||||
|
|
|
@ -36,7 +36,7 @@ Global="*res://scripts/global/global.gd"
|
||||||
|
|
||||||
[gdnative]
|
[gdnative]
|
||||||
|
|
||||||
singletons=[ "res://webrtc/webrtc.tres" ]
|
singletons=[ "res://webrtc/webrtc_debug.tres" ]
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
|
|
|
@ -62,10 +62,10 @@ __meta__ = {
|
||||||
}
|
}
|
||||||
|
|
||||||
[node name="subhead" type="HBoxContainer" parent="v"]
|
[node name="subhead" type="HBoxContainer" parent="v"]
|
||||||
visible = false
|
|
||||||
margin_top = 54.0
|
margin_top = 54.0
|
||||||
margin_right = 984.0
|
margin_right = 984.0
|
||||||
margin_bottom = 85.0
|
margin_bottom = 85.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
[node name="label" type="Label" parent="v/subhead"]
|
[node name="label" type="Label" parent="v/subhead"]
|
||||||
margin_right = 830.0
|
margin_right = 830.0
|
||||||
|
@ -83,7 +83,7 @@ rect_min_size = Vector2( 150, 0 )
|
||||||
placeholder_text = "Your Name Here"
|
placeholder_text = "Your Name Here"
|
||||||
|
|
||||||
[node name="body" type="ScrollContainer" parent="v"]
|
[node name="body" type="ScrollContainer" parent="v"]
|
||||||
margin_top = 54.0
|
margin_top = 89.0
|
||||||
margin_right = 984.0
|
margin_right = 984.0
|
||||||
margin_bottom = 560.0
|
margin_bottom = 560.0
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
|
@ -91,7 +91,7 @@ size_flags_vertical = 3
|
||||||
|
|
||||||
[node name="p" type="PanelContainer" parent="v/body"]
|
[node name="p" type="PanelContainer" parent="v/body"]
|
||||||
margin_right = 984.0
|
margin_right = 984.0
|
||||||
margin_bottom = 506.0
|
margin_bottom = 471.0
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
@ -99,21 +99,21 @@ size_flags_vertical = 3
|
||||||
margin_left = 7.0
|
margin_left = 7.0
|
||||||
margin_top = 7.0
|
margin_top = 7.0
|
||||||
margin_right = 977.0
|
margin_right = 977.0
|
||||||
margin_bottom = 499.0
|
margin_bottom = 464.0
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
|
|
||||||
[node name="zero_state" type="CenterContainer" parent="v/body/p/lobbies"]
|
[node name="zero_state" type="CenterContainer" parent="v/body/p/lobbies"]
|
||||||
margin_right = 970.0
|
margin_right = 970.0
|
||||||
margin_bottom = 492.0
|
margin_bottom = 457.0
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="v/body/p/lobbies/zero_state"]
|
[node name="Label" type="Label" parent="v/body/p/lobbies/zero_state"]
|
||||||
margin_left = 177.0
|
margin_left = 177.0
|
||||||
margin_top = 235.0
|
margin_top = 218.0
|
||||||
margin_right = 793.0
|
margin_right = 793.0
|
||||||
margin_bottom = 256.0
|
margin_bottom = 239.0
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
text = "Looks like there are no active lobbies at the moment! Why don't you make one?"
|
text = "Looks like there are no active lobbies at the moment! Why don't you make one?"
|
||||||
|
|
|
@ -107,6 +107,6 @@ hint_tooltip = "Open https://lyte.dev"
|
||||||
text = "lytedev"
|
text = "lytedev"
|
||||||
|
|
||||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/quit" to="." method="_on_JoinLobbyButton_pressed"]
|
[connection signal="pressed" from="VBoxContainer/HBoxContainer/quit" to="." method="_on_JoinLobbyButton_pressed"]
|
||||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/multiplayer" to="." method="_on_CreateLobbyButton_pressed"]
|
[connection signal="pressed" from="VBoxContainer/HBoxContainer/multiplayer" to="." method="_on_multiplayer_pressed"]
|
||||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/Singleplayer" to="." method="_on_Singleplayer_pressed"]
|
[connection signal="pressed" from="VBoxContainer/HBoxContainer/Singleplayer" to="." method="_on_Singleplayer_pressed"]
|
||||||
[connection signal="pressed" from="VBoxContainer/Container/VBoxContainer/HBoxContainer/LinkButton" to="." method="_on_LinkButton_pressed"]
|
[connection signal="pressed" from="VBoxContainer/Container/VBoxContainer/HBoxContainer/LinkButton" to="." method="_on_LinkButton_pressed"]
|
||||||
|
|
|
@ -185,6 +185,7 @@ text = "Send Message"
|
||||||
|
|
||||||
[connection signal="pressed" from="v/head/leave_button" to="." method="_on_leave_button_pressed"]
|
[connection signal="pressed" from="v/head/leave_button" to="." method="_on_leave_button_pressed"]
|
||||||
[connection signal="text_changed" from="v/head/lobby_info" to="." method="_on_lobby_info_text_changed"]
|
[connection signal="text_changed" from="v/head/lobby_info" to="." method="_on_lobby_info_text_changed"]
|
||||||
|
[connection signal="pressed" from="v/head/start" to="." method="_on_start_pressed"]
|
||||||
[connection signal="toggled" from="v/head/ready_up" to="." method="_on_ready_up_toggled"]
|
[connection signal="toggled" from="v/head/ready_up" to="." method="_on_ready_up_toggled"]
|
||||||
[connection signal="text_entered" from="v/body/v/h/chat" to="." method="_on_TextEdit_text_entered"]
|
[connection signal="text_entered" from="v/body/v/h/chat" to="." method="_on_TextEdit_text_entered"]
|
||||||
[connection signal="pressed" from="v/body/v/h/Button" to="." method="_on_Button_pressed"]
|
[connection signal="pressed" from="v/body/v/h/Button" to="." method="_on_Button_pressed"]
|
||||||
|
|
|
@ -1,52 +1,74 @@
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
const MultiplayerClient = preload("multiplayer_client.gd")
|
onready var signaller_url = "ws://localhost:8888"
|
||||||
|
# onready var signaller_url = "wss://webrtc-signaller.deno.dev:443"
|
||||||
|
|
||||||
onready var client = MultiplayerClient.new()
|
onready var ice_servers = [
|
||||||
|
{ "urls": ["stun:[::1]:3478", "stun:stun.l.google.com:19302"] },
|
||||||
|
# { "urls": ["stun:stun.l.google.com:19302"] }, # just google
|
||||||
|
# { "urls": ["stun:[::1]:3478"] }, # just localhost
|
||||||
|
]
|
||||||
|
|
||||||
# for command line flags
|
const SignallerClient = preload("signaller_client.gd")
|
||||||
onready var goto_multiplayer = false
|
const WebRTCNegotiator = preload("webrtc_negotiator.gd")
|
||||||
onready var create_lobby = false
|
|
||||||
onready var join_first_available_lobby = false
|
onready var signaller_client = SignallerClient.new(signaller_url)
|
||||||
|
onready var negotiator = WebRTCNegotiator.new(ice_servers, signaller_client)
|
||||||
|
|
||||||
|
onready var onetime_cmd_flags = {
|
||||||
|
"--multiplayer": false,
|
||||||
|
"--create-lobby": false,
|
||||||
|
"--join-first-available-lobby": false,
|
||||||
|
}
|
||||||
|
|
||||||
|
func check_onetime_flag(flag):
|
||||||
|
var result = onetime_cmd_flags["--%s" % flag]
|
||||||
|
onetime_cmd_flags["--%s" % flag] = false
|
||||||
|
return result
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
# client.signaller.connect("websocket_connected", self, "signaller_disconnected")
|
negotiator.signaller_client = signaller_client
|
||||||
add_child(client)
|
negotiator.ice_servers = ice_servers
|
||||||
client.signaller.connect("websocket_connected", self, "_signaller_connected")
|
add_child(negotiator)
|
||||||
|
|
||||||
for arg in OS.get_cmdline_args():
|
for flag in onetime_cmd_flags.keys():
|
||||||
match arg:
|
if flag in OS.get_cmdline_args():
|
||||||
"--multiplayer": goto_multiplayer = true
|
onetime_cmd_flags[flag] = true
|
||||||
"--create-lobby": create_lobby = true
|
|
||||||
"--join-first-available-lobby": join_first_available_lobby = true
|
|
||||||
var a: print("Unknown command line arg: %s" % a)
|
|
||||||
|
|
||||||
if goto_multiplayer:
|
|
||||||
goto_multiplayer = false
|
|
||||||
lobby_browser()
|
|
||||||
|
|
||||||
func goto_scene(scene_resource_name):
|
func goto_scene(scene_resource_name):
|
||||||
var _result = get_tree().change_scene("res://screens/%s.tscn" % scene_resource_name)
|
var _result = get_tree().change_scene("res://screens/%s.tscn" % scene_resource_name)
|
||||||
|
|
||||||
func main_menu():
|
func main_menu():
|
||||||
client.close()
|
negotiator.close()
|
||||||
goto_scene("main_menu")
|
goto_scene("main_menu")
|
||||||
|
|
||||||
|
func fake_singleplayer():
|
||||||
|
print("Faking network peer for singleplayer...")
|
||||||
|
negotiator.multiplayer.initialize(1, true)
|
||||||
|
get_tree().network_peer = negotiator.multiplayer
|
||||||
|
var peer: WebRTCPeerConnection = WebRTCPeerConnection.new()
|
||||||
|
peer.initialize()
|
||||||
|
negotiator.multiplayer.add_peer(peer, 1)
|
||||||
|
|
||||||
func start_singleplayer_game():
|
func start_singleplayer_game():
|
||||||
client.fake_singleplayer()
|
fake_singleplayer()
|
||||||
client.close()
|
negotiator.close()
|
||||||
|
goto_game()
|
||||||
|
|
||||||
|
func goto_game():
|
||||||
goto_scene("game")
|
goto_scene("game")
|
||||||
|
|
||||||
func _signaller_connected():
|
func _signaller_connected():
|
||||||
goto_scene("lobby_browser")
|
goto_scene("lobby_browser")
|
||||||
|
|
||||||
func lobby_browser():
|
func lobby_browser():
|
||||||
client.close()
|
negotiator.close()
|
||||||
Global.client.connect_to_signaller()
|
signaller_client.connect("connected", self, "_signaller_connected")
|
||||||
|
negotiator.connect_to_signaller()
|
||||||
|
|
||||||
func lobby():
|
func lobby():
|
||||||
goto_scene("multiplayer_lobby")
|
goto_scene("multiplayer_lobby")
|
||||||
|
|
||||||
func quit():
|
func quit():
|
||||||
client.close()
|
negotiator.close()
|
||||||
get_tree().quit()
|
get_tree().quit()
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
extends Node
|
|
||||||
|
|
||||||
"""
|
|
||||||
This module sets up WebRTC peer connections.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# var multiplayer_url = "wss://webrtc-signaller.deno.dev:443"
|
|
||||||
var multiplayer_url = "ws://localhost:8888"
|
|
||||||
# var multiplayer_url = "ws://echo.websocket.org"
|
|
||||||
var webrtc_ice_servers = [
|
|
||||||
{ "urls": ["stun:stun.l.google.com:19302"] },
|
|
||||||
# { "urls": ["stun:localhost:3478"] }
|
|
||||||
]
|
|
||||||
|
|
||||||
const SignallerClient = preload("signaller_client.gd")
|
|
||||||
|
|
||||||
onready var mp = WebRTCMultiplayer.new()
|
|
||||||
onready var signaller = SignallerClient.new()
|
|
||||||
|
|
||||||
func _ready():
|
|
||||||
signaller.connect("offer_received", self, "offer_received")
|
|
||||||
signaller.connect("answer_received", self, "answer_received")
|
|
||||||
signaller.connect("candidate_received", self, "candidate_received")
|
|
||||||
# signaller.connect("websocket_connected", self, "connected")
|
|
||||||
# signaller.connect("websocket_disconnected", self, "disconnected")
|
|
||||||
|
|
||||||
signaller.connect("peer_id_set", self, "_peer_id_set")
|
|
||||||
signaller.connect("peer_joined", self, "_peer_joined")
|
|
||||||
# mp.connect("peer_disconnected", self, "peer_disconnected")
|
|
||||||
# connect("lobby_sealed", self, "lobby_sealed")
|
|
||||||
add_child(signaller)
|
|
||||||
|
|
||||||
func fake_singleplayer():
|
|
||||||
print("Faking network peer for singleplayer...")
|
|
||||||
mp.initialize(1, true)
|
|
||||||
get_tree().network_peer = mp
|
|
||||||
var peer: WebRTCPeerConnection = WebRTCPeerConnection.new()
|
|
||||||
peer.initialize()
|
|
||||||
mp.add_peer(peer, 1)
|
|
||||||
|
|
||||||
func close():
|
|
||||||
mp.close()
|
|
||||||
signaller.close()
|
|
||||||
|
|
||||||
func connect_to_signaller():
|
|
||||||
close()
|
|
||||||
signaller.connect_to_websocket_signaller(multiplayer_url)
|
|
||||||
|
|
||||||
func _create_peer(peer_id):
|
|
||||||
# if peer_id == signaller.peer_id: return
|
|
||||||
var peer: WebRTCPeerConnection = WebRTCPeerConnection.new()
|
|
||||||
print("New Net Peer with peer_id %d" % [peer_id])
|
|
||||||
var _peer_init_results = peer.initialize({"iceServers": webrtc_ice_servers})
|
|
||||||
var _result = peer.connect("session_description_created", self, "_offer_created", [peer_id])
|
|
||||||
_result = peer.connect("ice_candidate_created", self, "_new_ice_candidate", [peer_id])
|
|
||||||
mp.add_peer(peer, peer_id)
|
|
||||||
var uid = mp.get_unique_id()
|
|
||||||
if peer_id > uid:
|
|
||||||
var offer_result = peer.create_offer()
|
|
||||||
print("Create Offer Result: %s" % offer_result)
|
|
||||||
else:
|
|
||||||
print("Did not create offer: %d <= %d" % [peer_id, uid])
|
|
||||||
return peer
|
|
||||||
|
|
||||||
func _new_ice_candidate(mid_name, index_name, sdp_name, peer_id):
|
|
||||||
print("New ICE Candidate - MID: %s, Index: %s, SDP: %s, PeerID: %s" % [mid_name, index_name, sdp_name, peer_id])
|
|
||||||
signaller.send_candidate(peer_id, mid_name, index_name, sdp_name)
|
|
||||||
|
|
||||||
func _offer_created(type, data, peer_id):
|
|
||||||
print("Offer created - Type: %s, PeerID: %s, Data: %s" % [type, peer_id, JSON.print(data)])
|
|
||||||
if not mp.has_peer(peer_id):
|
|
||||||
return
|
|
||||||
mp.get_peer(peer_id).connection.set_local_description(type, data)
|
|
||||||
if type == "offer":
|
|
||||||
signaller.send_offer(peer_id, data)
|
|
||||||
else:
|
|
||||||
signaller.send_answer(peer_id, data)
|
|
||||||
|
|
||||||
func _peer_id_set(peer_id):
|
|
||||||
print("Peer ID received %s - setting up to peer..." % [peer_id])
|
|
||||||
mp.initialize(peer_id, true)
|
|
||||||
get_tree().network_peer = mp
|
|
||||||
|
|
||||||
func _peer_joined(peers):
|
|
||||||
for i in range(len(peers)):
|
|
||||||
var peer = peers[i]
|
|
||||||
if peer.has("peerId"):
|
|
||||||
var peer_id = peer["peerId"]
|
|
||||||
if not mp.has_peer(peer_id):
|
|
||||||
_create_peer(peer_id)
|
|
||||||
|
|
||||||
func peer_disconnected(id):
|
|
||||||
print("Peer %s disconnected" % id)
|
|
||||||
if mp.has_peer(id):
|
|
||||||
mp.remove_peer(id)
|
|
||||||
|
|
||||||
func offer_received(data):
|
|
||||||
var id = data["peerId"]
|
|
||||||
if mp.has_peer(id):
|
|
||||||
print("Setting offer remote description: %s" % JSON.print(data))
|
|
||||||
mp.get_peer(id).connection.set_remote_description("offer", data["offer"])
|
|
||||||
else:
|
|
||||||
print("Received an offer for a peer with ID %s that hasn't been added" % id)
|
|
||||||
|
|
||||||
func answer_received(data):
|
|
||||||
var id = data["peerId"]
|
|
||||||
if mp.has_peer(id):
|
|
||||||
print("Setting answer remote description: %s" % JSON.print(data))
|
|
||||||
mp.get_peer(id).connection.set_remote_description("answer", data["answer"])
|
|
||||||
|
|
||||||
func candidate_received(data):
|
|
||||||
var id = data["peerId"]
|
|
||||||
if mp.has_peer(id):
|
|
||||||
print("Adding ice candidate: %s" % JSON.print(data))
|
|
||||||
mp.get_peer(id).connection.add_ice_candidate(data["mid"], data["index"], data["sdp"])
|
|
||||||
else:
|
|
||||||
print("Received candidate for non-existant peer %s" % id)
|
|
|
@ -3,168 +3,154 @@ extends Node
|
||||||
"""
|
"""
|
||||||
This module is responsible for making a WebSocket connection to the signaller
|
This module is responsible for making a WebSocket connection to the signaller
|
||||||
in order to enable establishish WebRTC P2P connections. Another module is
|
in order to enable establishish WebRTC P2P connections. Another module is
|
||||||
expected to fully setup the peer connections. (./multiplayer_client.gd)
|
expected to fully setup the peer connections.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
signal lobby_new(lobbiesList)
|
const DISPLAY_NAME_FILE = "user://display_name.txt"
|
||||||
signal lobby_delete(id)
|
const DEFAULT_DISPLAY_NAME = "UnnamedPlayer"
|
||||||
signal lobby_joined(id, peer_id)
|
|
||||||
signal lobby_left(id)
|
|
||||||
|
|
||||||
signal peer_joined(peers)
|
# lobby data
|
||||||
|
signal lobby_data_received(lobbies)
|
||||||
|
signal lobby_joined(lobby_and_peer)
|
||||||
|
signal lobby_left(id)
|
||||||
|
signal lobby_delete(id)
|
||||||
|
|
||||||
|
# peer data
|
||||||
|
signal peer_data_received(peers)
|
||||||
signal peer_left(id)
|
signal peer_left(id)
|
||||||
signal candidate_received(data)
|
|
||||||
|
# WebRTC negotiations
|
||||||
|
signal candidate_received(cand)
|
||||||
signal offer_received(data)
|
signal offer_received(data)
|
||||||
signal answer_received(data)
|
signal answer_received(data)
|
||||||
signal client_id_set(client_id)
|
|
||||||
signal peer_id_set(peer_id)
|
|
||||||
signal websocket_connected
|
|
||||||
signal websocket_disconnected
|
|
||||||
|
|
||||||
onready var ws: WebSocketClient = WebSocketClient.new()
|
# underlying websocket
|
||||||
|
signal received_message
|
||||||
|
signal connected
|
||||||
|
signal connection_failure
|
||||||
|
signal disconnected
|
||||||
|
|
||||||
|
onready var websocket: WebSocketClient = WebSocketClient.new()
|
||||||
|
# TODO: setget these?
|
||||||
onready var client_id = null
|
onready var client_id = null
|
||||||
onready var lobby_id = null
|
onready var display_name = DEFAULT_DISPLAY_NAME setget set_display_name
|
||||||
onready var peer_id = null
|
onready var peer_id = null
|
||||||
onready var display_name = "UnnamedPlayer"
|
|
||||||
onready var lobby_name = null
|
|
||||||
|
|
||||||
func is_host(): return peer_id == 1
|
var websocket_url = null
|
||||||
|
|
||||||
const DISPLAY_NAME_FILE = "user://display_name.txt"
|
func _init(url):
|
||||||
|
websocket_url = url
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var dnf = File.new()
|
display_name = _load_display_name()
|
||||||
if dnf.open(DISPLAY_NAME_FILE, File.READ) == OK:
|
websocket.connect("data_received", self, "_handle_data")
|
||||||
display_name = dnf.get_as_text()
|
websocket.connect("connection_established", self, "_connected")
|
||||||
dnf.close()
|
# websocket.connect("connection_succeeded", self, "_connection_succeeded")
|
||||||
var _result = ws.connect("data_received", self, "_parse_msg")
|
websocket.connect("connection_closed", self, "_closed")
|
||||||
_result = ws.connect("connection_established", self, "_connected")
|
websocket.connect("connection_error", self, "_connection_error", [false])
|
||||||
_result = ws.connect("connection_closed", self, "_closed")
|
websocket.connect("connection_failed", self, "_connection_error", [false])
|
||||||
_result = ws.connect("connection_error", self, "_closed", [false])
|
websocket.connect("server_close_request", self, "_close_request")
|
||||||
_result = ws.connect("connection_failed", self, "_closed", [false])
|
|
||||||
_result = ws.connect("connection_succeeded", self, "_succ")
|
|
||||||
_result = ws.connect("server_close_request", self, "_close_request")
|
|
||||||
|
|
||||||
func _succ():
|
func connect_websocket():
|
||||||
print("WebSocket Connection Succeeded")
|
close()
|
||||||
|
print("Attempting to connect to WebSocket signalling server at %s" % websocket_url)
|
||||||
|
var result = websocket.connect_to_url(websocket_url)
|
||||||
|
if result != OK:
|
||||||
|
print("Failed to connect to WebSocket signalling server at %s: %s" % [websocket_url, result])
|
||||||
|
|
||||||
func close():
|
func close():
|
||||||
ws.disconnect_from_host()
|
websocket.disconnect_from_host()
|
||||||
|
|
||||||
func connect_to_websocket_signaller(url: String):
|
func set_display_name(new_display_name: String):
|
||||||
print("WebSocket: %s" % ws)
|
display_name = new_display_name
|
||||||
close()
|
_send("update_display_name:%s" % display_name)
|
||||||
print("Attempting to connect to WebSocket signalling server at %s" % url)
|
|
||||||
var result = ws.connect_to_url(url)
|
|
||||||
if result != OK:
|
|
||||||
print("FAILED TO CONNECT TO %s" % url)
|
|
||||||
print("WebSocket Connect Result: %s" % result)
|
|
||||||
|
|
||||||
func _closed(unknown):
|
func request_lobby_list():
|
||||||
print("WebSocket closed: %s: " % unknown)
|
return _send("request_lobby_list")
|
||||||
emit_signal("websocket_disconnected")
|
|
||||||
|
|
||||||
func _close_request(code: int, reason: String):
|
|
||||||
print("Received WebSocket close request from signalling server - Code: %s, Reason: %s" % [code, reason])
|
|
||||||
|
|
||||||
func _connected(protocol = ""):
|
|
||||||
print("WebSocket signaller connected via protocol %s" % protocol)
|
|
||||||
ws.get_peer(1).set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
|
|
||||||
emit_signal("websocket_connected")
|
|
||||||
_send("json:%s" % JSON.print({
|
|
||||||
"type": "init",
|
|
||||||
"data": {
|
|
||||||
"name": display_name
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
|
|
||||||
func _process(_delta: float):
|
|
||||||
var status: int = ws.get_connection_status()
|
|
||||||
if status == WebSocketClient.CONNECTION_CONNECTED or status == WebSocketClient.CONNECTION_CONNECTING:
|
|
||||||
ws.poll()
|
|
||||||
func join_lobby(id: String):
|
func join_lobby(id: String):
|
||||||
return _send("lobby_join:%s" % id)
|
return _send("lobby_join:%s" % id)
|
||||||
|
|
||||||
func create_lobby():
|
func create_lobby():
|
||||||
return _send("lobby_create")
|
return _send("lobby_create")
|
||||||
|
|
||||||
func request_lobby_list():
|
func is_host(): return peer_id == 1
|
||||||
return _send("request_lobby_list")
|
|
||||||
|
|
||||||
func request_peer_list():
|
|
||||||
return _send("request_peer_list")
|
|
||||||
|
|
||||||
func set_display_name(new_display_name: String):
|
|
||||||
display_name = new_display_name
|
|
||||||
_send("update_display_name:%s" % display_name)
|
|
||||||
var dnf = File.new()
|
|
||||||
if dnf.open(DISPLAY_NAME_FILE, File.WRITE) == OK:
|
|
||||||
dnf.store_string(display_name)
|
|
||||||
dnf.close()
|
|
||||||
|
|
||||||
func _send(s: String):
|
|
||||||
return ws.get_peer(1).put_packet(s.to_utf8())
|
|
||||||
|
|
||||||
func set_lobby_name(s: String):
|
func set_lobby_name(s: String):
|
||||||
if is_host():
|
if is_host(): _send_json({"name": s}, "update_lobby")
|
||||||
_send("json:%s" % JSON.print({"type": "update_lobby", "data": {"name": s}}))
|
|
||||||
|
|
||||||
func lock_lobby():
|
func lock_lobby():
|
||||||
if is_host():
|
if is_host(): _send_json({"locked": true}, "update_lobby")
|
||||||
_send("json:%s" % JSON.print({"type": "update_lobby", "data": {"locked": true}}))
|
|
||||||
|
|
||||||
func set_lobby_max_players(n: int):
|
func set_lobby_max_players(n: int):
|
||||||
if is_host():
|
if is_host(): _send_json({"maxPlayers": n}, "update_lobby")
|
||||||
_send("json:%s" % JSON.print({"type": "update_lobby", "data": {"maxPlayers": n}}))
|
|
||||||
|
|
||||||
func set_ready(n: bool):
|
func request_peer_list(): _send("request_peer_list")
|
||||||
if !is_host():
|
|
||||||
_send("set_ready:%s" % JSON.print(n))
|
|
||||||
|
|
||||||
func _parse_msg():
|
func send_candidate(peerId, mid, index, sdp) -> int:
|
||||||
var msg: String = ws.get_peer(1).get_packet().get_string_from_utf8()
|
return _send_json({"peerId": peerId, "mid": mid, "index": index, "sdp": sdp}, "candidate")
|
||||||
|
|
||||||
|
func send_offer(peerId, offer) -> int:
|
||||||
|
return _send_json({"peerId": peerId, "offer": offer }, "offer")
|
||||||
|
|
||||||
|
func send_answer(peerId, answer) -> int:
|
||||||
|
return _send_json({"peerId": peerId, "answer": answer }, "answer")
|
||||||
|
|
||||||
|
func _closed(code):
|
||||||
|
print("WebSocket closed: %s: " % code)
|
||||||
|
emit_signal("disconnected")
|
||||||
|
|
||||||
|
func _close_request(code: int, reason: String):
|
||||||
|
print("Received WebSocket close request from signalling server - Code: %s, Reason: %s" % [code, reason])
|
||||||
|
# TODO: does this fire _closed?
|
||||||
|
|
||||||
|
func _connected(protocol = ""):
|
||||||
|
print("Signaller connected via WebSocket using protocol %s" % protocol)
|
||||||
|
websocket.get_peer(1).set_write_mode(WebSocketPeer.WRITE_MODE_TEXT)
|
||||||
|
emit_signal("connected")
|
||||||
|
_send_json({name = display_name}, "init")
|
||||||
|
|
||||||
|
func _process(_delta: float):
|
||||||
|
var status: int = websocket.get_connection_status()
|
||||||
|
if status == WebSocketClient.CONNECTION_CONNECTED or status == WebSocketClient.CONNECTION_CONNECTING:
|
||||||
|
websocket.poll()
|
||||||
|
|
||||||
|
func _handle_data():
|
||||||
|
var msg: String = websocket.get_peer(1).get_packet().get_string_from_utf8()
|
||||||
if msg.begins_with("json:"):
|
if msg.begins_with("json:"):
|
||||||
var data = JSON.parse(msg.substr(5))
|
var data = JSON.parse(msg.substr(5))
|
||||||
if data.error == OK:
|
if data.error == OK:
|
||||||
handle_message(data.result)
|
_process_message(data.result)
|
||||||
var _result = ws.get_peer(1).put_packet("".to_utf8())
|
var _result = websocket.get_peer(1).put_packet("".to_utf8())
|
||||||
else:
|
else:
|
||||||
print("Unhandled message: %s" % msg)
|
print("Unhandled message: %s" % msg)
|
||||||
|
|
||||||
func handle_message(data: Dictionary):
|
func _process_message(data: Dictionary):
|
||||||
match data["type"]:
|
match data["type"]:
|
||||||
"your_id":
|
"init":
|
||||||
client_id = data["data"]["id"]
|
client_id = data.id
|
||||||
emit_signal("client_id_set", client_id)
|
print("Signaller Received init response: %s" % data)
|
||||||
"your_peer_id":
|
"your_peer_id":
|
||||||
peer_id = int(data["data"])
|
peer_id = int(data.peerId)
|
||||||
emit_signal("peer_id_set", peer_id)
|
emit_signal("peer_id_set", peer_id)
|
||||||
|
|
||||||
"lobby_list": emit_signal("lobby_new", data["data"])
|
"lobby_data": emit_signal("lobby_data_received", data.data)
|
||||||
"lobby_new": emit_signal("lobby_new", [data])
|
"lobby_delete": emit_signal("lobby_delete", data.id)
|
||||||
"lobby_delete": emit_signal("lobby_delete", data["id"])
|
|
||||||
|
|
||||||
"lobby_joined":
|
"lobby_joined":
|
||||||
lobby_id = data["id"]
|
peer_id = data.peerId
|
||||||
lobby_name = data["name"]
|
emit_signal("lobby_joined", data)
|
||||||
peer_id = data["peerId"]
|
|
||||||
emit_signal("lobby_joined", data["id"], data["peerId"])
|
|
||||||
"lobby_left":
|
"lobby_left":
|
||||||
lobby_id = null
|
peer_id = null
|
||||||
lobby_name = null
|
|
||||||
emit_signal("lobby_left", data["id"])
|
emit_signal("lobby_left", data["id"])
|
||||||
|
|
||||||
"peer_joined":
|
"peer_data":
|
||||||
print(typeof(data), data)
|
print(typeof(data), data)
|
||||||
if data.get("id") != null: emit_signal("peer_joined", [data])
|
if data.get("id") != null: emit_signal("peer_joined", [data])
|
||||||
else: emit_signal("peer_joined", data["data"])
|
else: emit_signal("peer_joined", data["data"])
|
||||||
"peer_left":
|
"peer_left":
|
||||||
print("Peer Left: %s" % data)
|
print("Peer Left: %s" % data)
|
||||||
emit_signal("peer_left", data["data"])
|
emit_signal("peer_left", data)
|
||||||
"ready_change":
|
|
||||||
print("Peer Ready Change")
|
|
||||||
emit_signal("peer_joined", [data])
|
|
||||||
|
|
||||||
"candidate":
|
"candidate":
|
||||||
print("Candidate received - Data: %s" % JSON.print(data["data"]))
|
print("Candidate received - Data: %s" % JSON.print(data["data"]))
|
||||||
|
@ -176,29 +162,31 @@ func handle_message(data: Dictionary):
|
||||||
print("Answer received - Data: %s" % JSON.print(data["data"]))
|
print("Answer received - Data: %s" % JSON.print(data["data"]))
|
||||||
emit_signal("answer_received", data["data"])
|
emit_signal("answer_received", data["data"])
|
||||||
"ping":
|
"ping":
|
||||||
# print("Signaller Ping")
|
|
||||||
_send("pong")
|
_send("pong")
|
||||||
_: print("Unhandled Message - Data: %s" % JSON.print(data))
|
_: print("Unhandled Message - Data: %s" % JSON.print(data))
|
||||||
|
|
||||||
func send_candidate(peerId, mid, index, sdp) -> int:
|
func _load_display_name():
|
||||||
return _send("json:%s" % JSON.print({
|
var _display_name = DEFAULT_DISPLAY_NAME
|
||||||
"type": "candidate",
|
var display_name_file = File.new()
|
||||||
"data": {
|
if display_name_file.open(DISPLAY_NAME_FILE, File.READ) == OK:
|
||||||
"peerId": peerId,
|
_display_name = display_name_file.get_as_text()
|
||||||
"mid": mid,
|
else:
|
||||||
"index": index,
|
print("Failed to open %s for reading display_name, creating default" % DISPLAY_NAME_FILE)
|
||||||
"sdp": sdp
|
_store_display_name()
|
||||||
}
|
display_name_file.close()
|
||||||
}))
|
return _display_name
|
||||||
|
|
||||||
func send_offer(peerId, offer) -> int:
|
func _store_display_name():
|
||||||
return _send("json:%s" % JSON.print({ "type": "offer", "data": {"peerId": peerId, "offer": offer }}))
|
var display_name_file = File.new()
|
||||||
|
if display_name_file.open(DISPLAY_NAME_FILE, File.WRITE) == OK:
|
||||||
|
display_name_file.store_string(display_name)
|
||||||
|
else:
|
||||||
|
print("Failed to open %s for writing display_name" % DISPLAY_NAME_FILE)
|
||||||
|
display_name_file.close()
|
||||||
|
|
||||||
func send_answer(peerId, answer) -> int:
|
func _send(s: String):
|
||||||
return _send("json:%s" % JSON.print({ "type": "answer", "data": {"peerId": peerId, "answer": answer }}))
|
return websocket.get_peer(1).put_packet(s.to_utf8())
|
||||||
|
|
||||||
"""
|
func _send_json(data: Dictionary, type=null):
|
||||||
elif type.begins_with("S: "):
|
if type != null: data["type"] = type
|
||||||
emit_signal("lobby_sealed")
|
_send("json:%s" % JSON.print(data))
|
||||||
return
|
|
||||||
"""
|
|
||||||
|
|
107
scripts/global/webrtc_negotiator.gd
Normal file
107
scripts/global/webrtc_negotiator.gd
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
"""
|
||||||
|
This module sets up WebRTC peer connections.
|
||||||
|
"""
|
||||||
|
|
||||||
|
onready var webrtc = WebRTCMultiplayer.new()
|
||||||
|
|
||||||
|
var signaller_client = null
|
||||||
|
var ice_servers = null
|
||||||
|
|
||||||
|
func _init(_ice_servers, _signaller_client):
|
||||||
|
ice_servers = _ice_servers
|
||||||
|
signaller_client = _signaller_client
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
signaller_client.connect("offer_received", self, "_offer_received")
|
||||||
|
signaller_client.connect("answer_received", self, "_answer_received")
|
||||||
|
signaller_client.connect("candidate_received", self, "_candidate_received")
|
||||||
|
signaller_client.connect("connected", self, "_signaller_connected")
|
||||||
|
# signaller_client.connect("websocket_disconnected", self, "disconnected")
|
||||||
|
|
||||||
|
signaller_client.connect("peer_id_set", self, "_peer_id_set")
|
||||||
|
signaller_client.connect("peer_joined", self, "_peer_joined")
|
||||||
|
# webrtc.connect("peer_disconnected", self, "peer_disconnected")
|
||||||
|
# connect("lobby_sealed", self, "lobby_sealed")
|
||||||
|
add_child(self.signaller_client)
|
||||||
|
|
||||||
|
func _signaller_connected():
|
||||||
|
print("Connected to signaller. Will be using the following ICE servers: %s", ice_servers)
|
||||||
|
|
||||||
|
func close():
|
||||||
|
webrtc.close()
|
||||||
|
signaller_client.close()
|
||||||
|
|
||||||
|
func connect_to_signaller():
|
||||||
|
signaller_client.connect_websocket()
|
||||||
|
|
||||||
|
func _create_peer(peer_id):
|
||||||
|
# if peer_id == signaller_client.peer_id: return
|
||||||
|
var peer: WebRTCPeerConnection = WebRTCPeerConnection.new()
|
||||||
|
print("New Net Peer with peer_id %d" % [peer_id])
|
||||||
|
var _peer_init_results = peer.initialize({"iceServers": ice_servers})
|
||||||
|
var _result = peer.connect("session_description_created", self, "_offer_created", [peer_id])
|
||||||
|
_result = peer.connect("ice_candidate_created", self, "_new_ice_candidate", [peer_id])
|
||||||
|
webrtc.add_peer(peer, peer_id)
|
||||||
|
var uid = webrtc.get_unique_id()
|
||||||
|
if peer_id > uid:
|
||||||
|
var offer_result = peer.create_offer()
|
||||||
|
print("Create Offer Result: %s" % offer_result)
|
||||||
|
else:
|
||||||
|
print("Did not create offer: %d <= %d" % [peer_id, uid])
|
||||||
|
return peer
|
||||||
|
|
||||||
|
func _new_ice_candidate(mid_name, index_name, sdp_name, peer_id):
|
||||||
|
print("New ICE Candidate - MID: %s, Index: %s, SDP: %s, PeerID: %s" % [mid_name, index_name, sdp_name, peer_id])
|
||||||
|
signaller_client.send_candidate(peer_id, mid_name, index_name, sdp_name)
|
||||||
|
|
||||||
|
func _offer_created(type, data, peer_id):
|
||||||
|
print("Offer created - Type: %s, PeerID: %s, Data: %s" % [type, peer_id, JSON.print(data)])
|
||||||
|
if not webrtc.has_peer(peer_id):
|
||||||
|
return
|
||||||
|
webrtc.get_peer(peer_id).connection.set_local_description(type, data)
|
||||||
|
if type == "offer":
|
||||||
|
signaller_client.send_offer(peer_id, data)
|
||||||
|
else:
|
||||||
|
signaller_client.send_answer(peer_id, data)
|
||||||
|
|
||||||
|
func _peer_id_set(peer_id):
|
||||||
|
print("Peer ID received %s - setting up to peer..." % [peer_id])
|
||||||
|
webrtc.initialize(peer_id, true)
|
||||||
|
get_tree().network_peer = webrtc
|
||||||
|
|
||||||
|
func _peer_joined(peers):
|
||||||
|
for i in range(len(peers)):
|
||||||
|
var peer = peers[i]
|
||||||
|
if peer.has("peerId"):
|
||||||
|
var peer_id = peer["peerId"]
|
||||||
|
if not webrtc.has_peer(peer_id):
|
||||||
|
_create_peer(peer_id)
|
||||||
|
|
||||||
|
func peer_disconnected(id):
|
||||||
|
print("Peer %s disconnected" % id)
|
||||||
|
if webrtc.has_peer(id):
|
||||||
|
webrtc.remove_peer(id)
|
||||||
|
|
||||||
|
func offer_received(data):
|
||||||
|
var id = data["peerId"]
|
||||||
|
if webrtc.has_peer(id):
|
||||||
|
print("Setting offer remote description: %s" % JSON.print(data))
|
||||||
|
webrtc.get_peer(id).connection.set_remote_description("offer", data["offer"])
|
||||||
|
else:
|
||||||
|
print("Received an offer for a peer with ID %s that hasn't been added" % id)
|
||||||
|
|
||||||
|
func answer_received(data):
|
||||||
|
var id = data["peerId"]
|
||||||
|
if webrtc.has_peer(id):
|
||||||
|
print("Setting answer remote description: %s" % JSON.print(data))
|
||||||
|
webrtc.get_peer(id).connection.set_remote_description("answer", data["answer"])
|
||||||
|
|
||||||
|
func candidate_received(data):
|
||||||
|
var id = data["peerId"]
|
||||||
|
if webrtc.has_peer(id):
|
||||||
|
print("Adding ice candidate: %s" % JSON.print(data))
|
||||||
|
webrtc.get_peer(id).connection.add_ice_candidate(data["mid"], data["index"], data["sdp"])
|
||||||
|
else:
|
||||||
|
print("Received candidate for non-existant peer %s" % id)
|
|
@ -12,6 +12,8 @@ remotesync func add_player(peer_id):
|
||||||
var new_player = player.instance()
|
var new_player = player.instance()
|
||||||
new_player.set_network_master(peer_id)
|
new_player.set_network_master(peer_id)
|
||||||
add_child(new_player)
|
add_child(new_player)
|
||||||
|
new_player.global_position = Vector2(100, 100)
|
||||||
|
print("Added player: %s" % new_player)
|
||||||
|
|
||||||
func _on_Button_pressed():
|
func _on_Button_pressed():
|
||||||
Global.main_menu()
|
Global.main_menu()
|
||||||
|
|
|
@ -14,17 +14,16 @@ onready var lobbies = {}
|
||||||
onready var lobby = preload("res://objects/lobby.tscn")
|
onready var lobby = preload("res://objects/lobby.tscn")
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
display_name_edit.text = Global.client.signaller.display_name
|
display_name_edit.text = Global.signaller_client.display_name
|
||||||
Global.client.signaller.connect("lobby_new", self, "_lobby_new")
|
Global.signaller_client.connect("lobby_new", self, "_lobby_new")
|
||||||
Global.client.signaller.connect("lobby_delete", self, "_lobby_delete")
|
Global.signaller_client.connect("lobby_delete", self, "_lobby_delete")
|
||||||
Global.client.signaller.connect("lobby_joined", self, "_lobby_joined")
|
Global.signaller_client.connect("lobby_joined", self, "_lobby_joined")
|
||||||
Global.client.signaller.connect("lobby_left", self, "_lobby_left")
|
Global.signaller_client.connect("lobby_left", self, "_lobby_left")
|
||||||
Global.client.signaller.connect("websocket_disconnected", self, "_signaller_disconnected")
|
Global.signaller_client.connect("websocket_disconnected", self, "_signaller_disconnected")
|
||||||
Global.client.signaller.request_lobby_list()
|
Global.signaller_client.request_lobby_list()
|
||||||
|
|
||||||
if Global.create_lobby:
|
if Global.check_onetime_flag("create-lobby"):
|
||||||
Global.create_lobby = false
|
Global.signaller_client.create_lobby()
|
||||||
Global.client.signaller.create_lobby()
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
var ls = []
|
var ls = []
|
||||||
|
@ -35,13 +34,14 @@ func _ready():
|
||||||
|
|
||||||
# TODO: add search
|
# TODO: add search
|
||||||
func _input(ev):
|
func _input(ev):
|
||||||
if ev is InputEventKey and ev.pressed:
|
pass
|
||||||
if ev.scancode == KEY_T:
|
# if ev is InputEventKey and ev.pressed:
|
||||||
var ls = []
|
# if ev.scancode == KEY_T:
|
||||||
for n in range(5):
|
# var ls = []
|
||||||
var j = n + lobbies.size()
|
# for n in range(5):
|
||||||
ls.push_back({id = j, name = j, currentPlayers = j, maxPlayers = j, locked = false})
|
# var j = n + lobbies.size()
|
||||||
call_deferred("_lobby_new", ls)
|
# ls.push_back({id = j, name = j, currentPlayers = j, maxPlayers = j, locked = false})
|
||||||
|
# call_deferred("_lobby_new", ls)
|
||||||
|
|
||||||
func _signaller_disconnected():
|
func _signaller_disconnected():
|
||||||
Global.main_menu()
|
Global.main_menu()
|
||||||
|
@ -56,12 +56,12 @@ func _on_back_pressed():
|
||||||
Global.main_menu()
|
Global.main_menu()
|
||||||
|
|
||||||
func _on_create_lobby_pressed():
|
func _on_create_lobby_pressed():
|
||||||
Global.client.signaller.create_lobby()
|
Global.signaller_client.create_lobby()
|
||||||
|
|
||||||
func _on_join_pressed():
|
func _on_join_pressed():
|
||||||
var items = lobbies.get_selected_items()
|
var items = lobbies.get_selected_items()
|
||||||
if len(items) > 0:
|
if len(items) > 0:
|
||||||
Global.client.signaller.join_lobby(lobbies.get_item_metadata(items[0])["id"])
|
Global.signaller_client.join_lobby(lobbies.get_item_metadata(items[0])["id"])
|
||||||
|
|
||||||
func _lobby_new(new_lobbies: Array):
|
func _lobby_new(new_lobbies: Array):
|
||||||
# TODO: handle scrolling so that the user is never too jarred (like chat)
|
# TODO: handle scrolling so that the user is never too jarred (like chat)
|
||||||
|
@ -75,14 +75,14 @@ func _lobby_new(new_lobbies: Array):
|
||||||
|
|
||||||
if Global.join_first_available_lobby:
|
if Global.join_first_available_lobby:
|
||||||
Global.join_first_available_lobby = false
|
Global.join_first_available_lobby = false
|
||||||
Global.client.signaller.join_lobby(id)
|
Global.signaller_client.join_lobby(id)
|
||||||
|
|
||||||
func _lobby_delete(id: String):
|
func _lobby_delete(id: String):
|
||||||
print("Lobby Deleted: %s" % id)
|
print("Lobby Deleted: %s" % id)
|
||||||
_delete_lobby(id)
|
_delete_lobby(id)
|
||||||
|
|
||||||
func _add_lobby(id, lobby_data):
|
func _add_lobby(id, lobby_data):
|
||||||
call_deferred("update_lobbies_text")
|
call_deferred("_update_lobbies_text")
|
||||||
print("New Lobby ", lobby_data)
|
print("New Lobby ", lobby_data)
|
||||||
# if lobby_data.currentPlayers > 0:
|
# if lobby_data.currentPlayers > 0:
|
||||||
var new_lobby = lobby.instance()
|
var new_lobby = lobby.instance()
|
||||||
|
@ -91,19 +91,19 @@ func _add_lobby(id, lobby_data):
|
||||||
lobbies[id] = new_lobby
|
lobbies[id] = new_lobby
|
||||||
|
|
||||||
func _update_lobby(id, lobby_data):
|
func _update_lobby(id, lobby_data):
|
||||||
call_deferred("update_lobbies_text")
|
call_deferred("_update_lobbies_text")
|
||||||
print("Updated Lobby ", lobby_data)
|
print("Updated Lobby ", lobby_data)
|
||||||
lobbies[id].set_with_dict(lobby_data)
|
lobbies[id].set_with_dict(lobby_data)
|
||||||
|
|
||||||
func _delete_lobby(id):
|
func _delete_lobby(id):
|
||||||
call_deferred("update_lobbies_text")
|
call_deferred("_update_lobbies_text")
|
||||||
if lobbies.has(id):
|
if lobbies.has(id):
|
||||||
print("Removing lobby...")
|
print("Removing lobby...")
|
||||||
lobbies_grid.remove_child(lobbies[id])
|
lobbies_grid.remove_child(lobbies[id])
|
||||||
lobbies[id].queue_free()
|
lobbies[id].queue_free()
|
||||||
lobbies.erase(id)
|
lobbies.erase(id)
|
||||||
|
|
||||||
func update_lobbies_text():
|
func _update_lobbies_text():
|
||||||
var n = lobbies.size()
|
var n = lobbies.size()
|
||||||
lobbies_label.text = "Active Lobbies: %d" % n
|
lobbies_label.text = "Active Lobbies: %d" % n
|
||||||
if n < 1:
|
if n < 1:
|
||||||
|
@ -114,4 +114,4 @@ func update_lobbies_text():
|
||||||
lobbies_grid.remove_child(zero_state)
|
lobbies_grid.remove_child(zero_state)
|
||||||
|
|
||||||
func _on_display_name_text_changed(new_text):
|
func _on_display_name_text_changed(new_text):
|
||||||
Global.client.signaller.set_display_name(new_text)
|
Global.signaller_client.display_name = new_text
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
if Global.check_onetime_flag("multiplayer"):
|
||||||
|
_on_multiplayer_pressed()
|
||||||
|
|
||||||
func _on_Singleplayer_pressed():
|
func _on_Singleplayer_pressed():
|
||||||
Global.start_singleplayer_game()
|
Global.start_singleplayer_game()
|
||||||
|
|
||||||
func _on_CreateLobbyButton_pressed():
|
func _on_multiplayer_pressed():
|
||||||
Global.lobby_browser()
|
Global.lobby_browser()
|
||||||
|
|
||||||
func _on_JoinLobbyButton_pressed():
|
func _on_JoinLobbyButton_pressed():
|
||||||
Global.quit()
|
Global.quit()
|
||||||
|
|
||||||
|
|
||||||
func _on_LinkButton_pressed():
|
func _on_LinkButton_pressed():
|
||||||
OS.shell_open("https://lyte.dev")
|
OS.shell_open("https://lyte.dev")
|
||||||
|
|
|
@ -29,7 +29,7 @@ func _ready():
|
||||||
call_deferred("add_chat", "# Connected to %s" % Global.client.signaller.lobby_name)
|
call_deferred("add_chat", "# Connected to %s" % Global.client.signaller.lobby_name)
|
||||||
|
|
||||||
# hide/show controls depending on whether or not we're the host
|
# hide/show controls depending on whether or not we're the host
|
||||||
var is_host = Global.client.signaller.peer_id == 1
|
is_host = Global.client.signaller.peer_id == 1
|
||||||
if is_host:
|
if is_host:
|
||||||
ready_up.queue_free()
|
ready_up.queue_free()
|
||||||
else:
|
else:
|
||||||
|
@ -37,6 +37,7 @@ func _ready():
|
||||||
max_players.editable = false
|
max_players.editable = false
|
||||||
start.queue_free()
|
start.queue_free()
|
||||||
lock.queue_free()
|
lock.queue_free()
|
||||||
|
print("Setting up lobby... %s %s" % [Global.client.signaller.peer_id, is_host])
|
||||||
|
|
||||||
func _lobby_update(l):
|
func _lobby_update(l):
|
||||||
for u in l:
|
for u in l:
|
||||||
|
@ -48,7 +49,7 @@ func _lobby_update(l):
|
||||||
|
|
||||||
func _peer_joined(joined_peers):
|
func _peer_joined(joined_peers):
|
||||||
call_deferred("update_player_count")
|
call_deferred("update_player_count")
|
||||||
if Global.client.signaller.is_host(): call_deferred("update_can_start")
|
if is_host: call_deferred("update_can_start")
|
||||||
for peer_index in range(len(joined_peers)):
|
for peer_index in range(len(joined_peers)):
|
||||||
var peer_data = joined_peers[peer_index]
|
var peer_data = joined_peers[peer_index]
|
||||||
var id = peer_data["id"]
|
var id = peer_data["id"]
|
||||||
|
@ -112,6 +113,14 @@ func update_can_start():
|
||||||
if can_start: add_chat("! All players ready - game may now be started")
|
if can_start: add_chat("! All players ready - game may now be started")
|
||||||
start.disabled = !can_start
|
start.disabled = !can_start
|
||||||
|
|
||||||
|
func _on_start_pressed():
|
||||||
|
print("Start %s" % is_host)
|
||||||
|
if is_host: rpc("start_game")
|
||||||
|
|
||||||
|
remotesync func start_game():
|
||||||
|
print("Starting game!")
|
||||||
|
Global.goto_game()
|
||||||
|
|
||||||
func _lobby_left(_id): Global.lobby_browser()
|
func _lobby_left(_id): Global.lobby_browser()
|
||||||
func _on_leave_button_pressed(): Global.lobby_browser()
|
func _on_leave_button_pressed(): Global.lobby_browser()
|
||||||
func _on_TextEdit_text_entered(_new_text): send_chat_message()
|
func _on_TextEdit_text_entered(_new_text): send_chat_message()
|
||||||
|
|
265
server.ts
265
server.ts
|
@ -15,7 +15,7 @@ interface DataMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerDataObject = Record<
|
type ServerDataObject = Record<
|
||||||
string,
|
"peerId" | string,
|
||||||
string | number | symbol | null | boolean
|
string | number | symbol | null | boolean
|
||||||
>;
|
>;
|
||||||
type ServerData = ServerDataObject[] | ServerDataObject | string | boolean;
|
type ServerData = ServerDataObject[] | ServerDataObject | string | boolean;
|
||||||
|
@ -24,13 +24,11 @@ type Message = string | DataMessage;
|
||||||
const buildMessage = (
|
const buildMessage = (
|
||||||
type: string,
|
type: string,
|
||||||
data: ServerData | ServerData[],
|
data: ServerData | ServerData[],
|
||||||
) =>
|
) => {
|
||||||
Object.assign(
|
if (Array.isArray(data)) return { type, data };
|
||||||
{ type },
|
else if (typeof data === "object") return { type, ...data };
|
||||||
Array.isArray(data)
|
return `${type}:${data}`;
|
||||||
? { data }
|
};
|
||||||
: (typeof data === "object" ? data : { data }),
|
|
||||||
);
|
|
||||||
|
|
||||||
class Client {
|
class Client {
|
||||||
id: ID;
|
id: ID;
|
||||||
|
@ -38,7 +36,6 @@ class Client {
|
||||||
name: string;
|
name: string;
|
||||||
socket: WebSocket;
|
socket: WebSocket;
|
||||||
lobby: Lobby | null;
|
lobby: Lobby | null;
|
||||||
ready: boolean;
|
|
||||||
|
|
||||||
constructor(socket: WebSocket) {
|
constructor(socket: WebSocket) {
|
||||||
this.id = crypto.randomUUID();
|
this.id = crypto.randomUUID();
|
||||||
|
@ -46,7 +43,6 @@ class Client {
|
||||||
this.peerId = null;
|
this.peerId = null;
|
||||||
this.name = "Client";
|
this.name = "Client";
|
||||||
this.lobby = null;
|
this.lobby = null;
|
||||||
this.ready = false;
|
|
||||||
|
|
||||||
allClients.set(this.id, this);
|
allClients.set(this.id, this);
|
||||||
}
|
}
|
||||||
|
@ -55,13 +51,6 @@ class Client {
|
||||||
return this.socket.readyState == WebSocket.OPEN;
|
return this.socket.readyState == WebSocket.OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
setReady(ready: boolean) {
|
|
||||||
this.ready = ready;
|
|
||||||
this.lobby?.broadcast(
|
|
||||||
buildMessage("ready_change", { id: this.id, ready: this.ready }),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
remove() {
|
remove() {
|
||||||
this.lobbyLeave();
|
this.lobbyLeave();
|
||||||
if (this.isConnected()) {
|
if (this.isConnected()) {
|
||||||
|
@ -94,17 +83,24 @@ class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
peerList() {
|
peerList() {
|
||||||
if (!this.lobby) return;
|
if (!this.lobby) {
|
||||||
|
this.send(
|
||||||
|
buildMessage(
|
||||||
|
"info",
|
||||||
|
"you cannot request a list of peers unless you are in a lobby",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const peers: {
|
const peers: {
|
||||||
id: ID;
|
id: ID;
|
||||||
name: string;
|
name: string;
|
||||||
peerId: number | null;
|
peerId: number | null;
|
||||||
ready: boolean;
|
|
||||||
}[] = [];
|
}[] = [];
|
||||||
this.lobby.clients.forEach(({ id, name, peerId, ready }) =>
|
this.lobby.clients.forEach(({ id, name, peerId }) =>
|
||||||
peers.push({ id, name, peerId, ready })
|
peers.push({ id, name, peerId })
|
||||||
);
|
);
|
||||||
this.send(buildMessage("peer_joined", peers));
|
this.send(buildMessage("peer_data", peers));
|
||||||
// TODO: chunk async?
|
// TODO: chunk async?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,32 +112,15 @@ class Client {
|
||||||
locked: boolean;
|
locked: boolean;
|
||||||
currentPlayers: number;
|
currentPlayers: number;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
allLobbies.forEach((lobby) => {
|
allLobbies.forEach((lobby) => netLobbies.push(lobby.toData()));
|
||||||
const { id, name, maxPlayers, locked } = lobby;
|
this.send(buildMessage("lobby_data", netLobbies));
|
||||||
netLobbies.push({
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
maxPlayers,
|
|
||||||
locked,
|
|
||||||
currentPlayers: lobby.clients.size,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// TODO: chunk async?
|
|
||||||
this.send(buildMessage("lobby_list", netLobbies));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lobbyNew(lobby: Lobby) {
|
lobbyNew(lobby: Lobby) {
|
||||||
// if the client is already in a lobby, only send messages about their lobby
|
// if the client is already in a lobby, do not send them lobby updates
|
||||||
if (this.lobby && this.lobby != lobby) return;
|
if (this.lobby) return;
|
||||||
const { id, name, maxPlayers, locked } = lobby;
|
|
||||||
this.send(
|
this.send(
|
||||||
buildMessage("lobby_new", {
|
buildMessage("lobby_data", [lobby.toData()]),
|
||||||
id,
|
|
||||||
name,
|
|
||||||
maxPlayers,
|
|
||||||
locked,
|
|
||||||
currentPlayers: lobby.clients.size,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,10 +130,12 @@ class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
lobbyCreate(opts?: Partial<Lobby>) {
|
lobbyCreate(opts?: Partial<Lobby>) {
|
||||||
this.ready = true;
|
|
||||||
if (this.lobby) {
|
if (this.lobby) {
|
||||||
this.send(
|
this.send(
|
||||||
`[info] cannot create lobby (already in lobby ${this.lobby.id})`,
|
buildMessage(
|
||||||
|
"info",
|
||||||
|
`cannot create lobby: already in lobby ${this.lobby.id}`,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -163,22 +144,25 @@ class Client {
|
||||||
|
|
||||||
lobbyJoin(lobby: Lobby) {
|
lobbyJoin(lobby: Lobby) {
|
||||||
if (this.lobby) {
|
if (this.lobby) {
|
||||||
this.send(`[info] cannot join lobby (already in lobby ${this.lobby.id})`);
|
this.send(
|
||||||
|
buildMessage(
|
||||||
|
`info`,
|
||||||
|
`cannot join lobby: already in lobby ${this.lobby.id}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.lobby = lobby;
|
this.lobby = lobby;
|
||||||
lobby.addClient(this);
|
lobby.addClient(this);
|
||||||
this.send(
|
this.send(
|
||||||
buildMessage("lobby_joined", {
|
buildMessage("lobby_joined", {
|
||||||
id: lobby.id,
|
...this.lobby.toData(),
|
||||||
name: lobby.name,
|
|
||||||
peerId: this.peerId,
|
peerId: this.peerId,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
lobbyLeave() {
|
lobbyLeave() {
|
||||||
this.ready = false;
|
|
||||||
const leavingLobby = this.lobby;
|
const leavingLobby = this.lobby;
|
||||||
if (!leavingLobby) {
|
if (!leavingLobby) {
|
||||||
this.send(`[info] cannot leave lobby (not in a lobby)`);
|
this.send(`[info] cannot leave lobby (not in a lobby)`);
|
||||||
|
@ -219,6 +203,16 @@ class Lobby {
|
||||||
this.notify();
|
this.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toData() {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
name: this.name,
|
||||||
|
maxPlayers: this.maxPlayers,
|
||||||
|
locked: this.locked,
|
||||||
|
currentPlayers: this.clients.size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
update(
|
update(
|
||||||
requestor: Client,
|
requestor: Client,
|
||||||
newValues: { name?: string; maxPlayers?: number; locked?: boolean },
|
newValues: { name?: string; maxPlayers?: number; locked?: boolean },
|
||||||
|
@ -273,18 +267,17 @@ class Lobby {
|
||||||
crypto.getRandomValues(arr);
|
crypto.getRandomValues(arr);
|
||||||
client.peerId = Math.abs(arr[0]);
|
client.peerId = Math.abs(arr[0]);
|
||||||
}
|
}
|
||||||
client.send(buildMessage("your_peer_id", client.peerId.toString()));
|
client.send(buildMessage("init_peer", client.peerId.toString()));
|
||||||
this.broadcast(
|
this.broadcast(
|
||||||
buildMessage("peer_joined", [{
|
buildMessage("peer_data", [{
|
||||||
id: client.id,
|
id: client.id,
|
||||||
name: client.name,
|
name: client.name,
|
||||||
peerId: client.peerId,
|
peerId: client.peerId,
|
||||||
}]),
|
}]),
|
||||||
);
|
);
|
||||||
console.log("Sending peer_joined...");
|
|
||||||
client.send(
|
client.send(
|
||||||
buildMessage(
|
buildMessage(
|
||||||
"peer_joined",
|
"peer_data",
|
||||||
Array.from(this.clients.values()).map(
|
Array.from(this.clients.values()).map(
|
||||||
({ id, name, peerId }) => ({ id, name, peerId }),
|
({ id, name, peerId }) => ({ id, name, peerId }),
|
||||||
),
|
),
|
||||||
|
@ -303,6 +296,13 @@ class Lobby {
|
||||||
}
|
}
|
||||||
this.notify();
|
this.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPeer(peerId: number): Client | null {
|
||||||
|
for (const [_id, client] of this.clients) {
|
||||||
|
if (client.peerId == peerId) return client;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ClientMessage {
|
interface ClientMessage {
|
||||||
|
@ -316,86 +316,102 @@ interface ClientMessage {
|
||||||
data: ServerDataObject;
|
data: ServerDataObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseMessage(message: string): { type: string; data?: ServerData } {
|
||||||
|
const trimmedMessage = message.trim();
|
||||||
|
if (trimmedMessage.startsWith("json:")) {
|
||||||
|
const { type, ...data } = JSON.parse(trimmedMessage.substr(5));
|
||||||
|
return { type, data };
|
||||||
|
} else {
|
||||||
|
const splitAt = trimmedMessage.indexOf(":");
|
||||||
|
if (splitAt > 0) {
|
||||||
|
return {
|
||||||
|
type: trimmedMessage.substr(0, splitAt),
|
||||||
|
data: trimmedMessage.substr(splitAt + 1),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return { type: trimmedMessage };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// events
|
// events
|
||||||
function onMessage(client: Client, ev: MessageEvent) {
|
function onMessage(client: Client, ev: MessageEvent) {
|
||||||
// TODO: log who from?
|
// TODO: log who from?
|
||||||
const msg = ev.data.trim();
|
const msg = parseMessage(ev.data);
|
||||||
if (msg === "pong") return;
|
if (msg.type === "pong") return;
|
||||||
console.log("Client Message Received", msg);
|
console.log("Client Message Received", msg);
|
||||||
if (msg === "init") {
|
switch (msg.type) {
|
||||||
client.send(
|
case "init":
|
||||||
buildMessage("init", {
|
if (msg.data && (msg.data as { name: string })["name"]) {
|
||||||
|
client.name = (msg.data as { name: string }).name.toString();
|
||||||
|
}
|
||||||
|
client.send(buildMessage("init", {
|
||||||
id: client.id,
|
id: client.id,
|
||||||
|
peerId: client.peerId,
|
||||||
name: client.name,
|
name: client.name,
|
||||||
serverVersion: SERVER_VERSION,
|
serverVersion: SERVER_VERSION,
|
||||||
}),
|
}));
|
||||||
);
|
break;
|
||||||
}
|
case "lobby_create":
|
||||||
if (msg === "lobby_create") client.lobbyCreate();
|
client.lobbyCreate(msg.data as Partial<Lobby>);
|
||||||
if (msg.startsWith("set_ready:")) {
|
break;
|
||||||
client.setReady(JSON.parse(msg.split(":", 2)[1]));
|
case "lobby_leave":
|
||||||
}
|
client.lobbyLeave();
|
||||||
if (msg === "lobby_leave") client.lobbyLeave();
|
break;
|
||||||
if (msg === "request_lobby_list") client.lobbyList();
|
case "request_lobby_list":
|
||||||
if (msg === "request_peer_list") {
|
client.lobbyList();
|
||||||
if (client.lobby == null) {
|
break;
|
||||||
client.send(`[info] not in a lobby`);
|
case "request_peer_list":
|
||||||
} else {
|
|
||||||
client.peerList();
|
client.peerList();
|
||||||
}
|
break;
|
||||||
}
|
case "update_display_name":
|
||||||
if (msg.startsWith("update_display_name:")) {
|
if (msg.data) client.name = msg.data.toString();
|
||||||
const displayName = msg.substr("update_display_name:".indexOf(":") + 1);
|
break;
|
||||||
client.name = displayName;
|
case "lobby_join":
|
||||||
}
|
if (msg.data) {
|
||||||
if (msg.startsWith("lobby_join:")) {
|
const lobby = allLobbies.get(msg.data.toString());
|
||||||
const id = msg.substr(11);
|
if (lobby) {
|
||||||
const lobby = allLobbies.get(id);
|
client.lobbyJoin(lobby);
|
||||||
if (lobby) {
|
} else {
|
||||||
client.lobbyJoin(lobby);
|
client.send(buildMessage("info", `count not find lobby ${msg.data}`));
|
||||||
// client.peerList();
|
|
||||||
} else client.send(`[info] could not find lobby ${id}`);
|
|
||||||
}
|
|
||||||
if (msg.startsWith("json:")) {
|
|
||||||
const data: ClientMessage = JSON.parse(msg.substr(5));
|
|
||||||
if (data.type === "init") {
|
|
||||||
if (data.data.name) {
|
|
||||||
client.name = data.data.name.toString();
|
|
||||||
}
|
|
||||||
client.send(buildMessage("init", { id: client.id, name: client.name }));
|
|
||||||
} else if (data.type === "update_lobby") {
|
|
||||||
if (client.lobby) {
|
|
||||||
client.lobby.update(client, data["data"]);
|
|
||||||
} else {
|
|
||||||
client.send("[info] cannot update lobby (you're not even in one!)");
|
|
||||||
}
|
|
||||||
} else if (data.type === "lobby_create") {
|
|
||||||
client.lobbyCreate({ name: data.data?.name?.toString() });
|
|
||||||
if (data.data.name) {
|
|
||||||
client.name = data.data.name.toString();
|
|
||||||
}
|
|
||||||
client.send(buildMessage("init", { id: client.id, name: client.name }));
|
|
||||||
} else if (["candidate", "answer", "offer"].includes(data.type)) {
|
|
||||||
console.log("Received WebRTC Negotiation Message...");
|
|
||||||
if (typeof data.data === "object") {
|
|
||||||
const subdata = data.data;
|
|
||||||
if (typeof subdata["peerId"] === "number") {
|
|
||||||
const destPeerId: number = subdata["peerId"];
|
|
||||||
for (const iClient of client.lobby?.clients.values() || []) {
|
|
||||||
if (iClient.peerId == destPeerId) {
|
|
||||||
const payload = Object.assign({}, data);
|
|
||||||
const srcPeerId = client.peerId;
|
|
||||||
payload.data.peerId = srcPeerId;
|
|
||||||
console.log(
|
|
||||||
`Forwarding WebRTC Negotiation Message from peer ${srcPeerId} to peer ${destPeerId}...`,
|
|
||||||
);
|
|
||||||
iClient.send(payload);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case "update_lobby":
|
||||||
|
if (client.lobby) {
|
||||||
|
if (typeof (msg.data) === "object") {
|
||||||
|
client.lobby.update(client, msg.data as Partial<Lobby>);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
client.send(
|
||||||
|
buildMessage(
|
||||||
|
"info",
|
||||||
|
"failed to update lobby info: you are not in a lobby",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "candidate":
|
||||||
|
/* falls through */
|
||||||
|
case "answer":
|
||||||
|
/* falls through */
|
||||||
|
case "offer": {
|
||||||
|
if (!client.lobby) return;
|
||||||
|
console.log(`Received WebRTC Negotiation Message (type: ${msg.type})...`);
|
||||||
|
if (typeof msg.data !== "object") return;
|
||||||
|
const webrtcMessage = (msg.data as { peerId?: number });
|
||||||
|
if (!webrtcMessage.peerId || typeof webrtcMessage.peerId !== "number") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const destClient = client.lobby.getPeer(webrtcMessage.peerId);
|
||||||
|
if (!destClient || !destClient.peerId) return;
|
||||||
|
webrtcMessage.peerId = destClient.peerId;
|
||||||
|
destClient.send(buildMessage(msg.type, webrtcMessage));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
console.debug("Unknown message: ", msg);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,13 +444,10 @@ const PORT = parseInt(Deno.env.get("PORT") || "80");
|
||||||
console.log("Listening on port", PORT);
|
console.log("Listening on port", PORT);
|
||||||
const listener = Deno.listen({ port: PORT });
|
const listener = Deno.listen({ port: PORT });
|
||||||
for await (const conn of listener) {
|
for await (const conn of listener) {
|
||||||
// console.debug("Connection received:", conn);
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const server = Deno.serveHttp(conn);
|
const server = Deno.serveHttp(conn);
|
||||||
for await (const { respondWith, request } of server) {
|
for await (const { respondWith, request } of server) {
|
||||||
// console.debug("HTTP Request Received", request);
|
|
||||||
try {
|
try {
|
||||||
// console.warn(JSON.stringify([allClients, allLobbies]));
|
|
||||||
const { socket, response } = Deno.upgradeWebSocket(request);
|
const { socket, response } = Deno.upgradeWebSocket(request);
|
||||||
const client = new Client(socket);
|
const client = new Client(socket);
|
||||||
socket.onmessage = (ev) => onMessage(client, ev);
|
socket.onmessage = (ev) => onMessage(client, ev);
|
||||||
|
|
Loading…
Reference in a new issue