Search Unity

Is there a reason why my host is sending commands but not my remote client?

Discussion in 'Multiplayer' started by firestorm713q, Oct 12, 2015.

  1. firestorm713q

    firestorm713q

    Joined:
    Jan 6, 2013
    Posts:
    16
    I've posted this on answers as well, but here's a much more concise version of my problem. Here's the relevant code.
    Code (CSharp):
    1.  
    2. public SyncListInt UserDeckPositions = new SyncListInt();
    3.     public SyncListInt UserDeckLineup = new SyncListInt();
    4.     public SyncListInt UserDeckDugout = new SyncListInt();
    5.  
    6.     public List<int> ClientUserDeckPositions = new List<int>();
    7.     public List<int> ClientUserDeckLineup = new List<int>();
    8.     public List<int> ClientUserDeckDugout = new List<int>();
    9.  
    10. public override void OnStartLocalPlayer () {
    11.         base.OnStartLocalPlayer();
    12.         Debug.Log("Beginning Setup");
    13.         GetUserDeck();
    14.         NetworkLobbyUIHandler.LobbyUISingleton.ListUserCards(GameDataHandler.GameDataSingleton.User.CurrentDeck);
    15.         GetNetIdentity();
    16.         SetIdentity();
    17.         CmdDoneSettingUp();
    18.     }
    19.  
    20.     [Client]
    21.     void GetUserDeck()
    22.     {
    23.         Deck deck = GameDataHandler.GameDataSingleton.User.CurrentDeck;
    24.  
    25.         for (int i = 0; i < deck.Positions.Length; i++)
    26.         {
    27.             ClientUserDeckPositions.Add(deck.positions[i]);
    28.         }
    29.         for (int i = 0; i < deck.StartingLineup.Count; i++)
    30.         {
    31.             ClientUserDeckLineup.Add(deck.StartingLineup[i]);
    32.         }
    33.         for (int i = 0; i < deck.SideBoard.Count; i++)
    34.         {
    35.             ClientUserDeckSideBoard.Add(deck.SideBoard[i]);
    36.         }
    37.         string DName = deck.DeckName;
    38.         CmdProvideUserDeckToServer();
    39.         CmdProvideDeckNameToServer(DName);
    40.     }
    41.  
    42.     [Command]
    43.     public void CmdProvideTeamNameToServer(string teamName)
    44.     {
    45.         Debug.Log("Setting Teamname To: " + teamName);
    46.         TeamName = teamName;
    47.     }
    48.  
    49.     [Command]
    50.     public void CmdProvideUserDeckToServer()
    51.     {
    52.         UserDeckPositions.Clear();
    53.         UserDeckLineup.Clear();
    54.         UserDeckDugout.Clear();
    55.         //UserData user = GameDataHandler.GameDataSingleton.User;
    56.         Debug.Log ("Number of UserDeckPositions on the Client:"+ClientUserDeckPositions.Count);
    57.         for (int i = 0; i < ClientUserDeckPositions.Count; i++)
    58.         {
    59.             UserDeckPositions.Add(ClientUserDeckPositions[i]);
    60.         }
    61.         for (int i = 0; i < ClientUserDeckLineup.Count; i++)
    62.         {
    63.             UserDeckLineup.Add(ClientUserDeckLineup[i]);
    64.         }
    65.         for (int i = 0; i < ClientUserDeckDugout.Count; i++)
    66.         {
    67.             UserDeckDugout.Add(ClientUserDeckDugout[i]);
    68.         }
    69.         //RpcListDeckLineup();
    70.     }
    71.  
    72.  
    This works perfectly for whichever player hosts the game. All of their info is properly synced over the server, and the other player can see the synclists for the host player. The remote player skips over the commands and never actually syncs their data over the server. What am I doing wrong here?

    Edited: Added code
     
    Last edited: Oct 12, 2015
  2. _Adriaan

    _Adriaan

    Joined:
    Nov 12, 2009
    Posts:
    481
    The code you supply here is definitely not enough to look at your problem entirely, and I'll have to do a lot of guessing work:
    - syncvar's and synclists will only be sync'ed when they are set from the server / host. this is because the authoritative model that UNET currently works with. are you sure this is the case?
    - are you sure you are calling these commands from the local client?
     
  3. firestorm713q

    firestorm713q

    Joined:
    Jan 6, 2013
    Posts:
    16
    This code is my player prefab code. Basically I'm using a single UserHandler class to load and synchronize user data between two players.
    - I thought commands could be used from the remote client to set syncvars on the server?
    - I also thought checking Local Player Authority in the Network Identity would counteract the server authoritative thing?
    - I thought OnStartLocalPlayer guaranteed that I'd be calling from the Local Player. Do I misunderstand that function?
    I'll update the code with a few more functions, but it's the [command]s that aren't working, not the syncvars, technically.

    Edit: While I've removed the debug statements, I am absolutely sure that these functions never get called on the remote client no matter where I call them from. At one point I did this to test:
    Code (CSharp):
    1.  
    2. void Update()
    3. {
    4.      if(isLocalPlayer)
    5.           CmdLiterallyAnything();
    6. }
    7.  
    8. [Command]
    9. void CmdLiterallyAnything()
    10. {
    11.      Debug.Log("Literally Anything Happened");
    12. }
    to no avail (worked on whichever player was hosting, but not whichever player joined).
     
    Last edited: Oct 12, 2015
  4. _Adriaan

    _Adriaan

    Joined:
    Nov 12, 2009
    Posts:
    481
    Wait a second - Commands are called by the local player and run on the server. Rpc's are called by the server and run on the client. So a Command never runs on a remote player. If you want a function to run on remote players, then you call a Command (that is run on the server) that will call a Rpc (that is in turn run on each remote player). E.g.:

    Code (CSharp):
    1. [Command] public void CmdFireWithPower( float power )
    2. {
    3.     //called by local player, runs on server
    4.     RpcFireWithPower( power );
    5. }
    6. [ClientRpc] public void RpcFireWithPower( float power )
    7. {
    8.     //called by server, runs on all clients who have this object
    9.     if(!isLocalPlayer)
    10.         gameObject.SendMessage("FireWithPower", power, SendMessageOptions.DontRequireReceiver);
    11. }
    12.  
     
  5. firestorm713q

    firestorm713q

    Joined:
    Jan 6, 2013
    Posts:
    16
    That mostly makes sense, but then how do I accomplish the end result that I'm trying to accomplish? Basically when a player logs in, load some data from disk and load it into the sync vars/sync lists.
     
  6. _Adriaan

    _Adriaan

    Joined:
    Nov 12, 2009
    Posts:
    481
    I'm not entirely sure what you are trying to do. Why would a player (not the server) decide what data should be loaded? Again, Unity uses a authoritative server model, so maybe what you want to do isn't done so easily with Unity. Maybe there is another way you can design your system so that the server sends all the required data to the client instead of the other way around, and all the data that needs to be local can just remain local?
     
  7. firestorm713q

    firestorm713q

    Joined:
    Jan 6, 2013
    Posts:
    16
    Yeah, we're implementing a Web server for the data this week, so it won't be an issue now. I just didn't think it'd be this difficult to send data from remote clients. Where does it talk about the authoritative server in the docs?

    edit: to answer your other question, it wasn't really meant to be anything other than a stop-gap measure to load everything until I started working on a server-authoritative way to load player data. As we're shopping our game to publishers soon, I needed the absolute simplest thing possible. I had figured since I was storing all player data (what cards were in their deck, and what the deck was called) locally on the device, that the fastest way to get a demo of the matchmaker would be to have each player load their data and submit it to the server. Little did I know...
     
    Last edited: Oct 14, 2015