From 73fbde7747ff5c5b120984fdb896adb3f5c2f696 Mon Sep 17 00:00:00 2001 From: Seth Fenske <fenskesd@gmail.com> Date: Sat, 26 Apr 2025 16:06:26 -0500 Subject: [PATCH 1/2] Temp commit --- Host/Lobby/host.gd | 12 ---- Host/Lobby/host.tscn | 9 +++ Host/Networking/SignalingServer.gd | 93 ++++++++++++++++-------------- Host/Networking/rtc.gd | 19 ++++++ Host/TradingDay/trading_day.tscn | 8 ++- addons/ez_rtc/RTCSingleton.gd | 64 ++++++++++++++++++++ addons/ez_rtc/RTCSingleton.gd.uid | 1 + addons/ez_rtc/ez_rtc.gd | 22 +++++++ addons/ez_rtc/ez_rtc.gd.uid | 1 + addons/ez_rtc/plugin.cfg | 7 +++ addons/ez_rtc/rtc_listener.gd | 28 +++++++++ addons/ez_rtc/rtc_listener.gd.uid | 1 + project.godot | 9 +++ 13 files changed, 219 insertions(+), 55 deletions(-) create mode 100644 addons/ez_rtc/RTCSingleton.gd create mode 100644 addons/ez_rtc/RTCSingleton.gd.uid create mode 100644 addons/ez_rtc/ez_rtc.gd create mode 100644 addons/ez_rtc/ez_rtc.gd.uid create mode 100644 addons/ez_rtc/plugin.cfg create mode 100644 addons/ez_rtc/rtc_listener.gd create mode 100644 addons/ez_rtc/rtc_listener.gd.uid diff --git a/Host/Lobby/host.gd b/Host/Lobby/host.gd index 7203123..70298cb 100644 --- a/Host/Lobby/host.gd +++ b/Host/Lobby/host.gd @@ -1,5 +1,4 @@ extends Control -signal LobbyCodeChosen(code: String) @export var waitingScene: PackedScene @@ -7,17 +6,6 @@ signal LobbyCodeChosen(code: String) func _ready(): get_tree().set_auto_accept_quit(false) - $SignalingServer.LobbyInUse.connect(_lobby_in_use) - $SignalingServer.LobbyConnected.connect(_lobby_connected) - $SignalingServer.PlayerJoined.connect(add_player) - $SignalingServer.PlayerLeft.connect(remove_player) - $SignalingServer.LobbyClosed.connect(_close_lobby) - $SignalingServer.OfferRecieved.connect($RTCPeer.session_description_received) - $SignalingServer.AnswerRecieved.connect($RTCPeer.session_description_received) - $SignalingServer.IceCandidateReceived.connect($RTCPeer.add_remote_ice_candidate) - - $RTCPeer.SendData.connect($SignalingServer.send_packet) - IO.NewInputSource.connect(_handle_new_input_device) IO.InputAssignedToPlayer.connect(_addPlayerByInputDevice) diff --git a/Host/Lobby/host.tscn b/Host/Lobby/host.tscn index 32af749..65620fb 100644 --- a/Host/Lobby/host.tscn +++ b/Host/Lobby/host.tscn @@ -104,3 +104,12 @@ layout_mode = 1 [connection signal="pressed" from="VSplitContainer/CreateClose" to="." method="_on_create_close_pressed"] [connection signal="pressed" from="ControlBar/Play" to="." method="_on_play_pressed"] [connection signal="pressed" from="ControlBar/Quit" to="." method="_on_quit_pressed"] +[connection signal="AnswerRecieved" from="SignalingServer" to="RTCPeer" method="session_description_received"] +[connection signal="IceCandidateReceived" from="SignalingServer" to="RTCPeer" method="add_remote_ice_candidate"] +[connection signal="LobbyClosed" from="SignalingServer" to="." method="_close_lobby"] +[connection signal="LobbyConnected" from="SignalingServer" to="." method="_lobby_connected"] +[connection signal="LobbyInUse" from="SignalingServer" to="." method="_lobby_in_use"] +[connection signal="OfferRecieved" from="SignalingServer" to="RTCPeer" method="session_description_received"] +[connection signal="PlayerJoined" from="SignalingServer" to="." method="add_player"] +[connection signal="PlayerLeft" from="SignalingServer" to="." method="remove_player"] +[connection signal="SendData" from="RTCPeer" to="SignalingServer" method="send_packet"] diff --git a/Host/Networking/SignalingServer.gd b/Host/Networking/SignalingServer.gd index c642170..f89cb0c 100644 --- a/Host/Networking/SignalingServer.gd +++ b/Host/Networking/SignalingServer.gd @@ -1,44 +1,24 @@ extends Node -@export var ADDRESS: = "fenske.page" -@export var PORT: = 8916 - -var peer = WebSocketMultiplayerPeer.new() -var id: = 1 - # Called when the node enters the scene tree for the first time. func _ready(): - connect_to_signaling_server() + RTCSingleton.SendSignalingData.connect(self.send_packet) + self.OfferRecieved.connect(RTCSingleton.SessionDescriptionReceived) + self.AnswerRecieved.connect(RTCSingleton.SessionDescriptionReceived) + self.IceCandidateReceived.connect(RTCSingleton.OnIceCandidateReceived) + Connect() -signal OfferRecieved(type, sdp, remote_id) -signal AnswerRecieved(type, sdp, remote_id) -signal IceCandidateReceived(midName, indexName, sdpName, remoteId) +#region Server Connection +@export var ADDRESS: = "fenske.page" +@export var PORT: = 8916 +var peer = WebSocketMultiplayerPeer.new() -func _on_data_recieved(data: Dictionary): - if data.message == Globals.Message.id: - id = data.id - return - if data.message == Globals.Message.lobbyCreated: - _on_lobby_created(data) - return - if data.message == Globals.Message.lobbyUnavailable: - _on_lobby_unavailable() - return - if data.message == Globals.Message.playerJoined: - _on_player_joined(data) - return - if data.message == Globals.Message.playerLeft: - _on_player_left(data) - return - if data.message == Globals.Message.answer: - AnswerRecieved.emit("answer", data.sdp, data.id) - return - if data.message == Globals.Message.offer: - OfferRecieved.emit("offer", data.sdp, data.id) - return - if data.message == Globals.Message.candidate: - IceCandidateReceived.emit(data.mid, data.index, data.sdp, data.id) - return +func Connect(): + var err = peer.create_client("wss://%s:%s" % [ADDRESS, PORT]) + if err != OK: + print("Encountered error code: %s" % err) + print("Connecting to wss://%s:%s" % [ADDRESS, PORT]) +#endregion #region Lobby signal LobbyInUse @@ -79,7 +59,7 @@ func _on_player_left(data: Dictionary): #endregion -#region Basic I/O +#region Recieve Data func _process(_delta): if !has_packets(): return _on_data_recieved(get_packet_data()) @@ -92,15 +72,44 @@ func get_packet_data() -> Variant: var packet = peer.get_packet() if packet == null: return null return JSON.parse_string(packet.get_string_from_utf8()) +#endregion -func connect_to_signaling_server(): - var err = peer.create_client("wss://%s:%s" % [ADDRESS, PORT]) - if err != OK: - print("Encountered error code: %s" % err) - print("Connecting to wss://%s:%s" % [ADDRESS, PORT]) - +#region Output func send_packet(data: Dictionary): if !data.has("id"): data["id"]=id peer.put_packet(JSON.stringify(data).to_utf8_buffer()) #endregion + +#region Logic +signal OfferRecieved(type, sdp, remote_id) +signal AnswerRecieved(type, sdp, remote_id) +signal IceCandidateReceived(midName, indexName, sdpName, remoteId) +var id: = 1 + +func _on_data_recieved(data: Dictionary): + if data.message == Globals.Message.id: + id = data.id + return + if data.message == Globals.Message.lobbyCreated: + _on_lobby_created(data) + return + if data.message == Globals.Message.lobbyUnavailable: + _on_lobby_unavailable() + return + if data.message == Globals.Message.playerJoined: + _on_player_joined(data) + return + if data.message == Globals.Message.playerLeft: + _on_player_left(data) + return + if data.message == Globals.Message.answer: + AnswerRecieved.emit("answer", data.sdp, data.id) + return + if data.message == Globals.Message.offer: + OfferRecieved.emit("offer", data.sdp, data.id) + return + if data.message == Globals.Message.candidate: + IceCandidateReceived.emit(data.mid, data.index, data.sdp, data.id) + return +#endregion diff --git a/Host/Networking/rtc.gd b/Host/Networking/rtc.gd index d96b223..26c5969 100644 --- a/Host/Networking/rtc.gd +++ b/Host/Networking/rtc.gd @@ -1,5 +1,21 @@ +@tool extends Node +var OfflineTestFlag = "--offline" + +func _ready(): + isTestingMode = OS.get_cmdline_args().find(OfflineTestFlag) > 0 + +@onready var isTestingMode: = false +func IsTestingMode(): + return Engine.is_editor_hint() || isTestingMode + +func _enter_tree(): + print("Enter Tree") + +func _exit_tree(): + print("Exit Tree") + var rtcPeer : = WebRTCMultiplayerPeer.new() signal DataReceived(playerId: String, data: Variant) @@ -56,3 +72,6 @@ func SendData(data: Variant, peerId: int) -> void: var channel: WebRTCDataChannel = channels[peerId] channel.put_packet(data_buffer) #endregion + +func PutData(channel: WebRTCDataChannel, data: PackedByteArray): + channel.put_packet(data) diff --git a/Host/TradingDay/trading_day.tscn b/Host/TradingDay/trading_day.tscn index b697ae6..c8b42af 100644 --- a/Host/TradingDay/trading_day.tscn +++ b/Host/TradingDay/trading_day.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=12 format=3 uid="uid://cje1yvapa41qv"] +[gd_scene load_steps=13 format=3 uid="uid://cje1yvapa41qv"] [ext_resource type="Script" uid="uid://2wwwphpgxxp5" path="res://Host/TradingDay/background.gd" id="1_1xwot"] [ext_resource type="Script" uid="uid://e4fum3qxhatm" path="res://Host/TradingDay/Chart.gd" id="2_42rv4"] @@ -11,6 +11,7 @@ [ext_resource type="Script" uid="uid://cpeh82ihp5xpt" path="res://Host/TradingDay/Players.gd" id="7_1ys6b"] [ext_resource type="Script" uid="uid://c5j5s7p1gmkb1" path="res://Host/TradingDay/Price.gd" id="7_l1arb"] [ext_resource type="Script" uid="uid://mam3fov0mmuf" path="res://Host/TradingDay/card_controller.gd" id="10_vboce"] +[ext_resource type="Script" uid="uid://dn42mjo1mdk54" path="res://addons/ez_rtc/rtc_listener.gd" id="12_l1arb"] [node name="TradingDay" type="Node2D"] script = ExtResource("1_1xwot") @@ -71,6 +72,11 @@ GridNode = NodePath("../../Grid") [node name="CardController" type="Node" parent="."] script = ExtResource("10_vboce") +[node name="RTCListener" type="Node" parent="."] +process_mode = 4 +script = ExtResource("12_l1arb") +metadata/_custom_type_script = "uid://dn42mjo1mdk54" + [connection signal="ready" from="." to="." method="_on_ready"] [connection signal="DayFinished" from="Stocks" to="." method="DayFinished"] [connection signal="HourFinished" from="Stocks" to="Players" method="OnStockFinalized"] diff --git a/addons/ez_rtc/RTCSingleton.gd b/addons/ez_rtc/RTCSingleton.gd new file mode 100644 index 0000000..0babfa5 --- /dev/null +++ b/addons/ez_rtc/RTCSingleton.gd @@ -0,0 +1,64 @@ +extends Node + +signal SendSignalingData(data: Dictionary) +var channels : Dictionary = {} +var lobbyValue : = "" + +func AddDataChannel(connection: WebRTCDataChannel, playerId: int) -> void: + channels[playerId] = connection + +const STUN_SERVER_URL: = "stun:stun.l.google.com:19302" +var rtcPeer : = WebRTCMultiplayerPeer.new() + +var serverCreated: = false +func CreateRTCServer(lobby: String): + lobbyValue = lobby + # Skip if already instantiated + if serverCreated: + return + var err = RTC.rtcPeer.create_server() + serverCreated = true + +func CreateConnectionForPlayer(sourceId): + var peer = WebRTCPeerConnection.new() + peer.initialize({ "iceServers" : [{ "urls": [STUN_SERVER_URL] }] }) + peer.session_description_created.connect(OnSessionCreated.bind(sourceId)) + peer.ice_candidate_created.connect(OnIceCandidateCreated.bind(sourceId)) + var connection = peer.create_data_channel("chat", {"negotiated": true, "id": 0}) + AddDataChannel(connection, sourceId) + + RTC.rtcPeer.add_peer(peer, sourceId) + multiplayer.multiplayer_peer = RTC.rtcPeer + +#region Session +func OnSessionCreated(type, sdp, remoteId): + self.rtcPeer.get_peer(remoteId).connection.set_local_description(type, sdp) + SendSignalingData.emit({ + "message": Globals.Message.offer, + "lobbyValue": lobbyValue, + "type": type, + "sdp": sdp, + "remoteId": remoteId + }) + +func SessionDescriptionReceived(type, sdp, remote_id: int): + self.rtcPeer.get_peer(remote_id).connection.set_remote_description(type, sdp) +#endregion + +#region Ice Candidates +# Relays the signal from WebRTCPeerConnection +func OnIceCandidateCreated(midName, indexName, sdpName, remoteId): + SendSignalingData.emit({ + "message" : Globals.Message.candidate, + "lobbyValue": lobbyValue, + "mid": midName, + "index": indexName, + "sdp": sdpName, + "remoteId": remoteId + }) + +# Adds the new ice candidate +func OnIceCandidateReceived(midName, indexName, sdpName, remoteId): + var peer = self.rtcPeer.get_peer(remoteId) + peer.connection.add_ice_candidate(midName, indexName, sdpName) +#endregion diff --git a/addons/ez_rtc/RTCSingleton.gd.uid b/addons/ez_rtc/RTCSingleton.gd.uid new file mode 100644 index 0000000..431a991 --- /dev/null +++ b/addons/ez_rtc/RTCSingleton.gd.uid @@ -0,0 +1 @@ +uid://bsvdkeq85k38o diff --git a/addons/ez_rtc/ez_rtc.gd b/addons/ez_rtc/ez_rtc.gd new file mode 100644 index 0000000..ee8dbce --- /dev/null +++ b/addons/ez_rtc/ez_rtc.gd @@ -0,0 +1,22 @@ +@tool +extends EditorPlugin + +#region RTC Listener Custom Type +func _enter_tree(): + # Register the RTC Listener + add_custom_type("RTCListener", "Node", preload("res://addons/ez_rtc/rtc_listener.gd"), preload("res://Assets/icon.svg")) + +func _exit_tree(): + remove_custom_type("RTCListener") +#region RTC Listener Custom Type + +#region RTC Global +const GlobalName = "RTCSingleton" + +func _enable_plugin(): + # The autoload can be a scene or script file. + add_autoload_singleton(GlobalName, "res://addons/ez_rtc/RTCSingleton.gd") + +func _disable_plugin(): + remove_autoload_singleton(GlobalName) +#endregion diff --git a/addons/ez_rtc/ez_rtc.gd.uid b/addons/ez_rtc/ez_rtc.gd.uid new file mode 100644 index 0000000..c102d17 --- /dev/null +++ b/addons/ez_rtc/ez_rtc.gd.uid @@ -0,0 +1 @@ +uid://qh3y8ihmsu0s diff --git a/addons/ez_rtc/plugin.cfg b/addons/ez_rtc/plugin.cfg new file mode 100644 index 0000000..fb7856e --- /dev/null +++ b/addons/ez_rtc/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="EZ RTC" +description="A wrapper for the default Godot WebRTC exension which provides an easy way to establish RTC communication with a signaling server." +author="Seth Fenske" +version="1.0.0" +script="ez_rtc.gd" diff --git a/addons/ez_rtc/rtc_listener.gd b/addons/ez_rtc/rtc_listener.gd new file mode 100644 index 0000000..0239162 --- /dev/null +++ b/addons/ez_rtc/rtc_listener.gd @@ -0,0 +1,28 @@ +@tool +extends Node + +func _ready(): + if RTC!= null && !RTC.IsTestingMode(): + PutData.connect(RTC.SendData) + RTC.DataReceived.connect(self.RecieveData) + +func _enter_tree(): + # Don't process RTC events until we are connected. + self.process_mode = ProcessMode.PROCESS_MODE_DISABLED + +#region Send Data +signal PutData(channel: WebRTCDataChannel, data: PackedByteArray) + +func SendData(data: Variant) -> void: + var data_buffer: PackedByteArray = JSON.stringify(data).to_utf8_buffer() + PutData.emit(self.channel, data_buffer) +#endregion + +#region Read Data +@export var Sources: Array[String] +signal DataReceived(sourceId: String, data: Variant) + +func RecieveData(sourceId: String, data: Variant): + if (Sources.find(sourceId) > 0): + DataReceived.emit(sourceId, data) +#endregion diff --git a/addons/ez_rtc/rtc_listener.gd.uid b/addons/ez_rtc/rtc_listener.gd.uid new file mode 100644 index 0000000..c532d12 --- /dev/null +++ b/addons/ez_rtc/rtc_listener.gd.uid @@ -0,0 +1 @@ +uid://dn42mjo1mdk54 diff --git a/project.godot b/project.godot index e6e3a5a..5bb68c6 100644 --- a/project.godot +++ b/project.godot @@ -22,6 +22,7 @@ Globals="*res://Host/Networking/Globals.gd" IO="*res://Input/io.gd" Settings="*res://Host/GameSate/Settings.gd" GameState="*res://Host/GameSate/GameState.gd" +RTCSingleton="*res://addons/ez_rtc/RTCSingleton.gd" [display] @@ -29,6 +30,14 @@ window/stretch/mode="viewport" window/stretch/aspect="ignore" window/emulate_touch_from_mouse=true +[editor] + +run/main_run_args="--offline" + +[editor_plugins] + +enabled=PackedStringArray("res://addons/ez_rtc/plugin.cfg") + [file_customization] folder_colors={ -- GitLab From 1acb94fedf6cb6c9be228d899b61e70e1f9903b0 Mon Sep 17 00:00:00 2001 From: Seth Fenske <fenskesd@gmail.com> Date: Sat, 3 May 2025 16:47:12 -0500 Subject: [PATCH 2/2] Back to working demo --- Host/GameSate/GameState.gd | 4 +- Host/Lobby/host.gd | 13 ++--- Host/Lobby/host.tscn | 14 +++--- Host/Networking/RTCPeer.gd | 59 ----------------------- Host/Networking/RTCPeer.gd.uid | 1 - Host/Networking/SignalingServer.gd | 2 +- Host/SceneManager/scene_manager.gd | 2 - Host/TradingDay/Players.gd | 2 +- Host/TradingDay/Review/DayInReview.tscn | 8 +++- Host/TradingDay/Review/day_in_review.gd | 4 +- Host/TradingDay/Review/graph_point.gd | 8 ++-- Host/TradingDay/background.gd | 21 ++++----- Host/TradingDay/grid.tscn | 8 +--- Host/TradingDay/player_data_listener.gd | 10 ++-- Host/TradingDay/trading_day.tscn | 15 ++++-- Input/io.gd | 4 +- addons/ez_rtc/RTCSingleton.gd | 62 ++++++++++++++++++++---- addons/ez_rtc/rtc_listener.gd | 63 +++++++++++++++++++++---- project.godot | 6 +-- 19 files changed, 169 insertions(+), 137 deletions(-) delete mode 100644 Host/Networking/RTCPeer.gd delete mode 100644 Host/Networking/RTCPeer.gd.uid diff --git a/Host/GameSate/GameState.gd b/Host/GameSate/GameState.gd index 1e5587b..3cd8f1b 100644 --- a/Host/GameSate/GameState.gd +++ b/Host/GameSate/GameState.gd @@ -47,7 +47,9 @@ func SetHour(day: int, hour: int, data: TradingHourData): return func GetHour(day: int, hour: int) -> TradingHourData: - var dayData = Days.get(day) + var dayData = null + if day >= 0: + dayData = Days.get(day) if dayData == null: return null return GetHourFromData(dayData, hour) diff --git a/Host/Lobby/host.gd b/Host/Lobby/host.gd index 70298cb..9682f16 100644 --- a/Host/Lobby/host.gd +++ b/Host/Lobby/host.gd @@ -8,11 +8,12 @@ func _ready(): get_tree().set_auto_accept_quit(false) IO.NewInputSource.connect(_handle_new_input_device) IO.InputAssignedToPlayer.connect(_addPlayerByInputDevice) + connect_rtc() -func connect_rtc(rtc: RTC): - self.SendData.connect(rtc.SendData) - $SignalingServer.PlayerJoined.connect(rtc.AddName) - rtc.DataReceived.connect(_listen_to_rtc_data) +func connect_rtc(): + self.SendData.connect($RTCListener.SendData) + $SignalingServer.PlayerJoined.connect($RTCListener.AddPlayerName) + $RTCListener.DataReceived.connect(_listen_to_rtc_data) #region Shutdown func _notification(what): @@ -43,7 +44,7 @@ func _lobby_connected(lobbyCode: String): $VSplitContainer/CreateClose.text = "Close Lobby" host = false lobby_code = lobbyCode - $RTCPeer.create_rtc_server(lobbyCode) + $RTCListener.CreateLobby(lobbyCode) func _close_lobby(): for player in $Players.get_children(): @@ -97,7 +98,7 @@ func _addPlayerByInputDevice(playerId: String, input: IO.InputSource): $Players.add_child(playerLabel) func add_player(playerNumber:int, player_name): - $RTCPeer.create_connection_for_player(playerNumber) + $RTCListener.CreateConnectionForPlayer(playerNumber) func _listen_to_rtc_data(id: String, data: Variant): print("%s, %s" % [id, data]) diff --git a/Host/Lobby/host.tscn b/Host/Lobby/host.tscn index 65620fb..c9ad7ac 100644 --- a/Host/Lobby/host.tscn +++ b/Host/Lobby/host.tscn @@ -3,8 +3,8 @@ [ext_resource type="Script" uid="uid://cgey0jytirsj2" path="res://Host/Lobby/host.gd" id="1_janmn"] [ext_resource type="Script" uid="uid://cx616v3q25qt8" path="res://Host/Networking/SignalingServer.gd" id="2_cdhtb"] [ext_resource type="PackedScene" uid="uid://cho5kftxmyvd7" path="res://Client/ClientWaiting.tscn" id="2_jjtug"] -[ext_resource type="Script" uid="uid://dd36r0cpk568y" path="res://Host/Networking/RTCPeer.gd" id="3_vjxk6"] [ext_resource type="PackedScene" uid="uid://stub6ra523l5" path="res://Host/Lobby/NewInputDevice.tscn" id="5_bhg8j"] +[ext_resource type="Script" uid="uid://dn42mjo1mdk54" path="res://addons/ez_rtc/rtc_listener.gd" id="6_lqk0a"] [ext_resource type="PackedScene" uid="uid://5oprdqg6eaev" path="res://Host/Menu/SettingsButton.tscn" id="8_jssyn"] [node name="Lobby" type="Control"] @@ -94,22 +94,20 @@ scale = Vector2(0.25, 0.25) [node name="SignalingServer" type="Node" parent="."] script = ExtResource("2_cdhtb") -[node name="RTCPeer" type="Node" parent="."] -script = ExtResource("3_vjxk6") - [node name="Settings" parent="." instance=ExtResource("8_jssyn")] layout_mode = 1 +[node name="RTCListener" type="Node" parent="."] +process_mode = 4 +script = ExtResource("6_lqk0a") +metadata/_custom_type_script = "uid://dn42mjo1mdk54" + [connection signal="text_submitted" from="VSplitContainer/LobbyInfoBar/LobyCodeEditor" to="." method="_on_loby_code_editor_text_submitted"] [connection signal="pressed" from="VSplitContainer/CreateClose" to="." method="_on_create_close_pressed"] [connection signal="pressed" from="ControlBar/Play" to="." method="_on_play_pressed"] [connection signal="pressed" from="ControlBar/Quit" to="." method="_on_quit_pressed"] -[connection signal="AnswerRecieved" from="SignalingServer" to="RTCPeer" method="session_description_received"] -[connection signal="IceCandidateReceived" from="SignalingServer" to="RTCPeer" method="add_remote_ice_candidate"] [connection signal="LobbyClosed" from="SignalingServer" to="." method="_close_lobby"] [connection signal="LobbyConnected" from="SignalingServer" to="." method="_lobby_connected"] [connection signal="LobbyInUse" from="SignalingServer" to="." method="_lobby_in_use"] -[connection signal="OfferRecieved" from="SignalingServer" to="RTCPeer" method="session_description_received"] [connection signal="PlayerJoined" from="SignalingServer" to="." method="add_player"] [connection signal="PlayerLeft" from="SignalingServer" to="." method="remove_player"] -[connection signal="SendData" from="RTCPeer" to="SignalingServer" method="send_packet"] diff --git a/Host/Networking/RTCPeer.gd b/Host/Networking/RTCPeer.gd deleted file mode 100644 index 0e2dfea..0000000 --- a/Host/Networking/RTCPeer.gd +++ /dev/null @@ -1,59 +0,0 @@ -extends Node -signal SendData(data: Dictionary) - -@export var url: = "stun:stun.l.google.com:19302" - -var lobbyValue : = "" - -@onready var serverCreated = false -func create_rtc_server(lobby: String): - lobbyValue = lobby - # Skip if already instantiated - if serverCreated: - return - var err = RTC.rtcPeer.create_server() - serverCreated = true - -func create_connection_for_player(playerId): - var peer = WebRTCPeerConnection.new() - peer.initialize({ - "iceServers" : [{ "urls": [url] }] - }) - peer.session_description_created.connect(_on_session_created.bind(playerId)) - peer.ice_candidate_created.connect(ice_candidate_created.bind(playerId)) - var connection = peer.create_data_channel("chat", {"negotiated": true, "id": 0}) - RTC.AddDataChannel(connection, playerId) - - RTC.rtcPeer.add_peer(peer, playerId) - multiplayer.multiplayer_peer = RTC.rtcPeer - -#region Session -func _on_session_created(type, sdp, remoteId): - RTC.rtcPeer.get_peer(remoteId).connection.set_local_description(type, sdp) - SendData.emit({ - "message": Globals.Message.offer, - "lobbyValue": lobbyValue, - "type": type, - "sdp": sdp, - "remoteId": remoteId - }) - -func session_description_received(type, sdp, remote_id: int): - RTC.rtcPeer.get_peer(remote_id).connection.set_remote_description(type, sdp) -#endregion - -#region Ice Candidates -func ice_candidate_created(midName, indexName, sdpName, remoteId): - SendData.emit({ - "message" : Globals.Message.candidate, - "lobbyValue": lobbyValue, - "mid": midName, - "index": indexName, - "sdp": sdpName, - "remoteId": remoteId - }) - -func add_remote_ice_candidate(midName, indexName, sdpName, remoteId): - var peer = RTC.rtcPeer.get_peer(remoteId) - peer.connection.add_ice_candidate(midName, indexName, sdpName) -#endregion diff --git a/Host/Networking/RTCPeer.gd.uid b/Host/Networking/RTCPeer.gd.uid deleted file mode 100644 index 883a600..0000000 --- a/Host/Networking/RTCPeer.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dd36r0cpk568y diff --git a/Host/Networking/SignalingServer.gd b/Host/Networking/SignalingServer.gd index f89cb0c..678c6e1 100644 --- a/Host/Networking/SignalingServer.gd +++ b/Host/Networking/SignalingServer.gd @@ -49,7 +49,7 @@ func close_lobby(lobbyValue: String): #region Players -signal PlayerJoined(id:int, name: String) +signal PlayerJoined(id:String, name: String) func _on_player_joined(data: Dictionary): PlayerJoined.emit(data.id, data.name) diff --git a/Host/SceneManager/scene_manager.gd b/Host/SceneManager/scene_manager.gd index 9688859..b6ad48b 100644 --- a/Host/SceneManager/scene_manager.gd +++ b/Host/SceneManager/scene_manager.gd @@ -19,8 +19,6 @@ func Transition(currentScene: Node, nextScene: Globals.Scene): var nextNode = next.instantiate() if nextNode.has_signal("ChangeScene"): nextNode.ChangeScene.connect(self.Transition) - if nextNode.has_method("connect_rtc"): - nextNode.connect_rtc(RTC) add_child(nextNode) @export var Lobby: PackedScene diff --git a/Host/TradingDay/Players.gd b/Host/TradingDay/Players.gd index 63ba24a..a00fcce 100644 --- a/Host/TradingDay/Players.gd +++ b/Host/TradingDay/Players.gd @@ -4,7 +4,7 @@ var playerCount: = 0 var playerKeys: Array func SetPlayerIds(keys: Array): playerCount = keys.size() - playerKeys = keys + playerKeys = keys.duplicate() #region Stock Events @onready var price: = 0 diff --git a/Host/TradingDay/Review/DayInReview.tscn b/Host/TradingDay/Review/DayInReview.tscn index 2755423..2098266 100644 --- a/Host/TradingDay/Review/DayInReview.tscn +++ b/Host/TradingDay/Review/DayInReview.tscn @@ -1,10 +1,11 @@ -[gd_scene load_steps=6 format=3 uid="uid://djleiwvsjar00"] +[gd_scene load_steps=7 format=3 uid="uid://djleiwvsjar00"] [ext_resource type="Script" uid="uid://c2t0lwc31q58q" path="res://Host/TradingDay/Review/day_in_review.gd" id="1_vrwym"] [ext_resource type="PackedScene" uid="uid://bpjkcgbdtro3t" path="res://Host/TradingDay/Review/graph_point.tscn" id="2_8ika2"] [ext_resource type="Script" uid="uid://bafcw1hgepl0i" path="res://Host/TradingDay/Review/trading_day_data_provider.gd" id="2_c0n8j"] [ext_resource type="PackedScene" uid="uid://5pdwl8tk8dkk" path="res://Host/TradingDay/grid.tscn" id="4_8ika2"] [ext_resource type="Resource" uid="uid://dhy62t0y1olif" path="res://Host/TradingDay/Review/ResourceDefinitions/TradingDay1.tres" id="4_cnvyh"] +[ext_resource type="Script" uid="uid://dn42mjo1mdk54" path="res://addons/ez_rtc/rtc_listener.gd" id="6_nuag1"] [node name="DayInReview" type="Node2D"] script = ExtResource("1_vrwym") @@ -51,5 +52,10 @@ position = Vector2(840, 0) [node name="SpawnPoint8" type="Node2D" parent="Grid"] position = Vector2(960, 0) +[node name="RTCListener" type="Node" parent="."] +process_mode = 4 +script = ExtResource("6_nuag1") +metadata/_custom_type_script = "uid://dn42mjo1mdk54" + [connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"] [connection signal="timeout" from="TransitionTimer" to="." method="_on_transition_timer_timeout"] diff --git a/Host/TradingDay/Review/day_in_review.gd b/Host/TradingDay/Review/day_in_review.gd index 99827b6..32e2239 100644 --- a/Host/TradingDay/Review/day_in_review.gd +++ b/Host/TradingDay/Review/day_in_review.gd @@ -10,9 +10,7 @@ func _ready(): _graph_next_hour() _begin_animation() Max = $TradingDayDataProvider.GetMaxValue(day) - -func connect_rtc(rtc: RTC): - playerCount = rtc.GetPlayerCount() + playerCount = $RTCListener.GetPlayerCount() #region Node Configuration func _get_configuration_warnings(): diff --git a/Host/TradingDay/Review/graph_point.gd b/Host/TradingDay/Review/graph_point.gd index 5e4a33e..d63dae1 100644 --- a/Host/TradingDay/Review/graph_point.gd +++ b/Host/TradingDay/Review/graph_point.gd @@ -23,12 +23,12 @@ func _notification(what: int) -> void: func SetNewMaxHeight(newHeight: int): Maximum = newHeight -var height +var _height @export var Height: int: get(): - return height + return _height set(value): - height = value + _height = value recalculate_position() var maximum: = 100 @@ -71,7 +71,7 @@ signal AnimationFinished(node: Node) func StartAnimation(): $AnimationPlayer.play("RiseUp") -func _on_animation_player_animation_finished(anim_name): +func _on_animation_player_animation_finished(_anim_name): AnimationFinished.emit(self) #endregion diff --git a/Host/TradingDay/background.gd b/Host/TradingDay/background.gd index 44d17b0..59c03d0 100644 --- a/Host/TradingDay/background.gd +++ b/Host/TradingDay/background.gd @@ -7,7 +7,7 @@ func _ready(): $Grid.generate_graph() if Engine.is_editor_hint(): return - connect_rtc(RTC) + connect_rtc() send_input_scenes(GameState.CurrentDay) func _on_ready(): @@ -70,29 +70,28 @@ func _on_grid_stock_value_changed(value): #region Networking -signal SendVariable(name: String, value: Variant) -signal SendData(dict: Variant, peerId: String) +signal SendData(dict: Variant, peerId: int) signal SendDataToAllPlayers(dict: Variant) var playerIds: Array -func connect_rtc(rtc: RTC): - SendVariable.connect(rtc.SendVariable.bind(-1)) # -1 Sends to all players - SendData.connect(rtc.SendData) - SendDataToAllPlayers.connect(rtc.SendDataToAllPlayers) - playerIds = rtc.Get_Player_Ids().duplicate() - $Players.SetPlayerIds(rtc.rtcPeer.get_peers().keys()) +func connect_rtc(): + SendData.connect($RTCListener.SendData) + SendDataToAllPlayers.connect($RTCListener.SendDataToAllPlayers) + self.playerIds = $RTCListener.Get_Player_Ids().duplicate() + $Players.SetPlayerIds(self.playerIds) ## Sends stock purchase scene to all players except for ## the [param controller_player] player. They become the stock controller. func send_input_scenes(controller_player: int): + print("Player %s" % controller_player) var dict = { "type": "game_event", "game_event": "load_scene", "scene": var_to_bytes_with_objects(inputScene) } - var player1 = playerIds.get(controller_player) - playerIds.remove_at(controller_player) + var player1 = self.playerIds.get(controller_player) + self.playerIds.remove_at(controller_player) for playerId in playerIds: SendData.emit(dict, playerId) SendData.emit({ diff --git a/Host/TradingDay/grid.tscn b/Host/TradingDay/grid.tscn index 33ba067..94a51fb 100644 --- a/Host/TradingDay/grid.tscn +++ b/Host/TradingDay/grid.tscn @@ -1,15 +1,11 @@ -[gd_scene load_steps=3 format=3 uid="uid://5pdwl8tk8dkk"] +[gd_scene load_steps=2 format=3 uid="uid://5pdwl8tk8dkk"] [ext_resource type="Script" uid="uid://e4fum3qxhatm" path="res://Host/TradingDay/Chart.gd" id="1_nnkdj"] -[ext_resource type="FontFile" uid="uid://bu02jdmdcoi8j" path="res://Assets/DS-DIGIT.TTF" id="2_lf1ob"] -[node name="Grid" type="Node2D" node_paths=PackedStringArray("StocksNode")] +[node name="Grid" type="Node2D"] script = ExtResource("1_nnkdj") LineColor = Color(0.745098, 0.745098, 0.745098, 1) LineThickness = 1 Columns = 9 Rows = 10 -CustomFont = ExtResource("2_lf1ob") -StockValue = 345 StockLocation = Vector2(0, 91) -StocksNode = NodePath("") diff --git a/Host/TradingDay/player_data_listener.gd b/Host/TradingDay/player_data_listener.gd index 7b7d907..1a2be38 100644 --- a/Host/TradingDay/player_data_listener.gd +++ b/Host/TradingDay/player_data_listener.gd @@ -5,17 +5,17 @@ extends Node @export var PlayerContainer: Node @export var GridNode: Node -func connect_rtc(rtc: RTC): - rtc.DataReceived.connect(_on_data_received) - self.SendData.connect(rtc.SendData) +func _ready(): + $RTCListener.DataReceived.connect(_on_data_received) + self.SendData.connect($RTCListener.SendData) var index = 0 - for playerId in rtc.rtcPeer.get_peers().keys(): + for playerId in $RTCListener.Get_Player_Ids(): var player: Node2D = PlayerContainer.get_child(index) var data: = GameState.GetPlayerData(GameState.CurrentDay - 1, 7, str(index)) player.visible = true player.Cash = 500 player.Id = playerId - player.PlayerName = rtc.names[playerId] + player.PlayerName = $RTCListener.GetPlayerName(str(playerId)) players[playerId] = player index = index + 1 if data != null: diff --git a/Host/TradingDay/trading_day.tscn b/Host/TradingDay/trading_day.tscn index c8b42af..9e58ca2 100644 --- a/Host/TradingDay/trading_day.tscn +++ b/Host/TradingDay/trading_day.tscn @@ -2,10 +2,10 @@ [ext_resource type="Script" uid="uid://2wwwphpgxxp5" path="res://Host/TradingDay/background.gd" id="1_1xwot"] [ext_resource type="Script" uid="uid://e4fum3qxhatm" path="res://Host/TradingDay/Chart.gd" id="2_42rv4"] -[ext_resource type="PackedScene" uid="uid://d37m47k7c63s8" path="res://Client/StockPurchase.tscn" id="2_o8tlr"] +[ext_resource type="PackedScene" uid="uid://d37m47k7c63s8" path="res://Client/StockPurchase.tscn" id="2_l1arb"] [ext_resource type="PackedScene" uid="uid://8v120xs2a14u" path="res://Host/TradingDay/stocks.tscn" id="3_42rv4"] [ext_resource type="FontFile" uid="uid://bu02jdmdcoi8j" path="res://Assets/DS-DIGIT.TTF" id="3_eefjg"] -[ext_resource type="PackedScene" uid="uid://2gam1pehc15e" path="res://Client/StockController.tscn" id="3_u36li"] +[ext_resource type="PackedScene" uid="uid://2gam1pehc15e" path="res://Client/StockController.tscn" id="3_vw4lc"] [ext_resource type="PackedScene" uid="uid://dxseh3d20m3yf" path="res://Host/TradingDay/PlayerDisplay/player_money_display.tscn" id="4_0fjvf"] [ext_resource type="Script" uid="uid://bv4ovpaoojdx3" path="res://Host/TradingDay/player_data_listener.gd" id="5_42rv4"] [ext_resource type="Script" uid="uid://cpeh82ihp5xpt" path="res://Host/TradingDay/Players.gd" id="7_1ys6b"] @@ -15,9 +15,9 @@ [node name="TradingDay" type="Node2D"] script = ExtResource("1_1xwot") -Background = Color(0.0823529, 0.34902, 0.576471, 0.823529) -InputScene = ExtResource("2_o8tlr") -PriceFixingInput = ExtResource("3_u36li") +Background = Color(6.97896e-07, 0.278181, 0.376653, 1) +InputScene = ExtResource("2_l1arb") +PriceFixingInput = ExtResource("3_vw4lc") NextScene = 2 [node name="Grid" type="Node2D" parent="." node_paths=PackedStringArray("StocksNode")] @@ -69,6 +69,11 @@ script = ExtResource("5_42rv4") PlayerContainer = NodePath("..") GridNode = NodePath("../../Grid") +[node name="RTCListener" type="Node" parent="Players/PlayerDataListener"] +process_mode = 4 +script = ExtResource("12_l1arb") +metadata/_custom_type_script = "uid://dn42mjo1mdk54" + [node name="CardController" type="Node" parent="."] script = ExtResource("10_vboce") diff --git a/Input/io.gd b/Input/io.gd index 26e7b89..83aa1bc 100644 --- a/Input/io.gd +++ b/Input/io.gd @@ -3,7 +3,7 @@ extends Node var PlayerInputs = {} func _ready(): - RTC.DataReceived.connect(_rtcInput) + RTCSingleton.DataReceived.connect(_rtcInput) #region Detect New Input Devices signal NewInputSource(InputSource) @@ -23,7 +23,7 @@ func _input(event: InputEvent): func _rtcInput(peerId: String, _data: Variant): if isNewRTCDevice(peerId): - var newRtcDevice = RTCInput.Create(RTC.channels[int(peerId)], RTC.names[int(peerId)]) + var newRtcDevice = RTCInput.Create(RTCSingleton.channels[peerId], RTCSingleton.GetPlayerName(peerId)) NewInputSource.emit(newRtcDevice) #endregion diff --git a/addons/ez_rtc/RTCSingleton.gd b/addons/ez_rtc/RTCSingleton.gd index 0babfa5..93ed463 100644 --- a/addons/ez_rtc/RTCSingleton.gd +++ b/addons/ez_rtc/RTCSingleton.gd @@ -1,11 +1,23 @@ +@tool extends Node signal SendSignalingData(data: Dictionary) var channels : Dictionary = {} var lobbyValue : = "" +const OfflineTestFlag = "--offline" -func AddDataChannel(connection: WebRTCDataChannel, playerId: int) -> void: - channels[playerId] = connection +func _ready(): + isTestingMode = OS.get_cmdline_args().find(OfflineTestFlag) > 0 + +@onready var isTestingMode: = false +func IsTestingMode(): + return Engine.is_editor_hint() || isTestingMode + +func AddDataChannel(connection: WebRTCDataChannel, playerId: String) -> void: + self.channels[playerId] = connection + +func GetDataChannel(playerId: int) -> WebRTCDataChannel: + return self.channels[str(playerId)] const STUN_SERVER_URL: = "stun:stun.l.google.com:19302" var rtcPeer : = WebRTCMultiplayerPeer.new() @@ -16,19 +28,19 @@ func CreateRTCServer(lobby: String): # Skip if already instantiated if serverCreated: return - var err = RTC.rtcPeer.create_server() + var err = self.rtcPeer.create_server() serverCreated = true -func CreateConnectionForPlayer(sourceId): +func CreateConnectionForPlayer(sourceId: int): var peer = WebRTCPeerConnection.new() peer.initialize({ "iceServers" : [{ "urls": [STUN_SERVER_URL] }] }) peer.session_description_created.connect(OnSessionCreated.bind(sourceId)) peer.ice_candidate_created.connect(OnIceCandidateCreated.bind(sourceId)) var connection = peer.create_data_channel("chat", {"negotiated": true, "id": 0}) - AddDataChannel(connection, sourceId) + AddDataChannel(connection, str(sourceId)) - RTC.rtcPeer.add_peer(peer, sourceId) - multiplayer.multiplayer_peer = RTC.rtcPeer + self.rtcPeer.add_peer(peer, sourceId) + multiplayer.multiplayer_peer = self.rtcPeer #region Session func OnSessionCreated(type, sdp, remoteId): @@ -42,7 +54,9 @@ func OnSessionCreated(type, sdp, remoteId): }) func SessionDescriptionReceived(type, sdp, remote_id: int): - self.rtcPeer.get_peer(remote_id).connection.set_remote_description(type, sdp) + var peer = self.rtcPeer.get_peer(remote_id) + print(self.rtcPeer.get_peers()) + peer.connection.set_remote_description(type, sdp) #endregion #region Ice Candidates @@ -62,3 +76,35 @@ func OnIceCandidateReceived(midName, indexName, sdpName, remoteId): var peer = self.rtcPeer.get_peer(remoteId) peer.connection.add_ice_candidate(midName, indexName, sdpName) #endregion + +signal DataReceived(playerId: String, data: Variant) +func _process(_delta: float) -> void: + for peerId: int in rtcPeer.get_peers().keys(): + var connection: WebRTCPeerConnection = rtcPeer.get_peer(peerId).connection + var channel: WebRTCDataChannel = self.channels[str(peerId)] + connection.poll() + if channel.get_ready_state() == WebRTCDataChannel.STATE_OPEN: + if channel.get_available_packet_count() > 0: + var jsonString: = channel.get_packet().get_string_from_utf8() + var data: Variant = JSON.parse_string(jsonString) + DataReceived.emit(str(peerId), data) + +func SendData(channel: WebRTCDataChannel, data: Variant) -> void: + var data_buffer: PackedByteArray = JSON.stringify(data).to_utf8_buffer() + channel.put_packet(data_buffer) + +# TODO: This should probably not be handled here. The end goal should be that +# each RTC nodes only handles traffic to that specific player. +func SendDataToAllPlayers(data: Variant) -> void: + var data_buffer: PackedByteArray = JSON.stringify(data).to_utf8_buffer() + for peerId: int in rtcPeer.get_peers().keys(): + var channel: WebRTCDataChannel = channels[str(peerId)] + channel.put_packet(data_buffer) + +func GetPlayerName(playerId: String) -> String: + return self.names[playerId] + +var names : Dictionary = {} +func AddName(playerNumber:String, player_name: String) -> void: + names[playerNumber] = player_name + DataReceived.emit(str(playerNumber), player_name) diff --git a/addons/ez_rtc/rtc_listener.gd b/addons/ez_rtc/rtc_listener.gd index 0239162..89d242e 100644 --- a/addons/ez_rtc/rtc_listener.gd +++ b/addons/ez_rtc/rtc_listener.gd @@ -2,20 +2,55 @@ extends Node func _ready(): - if RTC!= null && !RTC.IsTestingMode(): - PutData.connect(RTC.SendData) - RTC.DataReceived.connect(self.RecieveData) + if RTCSingleton!= null && !RTCSingleton.IsTestingMode(): + PutData.connect(RTCSingleton.SendData) + RTCSingleton.DataReceived.connect(self.RecieveData) func _enter_tree(): # Don't process RTC events until we are connected. self.process_mode = ProcessMode.PROCESS_MODE_DISABLED +func CreateLobby(lobbyCode: String): + RTCSingleton.CreateRTCServer(lobbyCode) + +func CreateConnectionForPlayer(playerId: int): + RTCSingleton.CreateConnectionForPlayer(playerId) + +func AddPlayerName(playerId: int, name: String): + RTCSingleton.AddName(str(playerId), name) + #region Send Data signal PutData(channel: WebRTCDataChannel, data: PackedByteArray) -func SendData(data: Variant) -> void: - var data_buffer: PackedByteArray = JSON.stringify(data).to_utf8_buffer() - PutData.emit(self.channel, data_buffer) +# TODO: This is never set. In the future, we need to set this when +# the rest of our data is set. +var channel: WebRTCDataChannel + +func SendData(data: Variant, playerId: int) -> void: + var channel: = self.GetChannel(playerId) + PutData.emit(channel, data) + +func GetChannel(playerId: int) -> WebRTCDataChannel: + if self.channel != null: + return self.channel + return RTCSingleton.GetDataChannel(playerId) + +# TODO: This should probably not be handled here. The end goal should be that +# each RTC nodes only handles traffic to that specific player. +func SendDataToAllPlayers(data: Variant): + RTCSingleton.SendDataToAllPlayers(data) + +func SendVariable(key: String, value: Variant, peerId: int = -1): + var dict = { + "type": "game_event", + "game_event": "data", + "variable": key, + "value": value + } + #TODO: Don't rely on nodes to send data to all players. + #if peerId == -1: + #SendDataToAllPlayers(dict) + SendData(dict, peerId) #endregion #region Read Data @@ -23,6 +58,18 @@ func SendData(data: Variant) -> void: signal DataReceived(sourceId: String, data: Variant) func RecieveData(sourceId: String, data: Variant): - if (Sources.find(sourceId) > 0): - DataReceived.emit(sourceId, data) + if (!Sources.is_empty() && Sources.find(sourceId) > 0): + return + DataReceived.emit(sourceId, data) +#endregion + +#region Player Info +func Get_Player_Ids() -> Array: + return RTCSingleton.rtcPeer.get_peers().keys() + +func GetPlayerCount() -> int: + return self.Get_Player_Ids().size() + +func GetPlayerName(playerId: String) -> String: + return RTCSingleton.GetPlayerName(playerId) #endregion diff --git a/project.godot b/project.godot index 5bb68c6..19b5f08 100644 --- a/project.godot +++ b/project.godot @@ -17,7 +17,7 @@ config/icon="res://Assets/icon.svg" [autoload] -RTC="*res://Host/Networking/rtc.gd" +RTC="res://Host/Networking/rtc.gd" Globals="*res://Host/Networking/Globals.gd" IO="*res://Input/io.gd" Settings="*res://Host/GameSate/Settings.gd" @@ -30,10 +30,6 @@ window/stretch/mode="viewport" window/stretch/aspect="ignore" window/emulate_touch_from_mouse=true -[editor] - -run/main_run_args="--offline" - [editor_plugins] enabled=PackedStringArray("res://addons/ez_rtc/plugin.cfg") -- GitLab