MultiplayerSynchronizer not syncing properties - no errors

Godot Version

4.7.1

Question

Hello,

I have an issue with MultiplayerSynchronizer. It is not syncing my Input nodes, and it is not giving any errors.

The game should allow to join another game in progress (without needing a lobby).

The server flow:

  1. Host starts game
  2. Server networking is initialised
  3. World is loaded
  4. PlayerMultiplayerSpawner connects to PeerConnected event.
  5. PlayerMultiplayerSpawner recieves event that player id: 1 (host has joined)
  6. A new vehicle is spawned with the node name of 1
  7. The Vehicle script self-assigns the multiplayer authority based on it’s name when added to scene on _EnterTree()

When a new player joins, the server:

  1. PlayerMultiplayerSynchronizer gets a PeerConnected event.
  2. A new vehicle is spawned with the node name of e.g. 1234
  3. The Vehicle script self-assigns the multiplayer authority based on it’s name when added to scene on _EnterTree()

The client flow is:

  1. Initialise networking as client
  2. Load world
  3. Vehicle Nodes are ‘automatically’ spawned using PlayerMultiplayerSpawner
  4. The Vehicle script self-assigns the multiplayer authority based on it’s name (does not depend on server) on _EnterTree()

My scene structure when two players have joined, on the host (the client is identical - and the authority is set correctly):

The node/synchronizer I am having issues with:

The inspector view of the node/synchronizer (in scene mode):

The node I want to sync (changing any field to public did not help):

public partial class VehicleInput : Node
{
    [Export]
    float _SteerInput;

    [Export]
    float _AccelerateInput;

    [Export]
    float _BrakeInput;

    [Export]
    bool _IsAccelerateInputPressed;

    [Export]
    bool _IsBrakeInputPressed;

//...
}

The spawn script - attached to the PlayerMultiplayerSpawner node:

public partial class PlayerMultiplayerSpawner : MultiplayerSpawner
{
    // ...
    public override void _Ready()
    {
        if (Context.Instance.Multiplayer.IsServer())
        {
            GetParent().SetMultiplayerAuthority(Context.Instance.Multiplayer.MultiplayerPeer.GetUniqueId(), false);

            Context.Instance.Multiplayer.PeerConnected += OnPeerConnected;
            Context.Instance.Multiplayer.PeerDisconnected += OnPeerDisconnected;            
            CallDeferred(nameof(AddPlayerToRoot), Context.Instance.Multiplayer.MultiplayerPeer.GetUniqueId());
        }
    }

    private void OnPeerConnected(long id)
    {
        // only connected if server
        CallDeferred(nameof(AddPlayerToRoot), (int)id);
        // this.Spawn();
    }

    private void OnPeerDisconnected(long id)
    {
        // only connected if server
        var playerToDelete = GetParent().GetNode(id.ToString());
        playerToDelete?.QueueFree();
    }

    private void AddPlayerToRoot(int id)
    {
        var playerScene = ResourceLoader.Load<PackedScene>(CommonConstants.PATH_SCENE_VEHICLE);
        var player = playerScene.Instantiate<Vehicle>();
        player.Name = id.ToString();
        GetParent().AddChild(player);
        player.GlobalPosition = new Vector3(player.GlobalPosition.X, player.GlobalPosition.Y + 2.5f, player.GlobalPosition.Z);
    }
}

Excerpt from Vehicle script (attached to nodes 1 and 2080699575) which assigns authority:

public partial class Vehicle : VehicleBody3D
{
//...
    public override void _EnterTree()
    {
		// if (!Multiplayer.IsServer())
		// 	return;
		
		if (int.TryParse(this.Name, out int result))
		{
			this.SetMultiplayerAuthority(result);
		}
		else
		{
			Logger.LogErr<Vehicle>("Failed to set authority, as the node name does not translate into a multiplayer id (int).");
		}
    }


	// Called when the node enters the scene tree for the first time.
	public override void _Ready()
	{
		if (!IsMultiplayerAuthority())
			this.GetNode("Camera3D").QueueFree();	
	}
//...
}

What have I done wrong? Is there anything else I can check?

Could this be to do with timing? I use CallDeferred in PlayerMultiplayerSpawner as otherwise I get an error that the tree is still initializing.

Please let me know if I can explain anything (such as the state system).

I found the issue… I didn’t actually configure the MultiplayerSynchronizer to sync any properties, which is most easily done via the GUI. I assumed it just synced all visible properties. :distorted_face:

My code worked fine in the end. Even for in-progress joining surprisingly (thus far).

Here’s what you need to do:

  1. select the MultiplayerSynchronizer which is not syncing properties
  2. press “Replication” on the bottom docked panel (with output, debugger, audio etc.)
  3. select “Add property to sync…”