Search Unity

Owning multiple player objects

Discussion in 'Multiplayer' started by TehGM, Sep 9, 2015.

  1. TehGM

    TehGM

    Joined:
    Nov 15, 2013
    Posts:
    89
    There were voices about one player owning multiple player objects with server-side authority. I was waiting for it as it's quite required my by game project.
    I haven't tried/tested 5.2 yet, however I've read changelog few times and I can't see anything about it. Only spawning objects with client-side authority.
    Did I miss something or that feature is cancelled/delayed?
     
  2. p87

    p87

    Joined:
    Jun 6, 2013
    Posts:
    318
    My understanding from the documentation...

    http://docs.unity3d.com/Manual/UNetActions.html

    http://docs.unity3d.com/Manual/UNetConcepts.html
    I believe if you wanted to do something like this, let's say a real time strategy game where the player controls many objects (i'll call them "units"). The player would be kind of a high level object, not necessarily a unit that's running around on the field. You would still have a single player object, as it seems that is a limitation or design decision that was made in UNET. So perhaps the player object would just spawn once at the beginning of the match, it could potentially manage chat functionality, the camera, some movement /input scripts that control the camera, maybe a script for unit selection, and higher level stuff like that.

    Then apparently in 5.2 as quoted above (and as you mentioned), you can send commands from non-player objects that have client authority. So I think you would give client authority to each of the local player's units. So then they could send commands, for example move command, attack command, etc. (This was previously impossible, prior to 5.2 only Player objects could send Commands)

    It seems that is the intention behind this UNET change in 5.2. Previously you could have coded the same system, but all of the commands would have to be routed through the player, which complicates things. It's a lot more simple / easier to have the "move" command at the unit level, instead of having to route each unit's movement commands through the player object.

    I admittedly have not gone too deep into using UNET, so I could be wrong. In any case I'd like to hear how this is intended to be implemented using UNET, or how other people would approach this situation (where the player can control many objects).
     
    Last edited: Sep 9, 2015
  3. TehGM

    TehGM

    Joined:
    Nov 15, 2013
    Posts:
    89
    Hmm, yeah. However I was thinking that they'd make it player could have multiple player-objects. That's what I understood from their posts before update.
    Tbh, I was looking for something like assign few objects to one player without giving them authority. I'd like objects to be server-side authority, but players could send commands from few networkBehaviours anyway.
    The way it is now complicates my project a fair bunch.
     
  4. p87

    p87

    Joined:
    Jun 6, 2013
    Posts:
    318
    I think you are confused about "client authority", it's not "client-side authority". Commands are server-side code.
    My understanding is that a particular object can call "Commands" from a client that has the "client authority". Commands are code that is called from the client, and executes on the server.

    So in an RTS, the units that the local player controls would have "client authority". A unit might have a "move" command, that tells the server where it wants to move. The actual code within the command is executed on the server (eg, it might use a Navigation Agent or something to begin moving). Only the client where the unit has client-authority would be able to execute that unit's "move" command. So the opposing team would not be able to call a Move command for a unit that does not belong to them.

    "client authority" is basically specifying which client is allowed to execute commands.

    Commands are kind of confusing because unity uses some kind of black magic behind the scenes to map commands to a client->server request. When you call a command function on the client, its sending a request to the server. The Command parameters allow the client to send data to the server. The server only executes the code inside of the command if that particular client has the authority to do so.

    So I think you can do what you want... there may be a limitation as far as implementing multiple client authority, I'm not sure if multiple clients can have authority over the same object.

    Code (CSharp):
    1. public class Unit : NetworkBehaviour
    2. {
    3.     NavAgent;
    4.  
    5.     // client with authority can call CmdMove(position) to move this unit
    6.     [Command] CmdMove(Vector3 position)
    7.     {
    8.         // this is server side code
    9.         NavAgent.Move(position);
    10.     }
    11. }
     
    Last edited: Sep 9, 2015
    TehGM likes this.
  5. TehGM

    TehGM

    Joined:
    Nov 15, 2013
    Posts:
    89
    @philwinkel - Oh, then I've got confused with those 2 terms then, indeed. And if it's the way you described, then that's exactly what I needed. I'll test it... probably tomorrow, as I'm feeling like falling asleep soon now.
    Thanks!
     
  6. TehGM

    TehGM

    Joined:
    Nov 15, 2013
    Posts:
    89
    @philwinkel - Hmm, sadly, I think you weren't right (or I misunderstood).
    Code (csharp):
    1.   NetworkServer.SpawnWithClientAuthority(ship.gameObject, player.Connection);
    2.   //NetworkServer.Spawn(ship.gameObject);
    3.   //NetworkServer.ReplacePlayerForConnection(player.Connection, ship.gameObject, 0);
    Commented part was how I hoped it'd work (more or less).
    This new way gives me this exception:
    Code (csharp):
    1. AssignClientAuthority can only be used for NetworkIdentity component with LocalPlayerAuthority set.
    2. UnityEngine.Networking.NetworkServer:SpawnWithClientAuthority(GameObject, NetworkConnection)
    3. SpaceGame.GameManager:SpawnPlayerShip(NetworkMessage) (at Assets/Code/General/GameManager.cs:67)
    4. UnityEngine.Networking.NetworkClient:Send(Int16, MessageBase)
    5. SpaceGame.GameModes.GameTest:OnRespawnAllowed(NetworkMessage) (at Assets/Code/General/GameModes/GameTest.cs:15)
    6. UnityEngine.Networking.NetworkIdentity:UNetStaticUpdate()
    Point is, I don't want the player to be responsible of the object (movement, NetworkTransform etc), just be able to send commands - just like player objects without local authority.

    Guess it's still only one player object with server-side authority. :(
     
    Last edited: Sep 10, 2015
  7. p87

    p87

    Joined:
    Jun 6, 2013
    Posts:
    318
    yea there is a chance I wasn't right, i have not tried this yet with unet. It does sound like LocalPlayerAuthority might not work for your requirements. It would allow you to use commands, but then you would have to also process movement on the client and send that across the network. Which would make movement of those objects client-side..

    What I would try first is to figure out if there's some way to use LocalPlayerAuthority (so you can use [Command]'s ), and implement server-side movement. I have no idea if that's possible.

    You could create a higher level NetworkBehaviour that could either use Commands or send network messages back and forth. In the RTS example I was talking about, where you select a bunch of units and issue a move command, it could use that NetworkBehaviour to send the message containing some information that the server would take action upon. So say I select 3 units, and click somewhere to make those units move. You could send a message over the network with the relevant information (move, list of unit IDs to move, position to move to) and the server would be able to make them move. So i guess it's just kind of a roundabout way of sending commands for a bunch of objects that don't have LocalPlayerAuthority.

    As I am working with unet, there are some constraints that are making things difficult for me as well. In particular the fact that NetworkIdentity must be on the root of a GameObject, and NetworkBehaviours must be a component on that same game object. You can't have NetworkBehaviours on child gameobjects. I was designing a skill system and that threw a curve ball into the mix. Now I think I will have to do something similar to what I suggested, and make a high level NetworkBehaviour that can send commands like "execute skill". I would rather just have a command on the skill itself, but it's not possible due to the constraints.
     
    Last edited: Sep 20, 2015
  8. TehGM

    TehGM

    Joined:
    Nov 15, 2013
    Posts:
    89
  9. cubrman

    cubrman

    Joined:
    Jun 18, 2016
    Posts:
    412
    This is the first link that Google shows when typing "AssignClientAuthority can only be used for NetworkIdentity component with LocalPlayerAuthority set" so if anyone comes here for the same reason, here is the solution:

    In the editor, just open the NetworkIdentity component for the object you want to assign authority to and tick the check box "Local Player Authority" to set it to "ON" or "TICKED". I spawn objects (items in my case) with hasAuthority = false and set it to "true" for whatever player picks them up. This allows me to send commands from a client's version of the gun (for instance) directly to the server and then rerout them to all the clients. Btw here is the full code for AssignClientAuthority():



    // Methods below should reside in one of the NetworkBehaviour components of your player Prefab/GameObject (the one you put into the NetworkManager).


    Code (CSharp):
    1.       void OnPickUp(GameObject item)
    2.         {
    3.             NetworkIdentity = GetComponent<NetworkIdentity>();
    4.             if (hasAuthority)
    5.             {
    6.                 var itemNetIdentity = item.GetComponent<NetworkIdentity>();
    7.                 if (isServer)
    8.                     SetItemAuthority(itemNetIdentity.netId, NetworkIdentity);
    9.                 else
    10.                     CmdSetItemAuthority(itemNetIdentity.netId, NetworkIdentity);
    11.             }
    12.         }
    13.  
    14.         void SetItemAuthority(NetworkInstanceId itemID, NetworkIdentity newPlayerOwner)
    15.         {
    16.             var target = ClientScene.FindLocalObject(itemID);
    17.             var identity = target.GetComponent<NetworkIdentity>();
    18.             identity.AssignClientAuthority(newPlayerOwner.connectionToClient);
    19.         }
    20.  
    21.         [Command(channel = 0)]
    22.         public void CmdSetItemAuthority(NetworkInstanceId itemID, NetworkIdentity newPlayerOwner)
    23.         {
    24.             SetItemAuthority(itemID, newPlayerOwner);
    25.         }
     
    mtsgeo and RiverCanvas like this.
  10. Nolic0321

    Nolic0321

    Joined:
    Feb 15, 2017
    Posts:
    2
    How does this get handled properly? Maybe I just totally DON'T understand how Networking works. If I trace the code in my mind....

    PlayerObject runs OnPickUp(someItem) > hasAuthority would be false > Authority is never assigned.
    Server wouldn't do anything because the "OnPickUp()" method isn't a command that is being send from the player....

    I feel like this is the closest piece to the puzzle that is my figuring out how to get this whole networking thing to work properly!