UNET String SyncVar - Any Ideas?

Yet again, another networking noob!
Anyways,

I am testing a simple fps networking game.

This script (PlayerSync.cs) is attached to the Player Object that is assigned in the Network Manager (I am using Network Manager and Network Manager HUD)

Its job is to send the player’s name, assigned in a script before connecting to a server, to the server, who then adds the name to the Master Player List (modified on server only) and assigns the new value to a syncvar PlayerList.

PlayerList is then printed out in an OnGUI event.

Top - client #1
Middle - client #2
Bottom - host

PlayerSync.cs

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class PlayerSync : NetworkBehaviour {
    [SyncVar]
    private string playerList;

    void Start () {
        if (isLocalPlayer)
            CmdSetPlayer(Game.name);
    }
    [Command]
    void CmdSetPlayer(string name)
    {
        Game.masterList +="\n"+ name;
        playerList = Game.masterList;
    }

    void OnGUI()
    {
        if (isLocalPlayer){
            GUILayout.BeginArea(new Rect(Screen.width - 300, 10, 250, 500));
            GUILayout.BeginVertical("box");
            GUILayout.Label("~Players~");
            GUILayout.Space(10);

            GUILayout.Label(playerList);

            GUILayout.EndVertical();
            GUILayout.EndArea();
        }
    }
}

Game.cs

public static class Game {
    public static string masterList = "";

public static void Reset(){
   masterList = "";
   //only runs on start of scene
}
}

It seems the other clients fail to recieve an incoming clients name, while the incoming client reads all concurrent name.

As far as I know, commands are only executed on the Server, and therefore, MasterList should only be modified/altered on the Host.

I also know that SyncVar can only be edited on the server through a command, and is then (hopefully) synchronized with every client.

Any reasons why this is not working?

Because you didn’t re-assign the value of playerList after other player joinged
for example:

  1. Host ‘A’ start the game
    Game.masterList = ‘A’
    A’s playerList = ‘A’
    2.Client ‘B’ join the game
    Game.masterList =‘A B’
    A’s playerList = ‘A’ // only B’s CmdSetPlayer is invoked
    B’s playerList =‘A B’

Thanks for the reply!

Anyways,

Now under that idea, would moving PlayerSync.cs to a non-instantiated object (non-player) and replacing the Start function with something like OnStartClient or OnStartHost solve this issue, thus having only one instance of playerList?

Would I then have an issue with Command player authority?

Yes, command only can be set by player or object with assignauthority.
But you don’t need worried about it.
Assume you put a billbaord object ‘billboard’ on the scene

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class PlayerSync : NetworkBehaviour {

    /// onStartLocalPlayer only be invoked by the player's client
    public override void OnStartLocalPlayer () {
       /// Find or FindByTag
       GameObject billBoardContainer = GameObject.Find("billboard");      
       BillBoard billBoard = billBoardContainer.GetComponent<BillBoard>();
       /// command can accep object with NetworkIdentity
       CmdSetPlayer(billBoardContainer, "name");
    }
    [Command]
    void CmdSetPlayer(GameObject billBoardContainer, string name)
    {
        // it will map to the coorectly object in server side
        BillBoard billBoard = billBoardContainer.GetComponent<BillBoard>();       
        billBoard.Addname(name);
    }
}
using UnityEngine;
using UnityEngine.Networking;

public class BillBoard : NetworkBehaviour
{

    [SyncVar]
    private string playerList = "";

    public void Addname(string newName)
    {
        this.playerList += "\n" + name;
    }


    void OnGUI()
    {
        GUILayout.BeginArea(new Rect(Screen.width - 300, 10, 250, 500));
        GUILayout.BeginVertical("box");
        GUILayout.Label("~Players~");
        GUILayout.Space(10);

        GUILayout.Label(playerList);

        GUILayout.EndVertical();
        GUILayout.EndArea();

    }
}

Again, thanks for the reply!

Anyways, I see what you mean -
Having the syncvar stored on a non-instantiated object (therefore only one instance in the scene) will allow you to pass the object as a parameter and making each client read the same exact syncvar.

Hello there, I tried to use this example in my project but I got a problem. I am using Lobby so I don’t know where should I put “billboard” gameobject exactly… Cause the scene is changing and I am left with NullReferenceException ehhh. Any ideas? Thanks!

Reply to Chom1czek
I assume you put the “BillBoard” on lobbyscene, and put “PlayerSync” script on playerprefab of playscene. You should also put “BillBoard” in playscene.

But you use “NetworkLobbyManager”, you can directly sync name from NetworkLobbyPlayer

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class MyNetworkLobbyPlayer : NetworkLobbyPlayer {
    /// Or other info you want to stored in lobbyscene
    [SyncVar]
    private string m_myName;

    public string myName
    {
        get
        {
            return m_myName;
        }
        set
        {
            this.m_myName = value;
        }
    }
}
using UnityEngine;
using UnityEngine.Networking;

public class BillBoard2 : NetworkBehaviour
{
    /// no need sync name list
    /// directly retrieve NetworkLobbyPlayer

    void OnGUI()
    {
        GUILayout.BeginArea(new Rect(Screen.width - 300, 10, 250, 500));
        GUILayout.BeginVertical("box");
        GUILayout.Label("~Players~");
        GUILayout.Space(10);
        
        /// NetworkLobbyPlayer can be directly retrieved
        NetworkLobbyManager lobbyManager = NetworkLobbyManager.singleton as NetworkLobbyManager;

        for (int i = 0; i < lobbyManager.maxPlayers; i++)
        {
            if(lobbyManager.lobbySlots[i] != null)
            {
                MyNetworkLobbyPlayer player = lobbyManager.lobbySlots[i] as MyNetworkLobbyPlayer;
                GUILayout.Label(player.myName);
                GUILayout.Space(1);
            }
        }

        GUILayout.EndVertical();
        GUILayout.EndArea();

    }
}

@chenyuchih , wow thanks I will try it out now! I want to ask what about “game scores” like points and stuff, where would be the best place to keep them? On PlayerPrefab or LobbyPlayer like nickname?

@Chom1czek , It depends on your design.
Just put it on playerPrefab is convenient for use. But If your playerPreb will be replace during game, you may need put it another place for consist.