[SyncVar] and variable initialization in Unity.

In the clients and server game I am developing, I need to recognize which player the client is.

So I pass the player number I set in the server to the client using a SyncVar.

However, there is a problem.

If you set the player number in the server, it will be overwritten by the server itself to it’s default value.

Why is that?

The reason is that the initialization of SyncVar happen somewhere after your player Object was already initialized locally. So setting the player number value right after Initialize() might be overwritten once the player is spawned.

In order to overcome this you need to send a message from the server to the client with the Player Number when the server adds the player.
Once the client’s player has spawned he can call a Cmd to update the player number on the server(the number it received from the server with a message).

(Kind of complex, not sure if there is a better way to do this identity synchronization)

            bool leftPlayer = FindObjectOfType<NetManager>().GetPlayerNumber(NetworkServer.connections[k].connectionId) == 1;
            var go = (GameObject)Instantiate(
                playerPrefabList[1],
                transform.position + new Vector3(0, 10, 0),
                Quaternion.identity);
            int netPlayer = leftPlayer ? 0 : 1 + (isServerOnly ? 1 : 0);
            go.GetComponent<NetPlayer>().player1 = netPlayer;
            go.GetComponent<NetPlayer>().playerControllerId = 0;
            PlayerMessage msg = new PlayerMessage();
            msg.player1 = netPlayer;
            NetworkServer.SendToClient(NetworkServer.connections[k].connectionId, (short)(MsgType.Highest + 5), msg);
            NetworkServer.AddPlayerForConnection(NetworkServer.connections[k], go, go.GetComponent<NetPlayer>().playerControllerId);

Here is the code that handles the message on the client:

public void OnPlayerMessage(NetworkMessage netMsg)
{
   PlayerMessage message = netMsg.ReadMessage();
   myPlayer1ID = message.player1;
}

myPlayer1ID is a static int.

And then on the client I do this:

void Update()
{
       if (hasAuthority && !didInitServer)
       {
              didInitServer = true;
              SetServerPlayerNumber(NetManager.myPlayer1ID);
       }
}

public void SetServerPlayerNumber(int playerNumber)
{
       CmdSetNumber(playerNumber);
}
[Command]
void CmdSetNumber(int number)
{
       playerNumber = number;
}

 

Here is a similar code for creating the player on the server, what is wrong with this code?

        bool leftPlayer = FindObjectOfType().GetPlayerNumber(NetworkServer.connections[k].connectionId) == 1;
var go = (GameObject)Instantiate(
playerPrefabList[1],
transform.position + new Vector3(0, 10, 0),
Quaternion.identity);
go.GetComponent().player1 = leftPlayer?0:1 + (isServerOnly ? 1 : 0);
go.GetComponent().playerControllerId = 0;
PlayerMessage msg = new PlayerMessage();
msg.player1 = go.GetComponent().player1;
NetworkServer.SendToClient(NetworkServer.connections[k].connectionId, (short)(MsgType.Highest + 5), msg);
NetworkServer.AddPlayerForConnection(NetworkServer.connections[k], go, go.GetComponent().playerControllerId);

 

What’s wrong with this code is that msg.player1 might not be what we want, because go.GetComponent<NetPlayer>().player1 is SyncVar and might get it’s default value overwrite the value we have just set.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s