How to set correct authority on object spawned in scene for a late joining player?

Godot Version

4.3.stable

Question

I have an object that players can approach and take over authority for it. It works as expected when all players are in the game when the object’s authority is changed.

If authority changes away from the host (peer 1) during game play to another player, then a 3rd player joins the game (late joining peer), this is where the problem shows up.

Like player2 grabbed authority over the object, now it’s set to 42398423 (that peer’s id). Then a 3rd player joins, the auth of the subject object is defaulted to 1, which throws a bunch of “on_sync_receive: Ignoring sync data from non-authority or for missing node.”

My guess is because when this player is spawned, the scene loads in the subject object, but it spawns in with default auth of 1. This object is spawned with a multiplayer spawner. But the change of authority is not communicated to a late joining player. How do I communicate the authority to the late joining player to avoid those errors?

I do have a multiplayer synchronizer that syncs the authority of who owns it, but that data has not synched on “enter_tree” or “ready” of the object when it spawns in. So I cannot correctly set the authority.

Any have any ideas or strategies on how to tackle this? I don’t need an exact solution, but something to get me unstuck!

Thanks!

3 Likes

It sounds like you are using an RPC?

If so have you considered using a multiplayer synchronizer? It has logic to detect when a player joins and set them up with the current state of things. Just need to setup authority as a synced property, and whenever it changes on the peer you set the authority.

If you dont want to use it, each node that requires the newest player needs to listen for player connected signals from the multiplayer api and RPC that client directly when appropriate.

1 Like

Yes, I’m using a multiplayer synchronizer, apologies, I need to update my description. However, now that you mentioned synching the authority, I’m synching a separate field that tracks that, but not the actual authority property of the object. I will try that!

Thanks!

Hmm, I’m not seeing a way to access the “multiplayer_authority” property from the synchronizer…

I have a few other approaches that I’m going to investigate in the mean time

So your first approach is what i would do.

Then you should be able to do one of two things

Create a setter function

@export var auth : int = 1 : set = _new_authority

func _new_authority(uid:int):
  auth = uid
  set_myltiplayer_authority(auth)

Or

Use the synchronizer signal

@export var auth : int = 1

func ready():
  $MultuplayerSynchromizer.delta_synchronized.connect(_on_delta_synchronized)

func _on_delta_synchronized():
  set_myltiplayer_authority(auth)

The latter approach might work but the property is not exported, so you may have to add it manually to the replication_config with .:multiplayer_authority although i have never tried this and you still may need to call the set auth function anyway.

1 Like

Multiplayer authority isn’t a property of Node. The setter approach should still work as long as you make your own variable tracking authority.

1 Like

Thank you for the replies!

The process I’m trying to implement is:

  • Player hits “C” to spawn craft (Helicopter scene) [Working].

  • Within the helicopter scene we have a multiplayer synchronizer setup to synch position/rotation and the _auth_peer_id of the helicopter. [Working]

  • When a player hits “F” near the craft, it calls an RPC that calls the _auth_peer_id setter.
    1. I originally called to the authority (rpc_id(authority)) here, as I thought that peer would set the _auth_peer_id, which would be synched to the rest of the peers. (nope)
    2. I then just removed the rpc_id and changed to call to all peers.

  • Neither of these seemed to solve the issue of the late joining peer.

  • Interestingly, it works if the authority/host peer spawns and gains control of the craft.

  • It doesn’t work when client 2 spawns and gains control (see steps below)

  • The _auth_peer_id setter is not called when the late joining peer arrives

  • I’ve also tried switching between replicate always and onChange with no luck.

Here’s the script in question here (Godot 4.3).
Note: These changes are only on the method-1 branch.


The exact steps to produce:

  • open all clients (3)
  • hit “host” on one
  • hit “join game” on client 2, hit “c” to spawn “craft”, walk up to it and hit “F”. The craft should follow that player.
  • Hit “join game” on the last client, errors will appear.

The error is a pretty common one when running into authority problems:


I know this is a large dump, I’m going to come back to this tomorrow (hopefully) and try things out with a fresh mind.
Thanks!

@batteryaciddev like i said before you should just use a multiplayer synchronizer.

But, I dont know your tree layout so for the rpc method too work just listen for the peer connected signal and create a direct means to set authority.

func _ready():
  multiplayer.peer_connected.connect(func(id): new_peer.rpc_id(id, get_multiplayer_authority()))

@rpc
func new_peer(id):
  _update_auth_peer_id(id)

ill let you figure out the security. Or determine if this is satisfactory. I feel like this could miss if the new peer doesnt have a full scene instantiated yet. ( I.e. this may be prown to race conditions)

After some investigation, and a realization I was overcomplicating things, I don’t think this approach of allowing client-authority on the object is a good approach. Sticking to server-authority and just synching from the server is the way to go!

Thank you all for the feedback!

@pennyloafers I’m a big fan of your work, thank you for supporting the community!

2 Likes