Search Unity

Assign Player Authority

Discussion in 'Multiplayer' started by SirDevin, Mar 2, 2017.

  1. SirDevin

    SirDevin

    Joined:
    Oct 10, 2014
    Posts:
    30
    I cannot for the life of me figure out how to assign authority to a non-player object. This object does have a Network Identity component attached with local player authority as true.

    Please take a look at this code and see what is wrong. All I am trying to do at this point is send a command that runs on the server only.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Networking;
    5.  
    6. public class TestCommand : NetworkBehaviour {
    7.  
    8.     public int newValue;
    9.     NetworkIdentity iden;
    10.  
    11.     void Update(){
    12.         if (Input.GetKeyDown(KeyCode.Space)) {
    13.             SendRequest ();
    14.         }
    15.     }
    16.  
    17.     public void SendRequest(){
    18.         CmdChange (gameObject, 5);
    19.     }
    20.  
    21.     [Command]
    22.     public void CmdChange(GameObject obj, int value){
    23.         iden = obj.GetComponent<NetworkIdentity> ();
    24.         iden.AssignClientAuthority (connectionToClient);
    25.         newValue = value;
    26.         iden.RemoveClientAuthority (connectionToClient);
    27.     }
    28. }
     
  2. SirDevin

    SirDevin

    Joined:
    Oct 10, 2014
    Posts:
    30
    I have gotten much closer to figuring it our finally. So the issue I was having is not with the Method AssignClientAuthority() in itself.

    The way this Method works is that it can only be ran on the server to change the current authority of the object. My issue was that I was trying to change the authority from an object that currently did not have authority. So I was in a predicament, I needed to run this Method on the server, but in order to do that I needed access to the server.

    After hours of frustrating trial and error this is the solution I have found. Since the player object is the only object that is given authority from the beginning I wrote the below script to handle all authority changes on the player object.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Networking;
    5.  
    6. public class ClientAuthority : NetworkBehaviour {
    7.  
    8.     void Start(){
    9.         if (isLocalPlayer) {
    10.             GameObject.Find ("GlobalGameManager").GetComponent<UserProfile> ().playerConnId = gameObject;
    11.             CmdGetAuthority (GameObject.Find("Camera"));
    12.         }
    13.     }
    14.  
    15.     /*public void GetAuthority(GameObject obj){
    16.         CmdGetAuthority (obj);
    17.     }*/
    18.  
    19.     /*public void RemoveAuthority(GameObject obj){
    20.         CmdRemoveAuthority (obj);
    21.     }*/
    22.  
    23.     [Command]
    24.     public void CmdGetAuthority(GameObject obj){
    25.         //GameObject.Find ("Camera").GetComponent<TestCommand> ().newValue = 5;
    26.         if (isServer) {
    27.             obj.GetComponent<NetworkIdentity> ().AssignClientAuthority (connectionToClient);
    28.         }
    29.     }
    30.  
    31.     [Command]
    32.     public void CmdRemoveAuthority(GameObject obj){
    33.         if (isServer) {
    34.             obj.GetComponent<NetworkIdentity> ().RemoveClientAuthority (connectionToClient);
    35.         }
    36.     }
    37. }
    38.  
    The GlobalGameManager reference is to get a reference for the local player to get access to these Methods. Here is an example of the Methods in use.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Networking;
    5.  
    6. public class TestCommand : NetworkBehaviour {
    7.  
    8.     public int newValue;
    9.     GameObject objID;
    10.  
    11.     void Start(){
    12.         objID = GameObject.Find ("GlobalGameManager");
    13.     }
    14.  
    15.     public void SendRequest(){
    16.         objID.GetComponent<UserProfile> ().playerConnId.GetComponent<ClientAuthority> ().CmdGetAuthority (gameObject);
    17.         StartCoroutine (Delay());
    18.     }
    19.  
    20.     [Command]
    21.     public void CmdChange(int value){
    22.         newValue = value;
    23.     }
    24.  
    25.     IEnumerator Delay(){
    26.         yield return new WaitForSeconds (0.1f);
    27.         CmdChange (5);
    28.         objID.GetComponent<UserProfile> ().playerConnId.GetComponent<ClientAuthority> ().CmdRemoveAuthority (gameObject);
    29.     }
    30. }
    31.  
    It starts when the SendRequest Method is called. This first requests access from the player object then starts the Delay co-routine. I am using a co-routine because for some reason when I do not it will not work the first time you call the Method, but it would work if you called it a second time. It delays it by 0.1 seconds then runs the command then it removes its authority. It you have any tips to make this better(perhaps how to make it work without the co-routine) would be greatly appreciated!
     
  3. angusmf

    angusmf

    Joined:
    Jan 19, 2015
    Posts:
    261
    I haven't found a way around building in a delay, but instead of a fixed time, I do this:

    Code (CSharp):
    1. yield return new WaitWhile(() => !NetworkServer.active)