How MutliplayerSynchronizer synchronizes?

Godot Version

Godot 4.2 (4.0 +)

Question

I’m thinking about how the Multiplayer Synchronizer works.
For example, I have this RPC function of throwing a grenade:

@rpc('any_peer', 'call_local', 'reliable')
func throw_grenade(camera_transform: Transform3D) -> void:
	if typeof(camera_transform) != TYPE_TRANSFORM3D:		return
	
	var peer_id: int = multiplayer.get_remote_sender_id()
	
	
	var grenade := GRENADE_SCENE.instantiate()
	grenade.set_multiplayer_authority(peer_id)
	
	grenade.global_transform = camera_transform
	grenade.position += Vector3.UP * 2 #some offset by global coords
	
	grenades.add_child(grenade)
	
	grenade.apply_central_impulse(-camera_transform.basis.z * GRENADE_THROW_FORCE)

And MultiplayerSynchronizer node in GRENADE_SCENE:

Does the function work only when the object is created via RPC, or can I somehow synchronize an existing node?

When an object is created via RPC, is it given any value that is the same for everyone and does MultiplayerSynchronizer understand this?
Or does it just work through object’s NodePath?

I am interested to know this since I haven’t found anything on this topic yet

Your function is doing two things, a MultiplayerSynchronizer just synchronizes properties. You need to combine with a multiplayerSpawner in order to instantiate nodes.

Other then abstracting away RPC boiler code it is essentially the same as RPC in terms of data flow and still requires a node path to get to the same node on the remote end.

You should check out the dev blogs

1 Like

so it works by spawn_path property in MultiplayerSpawner, but how does it work without this node? Just through code and RPC. I have a player spawn system without a MultiplayerSpawner and I don’t understand how it works at all, I have the same system as in this blog

So since it seems like you are doing a peer-to-peer network you should have a mspawn class that is authed to the peer. This will grant the permission to spawn a remote grenade on all peers.

The Throw the grenade function will setup the position and velocity, then add child to a node location mspawn is watching. This will spawn the grenade in the origin of the watched node with default values with no velocity on each peer.

Each grenade scene should then have a multsync object that on spawn sets position and velocity.

Note: when you set auth to the grenade you should make it recursive to all child nodes in the scene so the grenade multsync is owned by the player who throws it.

2 Likes

oh thanks for such a detailed explanation, I finally understood the meaning of these nodes. That is, without a mspawner it won’t work?

You could do it with RPC but it will be a lot easier to use the mspawner. And if a you want to allow players to join mid game spawners already have the functionality to spawn nodes for the new client. Although it may require you to structure multiple mspawners for the tree replication.

But yea, for dynamic scenes where nodes are created and freed both types of multiplayer nodes are needed as each does a different job.

If you have a static scene RPC and multisync nodes are fine.

If you want to replicate a spawner in rpc to need to listen for two types of events. Peer connected and child added. All while keeping track of what children of depth 1 exist on the monitored node. But at this point you should just use the built in nodes.

1 Like

I don’t fully understand how it works without the MultiplayerSynchronizer. By a global NodePath like /root/map/grenades/?
But how will it understand the path if, when adding an object, it is assigned an almost random name, for example /root/map/grenades/@grenade@31. It may be different for some clients.

Will it work if I send the tick argument with the Time.get_ticks_usec() value to the RPC and assign it to the name like grenade_45232141 so that everyone has the same name? :smile:

I would attach a MultiplayerSynchronizer in the scene of the grenade. It will look at its existence (it’s path) and send info to remote clients synchronizer in the same path. So for each new grenade they will each have their own synchronizer and path.

You shouldnt need to worry about timestamps I think synchronizers send “unreliable ordered”. So the will drop packets if they come out of order at least. (Spawners use reliable packets, so it is guaranteed to make sure each client gets the new node)

That is how the network arch works. Although new nodes typically defaults to the host for authority, IDK if that is going to cause issue, but since the spawner is owned by the peer maybe it will work out.

The MultiplayerSpawner will also sync the name there shouldn’t be a worry (but since you are peer-to-peer maybe should), and yes you can change it to whatever you like. It will have some funny characters in the name that is general godot add_child stuff to make it uniquely named. But if you don’t like that you can pass a parameter to add_child(new_node, true) to make it human readable.

If you are setting the name manually IDK if you need to worry about name collisions. But give it a try

I’m pretty confident it will avoid name collisions

2 Likes

If you want to save packet history to resolve conflicts, you may need to make a custom synchronizer with a script that pulls properties off of the synced object packs them with a time stamp in an array or dictionary, and send it off. For custom properties you need to export them in order to be added to the replication config.

Then When the remote synchronizer gets that array it unpacks it checks timestamps, or frame number, and puts the new data on the remote synched object. Then takes the array and saves it locally. You can trigger this event with the synchronized signal when the new data is received.

1 Like

I’m wrong about how the synchronizer works the default mode is only “unreliable” so you may have funny issues if the UDP packets get delayed over the network.

If this becomes problematic you can try REPLICATION_MODE_ON_CHANGE which will be reliable. Although that may have its own issues.

I guess then to make it unreliable ordered you should make your own custom script described above, using a timestamp, or frame nber, with your aggregated property list packet.

If you want a rundown on low level network fundamentals take a look at this article series on network physics.

I made a physics script here following some of the core concepts.

3 Likes

If you want to duplicate a scene you need to use the MultiplayerSpawner.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.