Closed chrisl8 closed 1 year ago
Hi,
Can you please elaborate a bit more about errors you get? I'm in a process of checking the project you've provided but it would be generally appreciated if we have some starting direction to look at. Thank you!
There are no errors, the scenes are simply not propagated out to the other players who join the game when using WebRTC.
Run the game with 2 or 3 or 4 instances and if you use ENet you will see the scene in every instance, but with WebRTC it will only show up in the server instance and not the others.
Here is what it looks like when using ENet:
Here is what it looks like using WebRTC:
The MultiplayerSpawner just does not function when using WebRTC.
Thank you.
A little update. There's a signal in MultiplayerSpawner
- spawned
- that is emitted once a scene has been replicated. In case when we're using ENet
- it's emitted (and the scene has been replicated), no problem there. But when it's WebRTC
- nothing happens.
I've also rechecked the networking code and, from the first sight, there're no problems/bugs with it, the peers are interconnected. So I suspect the problem might be in the scene replication code itself.
I will keep you updated once I know more.
You seem to be using the create_mesh
setup, where each peer is connected to each other in mesh form and there is no "server".
Since the server (ID = 1) is the default authority of nodes, you will need to set the MultiplayerSpawner authority to the player ID you want to act as server.
In this specific case, this patch in your game solves the issue:
diff --git a/main-user-client/User.gd b/main-user-client/User.gd
index 95b1d9a..d114024 100644
--- a/main-user-client/User.gd
+++ b/main-user-client/User.gd
@@ -20,7 +20,10 @@ var game_scene_initialized: bool = false
var level_scene := preload("res://scene.tscn")
var is_server: bool = false
var server_name: String = ""
-var server_id := -1
+var server_id := -1 :
+ set(value):
+ server_id = value
+ get_tree().get_root().get_node("Main/LevelSpawner").set_multiplayer_authority(value)
var server_password: String = ""
var local_debug_instance_number := -1
var mult: SceneMultiplayer = null
@Faless I am testing what you posted now, but it is not changing the behavior of the game at all for me. The results are still the same: no replication of scene to peers/clients.
@chrisl8 That's weird, it works on my end. Scenes are being replicated but with a slightly bigger delay than when using ENet
. Maybe there's a syntax error lurking somewhere? Pasting Faless' code just in case:
var server_id := -1 :
set(value):
server_id = value
get_tree().get_root().get_node("Main/LevelSpawner").set_multiplayer_authority(value)
@Faless @azuloo The solution provided works for TWO instances, but running 3+ breaks it. You can see this by setting Run instances to 3 or 4 in Debug.
If I add a greater delay for the startup I can see that it works at first when only 2 are connected, but fails when a 3rd client connects.
@chrisl8 well, this is a matter of timing in your code, not in the replication code.
You simply need to set the User.server_id
(i.e. set the multiplayer authority) before you add the peer to WebRTCMultiplayerPeer.
@chrisl8 well, this is a matter of timing in your code, not in the replication code. You simply need to set the
User.server_id
(i.e. set the multiplayer authority) before you add the peer to WebRTCMultiplayerPeer.
It doesn't matter how long I delay things, if there are more than 2 peers, it fails.
I will keep working on it though, perhaps this is not a Godot engine bug after all.
I didn't quite like the solution where we created new WebRTCMultiplayerPeer
, new mesh and established new interconnections between peers each time a new peer had appeared. So I've decided to try to not do that and move the initialization part into a separate func. In init_connection()
I've only left the part where we establish a new connection (and adding a new peer essentially) but only for those peers that haven't been already interconnected.
And it actually worked! Here's the changes (along with the Faless' code from earlier):
User.gd
func init_rtc_peer():
rtc_peer = WebRTCMultiplayerPeer.new() # Comment to disable WebRTC
#rtc_peer = ENetMultiplayerPeer.new() # Comment to disale ENet
if User.is_server:
rtc_peer.create_mesh(ID) # Comment to disable WebRTC
#rtc_peer.create_server(8080)
else:
rtc_peer.create_mesh(ID) # Comment to disable WebRTC
#rtc_peer.create_client('127.0.0.1', 8080)
get_tree().get_multiplayer().multiplayer_peer = rtc_peer
func init_connection():
for peer_id in peers.keys():
if connection_list.has(peer_id):
continue # This peer has already been initiated, skipping
var connection := WebRTCPeerConnection.new()
connection.initialize({"iceServers": [ { "urls": ["stun:stun.l.google.com:19302"]}]})
connection.session_description_created.connect(session_created.bind(connection))
connection.ice_candidate_created.connect(ice_created.bind(connection))
connection_list[peer_id] = connection
rtc_peer.add_peer(connection, peer_id) # Comment to disable ENet
network_initialized = true
Client.gd
...
if type == Message.USER_INFO:
User.user_name = data
User.ID = id
print("Received User name = %s ID# %s" %[data, id])
User.init_rtc_peer()
user_name_feedback_received.emit()
return
...
I've tested it with 4 windows and the scene has spawned in all of them. Please let me know if I didn't break any logic in your code, because it was quite a fast solution. P.S. I didn't do it as a diff because it was a little bit messy there, so my apologies if it's not intuitive.
@azuloo and @Faless Thank you so much for your assistance!
You have proven clearly now that MultiplayerSpawner does indeed work with WebRTCMultiplayerPeer along with pushing me in the right direction to make it work.
Each of your contributions was a key to the puzzle.
If anyone else finds themselves here and is in need of help, feel free to check out the repo I used to open this ticket at https://github.com/chrisl8/godot-webrtc-test and please open Issues against that repository if it doesn't work for you and I will be happy to work with you to improve the example to be more clear and usable. I am happy to use that repo of mine as a "general user help forum" on WebRTC multiplayer in Godot.
I am closing this now as it is clear that there is no bug with Godot here. Thank you.
Godot version
v4.1.1.stable.official [bd6af8e0e]
System information
Windows 10 - Godot v4.1.1 stable
Issue description
MultiplayerSpawner works fine with ENet multiplayer, but it does not work WebRTC. Using the same code base and switching between the two allows it to work when switching to ENet.
I have not yet found a fully working WebRTC example game that implements MultiplayerSpawner, so it is entirely possible that I am just doing it wrong.
However, it works with ENet, and the game works if I manually spawn the scenes on other devices, including MultiplayerSynchronizers work fine over WebRTC, just not the Spawners.
Steps to reproduce
Build a basic WebRTC game, including signaling server and attempt to add scenes that are tied to MultiplayerSpawner and they do not show up on peer games.
Minimal reproduction project
I have created a repo to demonstrate my findings here:
https://github.com/chrisl8/godot-webrtc-test
It requires running a Node.js based signalling_server to function.
The webrtc-native and node modules are both included in the repo, so it should be easy to pull down and run.
I cut my example down to the bone, so it does not include any MultiplayerSynchronizers. If you need me to add more to the example let me know and I can.