Search Unity

  1. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Let us know a bit about your interests, and if you'd like to become more directly involved. Take our survey!
    Dismiss Notice
  4. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  5. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Unity Multiplayer Assign authority to local client gameobject?

Discussion in 'Connected Games' started by Velo222, Dec 1, 2015.

  1. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,172
    Hello,

    I am trying to instantiate/spawn an object at the beginning of the game that only the local client will have authority over.

    Here is my code:

    Code (CSharp):
    1. // Update is called once per frame
    2.     void Update () {
    3.  
    4.  
    5.         //Debug.Log("I am running and the num connections is: " + NetworkServer.connections.Count);
    6.  
    7.  
    8.         if (doOnce2 && NetworkServer.localClientActive)
    9.         {
    10.             CmdInstantiateObjectForLocalClient();
    11.  
    12.             doOnce2 = false;
    13.         }
    14.  
    15.     }
    16.  
    17.  
    18.  
    19.  
    20.     //---------------------------   Functions   --------------------------------------------------
    21.  
    22.  
    23.  
    24.     [Command]
    25.     void CmdInstantiateObjectForLocalClient()
    26.     {
    27.         instance2 = (GameObject)GameObject.Instantiate(localClientInstantiationObject, new Vector3(10, 200, -50), Quaternion.identity);
    28.         NetworkServer.SpawnWithClientAuthority(instance2, NetworkServer.connections[0]);
    29.     }

    When I play the game though, and setup a lan host, I get an "Argument is out of range" error for the NetworkServer.connections parameter. What connection number is the local client? If there's a better way, how would I go about spawning an object that the local client has authority over?

    I know that the local client and server are one and the same essentially, but what would spawning an object with local client authority look like?
     
    Last edited: Dec 1, 2015
  2. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    628
  3. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,172
    That is what I am using though (see code line 28 above). I'm trying to figure out how to set that second parameter to designate the local client. That function only seems to work on other remote clients, but not for the local client. I thought perhaps the local client was connection "zero", but that doesn't seem to be the case. It states that the first remote connection is "1" -- which I do have working.
     
  4. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    628
    The second parameter isn't an int, it's either a NetworkConnectionId, or a GameObject. The NetworkInstanceId is found on the client via the GameObject's NetworkIdentity.netId. On the server you can simply use the GameObject parameter. So if this code is executed on a GameObject on the server, use the GameObject parameter. If this code is a request being sent to the server from a client, you want to use the NetworkConnectionId parameter.
     
  5. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,172
    Yes, but more specifically, the GameObject parameter has to be a "player" gameobject. Because I'm working on an RTS-type game, I'm not using player objects at all. So, it looks as if I can instantiate non-player units on remote clients with respective authorities just fine, but when it comes to instantiating units on the local client itself, the parameters are not valid for that function.

    For example, I tried that function by just passing in the instantiated gameobject on the server and I get this error:
    "SpawnWithClientAuthority player object is not a player.
    UnityEngine.Networking.NetworkServer:SpawnWithClientAuthority(GameObject, GameObject)"
     
  6. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    628
    If I understand what you're saying now, you're trying to use this code on the client. You can't. You have to send a Command request from the client to the server. Only the server can execute NetworkServer functions.
     
  7. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,172
    Is there any chance you could give me a code example of where a gameobject is instantiated and spawned, and that gameobject has local client authority? I don't care if the example is from a client or the server itself. Either one lol.

    I'm going to keep playing with the function. But are you telling me that if I create a gameobject, and checkmark "Server Only". Then place a script on this gameobject that instantiates a non-player prefab -- how do I assign the local client the authority over that gameobject? Or does it just happen automatically perhaps?

    Overall, a piece of code that shows how a local client can be assigned authority over a gameobject would be helpful.
     
  8. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    628
    It's like I tell everyone...how you go about doing this for yourself, depends entirely upon what you're trying to acheive. I'll try to supply an example in the form of an RTS like you're trying to do.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Networking;
    4. using System.Collections;
    5.  
    6. public class Player : NetworkBehaviour
    7. {  
    8. /// <summary>
    9. /// THIS SCRIPT IS ATTACHED TO THE PLAYER GAMEOBJECT THAT IS SPAWNED WHEN THE PLAYER CONNECTS TO A GAME.
    10. /// </summary>
    11.     ///
    12.     public GameObject troopPrefab;
    13.  
    14.     void Update()
    15.     {
    16.         if(Input.GetKey(KeyCode.Space))
    17.             CmdRequestTroopSpawn(); //THIS SENDS A REQUEST TO THE SERVER TO SPAWN A TROOP.
    18.     }
    19.  
    20.     [Command]    //LIKE WITH ANY COMMAND THIS CODE IS ONLY EXECUTED ON THE SERVER.
    21.     public void CmdRequestTroopSpawn()
    22.     {
    23.         GameObject troop = Instantiate(troopPrefab, transform.position, Quaternion.identity) as GameObject; //SpawnWithClientAuthority WORKS JUST LIKE NetworkServer.Spawn ...THE
    24.                                                                                                             //GAMEOBJECT MUST BE INSTANTIATED FIRST.
    25.  
    26.         NetworkServer.SpawnWithClientAuthority(troop, gameObject); //THIS WILL SPAWN THE troop THAT WAS CREATED ABOVE AND GIVE AUTHORITY TO THIS PLAYER. THIS PLAYER (GAMEOBJECT) MUST
    27.                                                                       //HAVE A NetworkIdentity ON IT WITH Local Player Authority CHECKED.
    28.     }
    29. }
    30.  
     
  9. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,172
    Ok, I found out something new (for me), which may have been the problem. And thanks for your example code DRRosen.

    So I created another spawnable prefab of the exact same gameobject, except on this prefab I unchecked "Local Player Authority" on the Network Identity script. Now, when I instantiate and spawn this new prefab (without local authority checked), the gameobject has local client authority automatically. That's with this code:

    Code (CSharp):
    1. [Command]
    2.     void CmdInstantiateUnit4()
    3.     {
    4.         instance1 = (GameObject)GameObject.Instantiate(marineRifleman1, new Vector3(13, 200, 10), Quaternion.identity);
    5.         //NetworkServer.SpawnWithClientAuthority(instance1, instance1);
    6.         NetworkServer.Spawn(instance1);
    7.  
    8.     }

    Now I can spawn units on the host client/server and move them around. I also did have it working where only the remote client could spawn units from it's side of things, but for some reason that stopped working now lol.

    Overall, I'm making progress! But it's way more confusing than I thought it would be at first, haha.

    Now that I have that working, I'm going to keep playing around with things. I might have more questions tomorrow though :)
     
  10. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    628
    This implementation isn't going to work in the long run. NetworkServer.Spawn doesn't tell the game who actually is supposed to be controlling that spawned Object. Give it a try and you'll see what I mean. Boot up your game with 3 people (1 server, 2 clients). In your code you have a line you commented out. That line was fine with one change. Your second parameter needs to be the GameObject that the player spawned when it connected to the game. Not the GameObject you're trying to spawn now. Using UNet...when a PLAYER joins a GAME they (at some point) spawn a GameObject to represent their connection to the GAME on the SERVER. This GameObject is how the server knows which player is which. THAT GameObject is the one you need to include. So if THAT GameObject is called PLAYER1 your line of code would read NetworkServer.SpawnWithClientAuthority(instance1, PLAYER1); ...I hope this is making sense for you because what you put in your last post is leading you in the COMPLETELY wrong direction.
     
    Nikolasio likes this.
  11. Velo222

    Velo222

    Joined:
    Apr 29, 2012
    Posts:
    1,172
    Hey DRRosen3,

    Just letting you know I took your advice. :) There's two things that I did today that are making it much easier now to determine ownership and authority overall. First of all, I did implement player objects. At first I didn't think an RTS would need them at all, but it makes ownership so much easier now, as you stated. Now, I can use the "isLocalPlayer" condition to know who is doing what inputs -- and have "player objects" spawned automatically by the system.

    In addition, for the NetworkServer.SpawnWithClientAuthority() function I found a parameter variable that seems to be exactly what I was wanting. It is NetworkServer.SpawnWithClientAuthority(myGameObject, connectionToClient). The "connectionToClient" parameter automatically refers now to the "owning" clients connection, and gives that gameObject the owning clients authority.

    Overall, that simplified the process for me by a very large amount.

    Thanks DRRosen.
     
    DRRosen3 likes this.
  12. MiddleEye

    MiddleEye

    Joined:
    Feb 9, 2017
    Posts:
    16
    Assigning and Removing client object for ball object on triggerStay when pressing F, and triggerExit. Trigger stay assigns object, trigger exit removes object. Only issue is that it only works on Host side. Here's the full project.
    http://www99.zippyshare.com/v/aJHuAkzz/file.html
     

    Attached Files:

  13. MiddleEye

    MiddleEye

    Joined:
    Feb 9, 2017
    Posts:
    16
    This works completely. Attached to your player object with a trigger and it will grab the ID of any object that passes through the player trigger and release the ID on trigger exit.
     

    Attached Files:

  14. MiddleEye

    MiddleEye

    Joined:
    Feb 9, 2017
    Posts:
    16
  15. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    352
    Just to recap here.

    1. Only the SERVER can spawn an object - end of story

    In Unet, servers spawn objects and that's it. End of story.

    2. You DO HAVE TO HAVE "player" objects. Every client, must have a player object. End of story.

    It's totally normal that the "player" object is not actually a tank or whatever - it can just be an empty game object (usually called an "abstract player object") which every client has one of.

    (And don't forget that every device running will have every player object. Even if they are just abstract player objects. If there are six playing, then every device will have six (not one) player objects in the scene. To be clear: on a given machine, of the six, only one will have
    .isLocalPlayer
    true. Actually, in some situations you have to "find" that one of the six, which can be annoying.)

    3. Regarding spawning objects which have client authority - see point 1.

    It's very easy to spawn objects with client authority. Just go to the doco page Manual/UNetSpawning.html and scroll down to

    NetworkServer.SpawnWithClientAuthority(treeGo, conn);


    Just to repeat point 1: in Unet, only the server can spawn things. End of story. Only the server can spawn objects with client authority. Only the server can spawn players. Only the server can spawn scenery items. In Unet, only the server can spawn any object whatsoever.

    4. Say some specific player, X, will have the authority over the object. Of course, you can't spawn the object until X has joined!!

    In the line of code just above, people often ask ... how the hell do you know which "conn"
    NetworkConnection
    to use?

    Of course, it is meaningless until X has actually joined the game! See point 2!

    So you might do things like this.

    Example 1

    Only one specific client is your "mothership". Of course, the server must, obviously, know the
    NetworkConnection
    to that client.

    You'll already have it saved in a variable
    networkConnectionToMothership
    . (If you don't - you have much bigger problems!!!)

    Thus, in this example, you have the "conn" to use - it's that easy.

    Example 2

    A client (say, client JohnSmith) wants to spawn an object, which JohnSmith will have authority over.

    Reading "point 1" above, you know that only the server can spawn anything.

    So quite simply, the client (JohnSmith) asks the server to spawn the object.

    "Asks the server" simply means send a
    Command
    . (Remember that all communications from clients-to-server are known as "Commands" in Unet.)

    Inside any "Command" (ie, running on the server) you literally have the property

    .connectionToClient


    which gives you the "conn" needed!

    So the code on the server is often this simple:
    Code (CSharp):
    1.     [Command]
    2.     void CmdPleaseSpawnSomething() {
    3.  
    4.         GameObject p = Instantiate(some_Prefab);
    5.         NetworkServer.SpawnWithClientAuthority(p, connectionToClient);
    6.         // "connectionToClient" is magically available with no effort
    7.         // it means the client who called this command
    8.     }
    9.  
    So that's the deal.

    Note however .......

    None of this will actually work :( Unless the code has the basics outlined here:

    https://forum.unity.com/threads/net...lient-disconnect-error-1.439245/#post-3754939
     
    Last edited: Oct 5, 2018
    pesapower and Joe-Censored like this.