Player Object does not have authority?
I'm just beginning practice with network programming and multiplayer.
I've set up a very basic chat script that I've put onto my Player Object prefab.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine;
using UnityEngine.UI;
public class Chat : NetworkBehaviour
{
private InputField TextField;
private Text chatWindow;
public override void OnStartLocalPlayer()
{
chatWindow = GameObject.Find("MessageLog").GetComponent<Text>();
chatWindow.text += "Chat Activated";
Debug.Log(chatWindow.text);
Debug.Log("isLocalPlayer? "+isLocalPlayer);
Debug.Log("isServer? " + isServer);
Debug.Log("isClient? " + isClient);
Debug.Log("hasAuthority? " + hasAuthority);
}
[Command]
public void CmdSendMessage(string m)
{
RpcGetMessage(m);
}
[ClientRpc]
public void RpcGetMessage(string m)
{
chatWindow.text += "\n" + m;
}
public void HandleMessage()
{
TextField = GameObject.Find("ChatField").GetComponent<InputField>();
if (TextField.text != "")
{
if (isServer)
{
RpcGetMessage(TextField.text);
}
else
{
CmdSendMessage(TextField.text);
}
TextField.text = "";
}
}
}
When I launch my little game as host, the debug functions in OnStartLocalPlayer run and tell me accurate information. Then when I put a message in my text field and press send. The chat fails with a warning stating: "Trying to send command for object without authority."
First of all, it shouldn't be sending a command from the host player. I put the "isServer" check for that very reason (which fails in the HandleMessage function).
Secondly, the player object which this script is on should have authority.
When I use a host and client setup nothing changes.
Notes: All the network setup is based on all the work up to this step in the Multiplayer Networking Tutorial: https://unity3d.com/learn/tutorials/topics/multiplayer-networking/death-and-respawning?playlist=29690
The Player Object has a Network Identity set to Local Authority.
I just added the Chat script to the player prefab and the 3 canvas elements: Text InputField Button - Calls HandleMessage. Defined by dragging the prefab player object into the button's OnClick list.
Update:
It seems that what was going on is that the button was referring to some 'other' version of the player object, not the particular instance that the user was using and/or ALL player objects.
I'm guessing it was referring to the static class or something of that nature, but I'm not familiar enough with Unity development to say.
However I'm now experiencing more issues, still causing me to be unable to send and receive messages:
When I'm on the host and I send a message, it skips the Command function call and goes straight to the Rpc call. It runs fine on the host game instance but nothing happens on the client instance. I have a (!isLocalPlayer) check before it updates the text field and whatnot so I'm assuming that gets switched and nothing happens. When I try to put a text field entry as a debug log BEFORE the (!isLocalPlayer) it says that the variable on that line is a null reference. I don't know why this isn't considered the local player and none of the variables are considered the same. (Is it because the function is being called on the HOSTS player object in my client instance?)
When I'm on the client and I send a message, it steps through all the steps up to Calling the Command function. Then on the host, nothing gets called.
Answer by RamonLion · Mar 01, 2017 at 11:55 PM
I figured it out.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class Chat : NetworkBehaviour
{
private InputField TextField;
private Text chatWindow;
public void Awake()
{
chatWindow = GameObject.Find("MessageLog").GetComponent<Text>();
TextField = GameObject.Find("ChatField").GetComponent<InputField>();
}
public override void OnStartLocalPlayer()
{
chatWindow.text += "Chat Activated";
Button btn = GameObject.Find("Send").GetComponent<Button>();
btn.onClick.AddListener(HandleMessage);
}
[Command]
public void CmdSendMessage(string m)
{
RpcGetMessage(m);
}
[ClientRpc]
public void RpcGetMessage(string m)
{
chatWindow.text += "\n" + m;
}
private void HandleMessage()
{
if (TextField.text != "")
{
if (isServer)
{
RpcGetMessage(TextField.text);
}
else
{
CmdSendMessage(TextField.text);
}
TextField.text = "";
}
}
}
It was a scoping issue but not quite in the way I had interpreted.
The issue was that all the commands were being made by the local user's object. But then when the host was enacting Rpc commands it was being directed the the client side hosts game object. So while I was using the local player authority as an I/O I was supposed to make the local authority SEND the commands and then the hosts instance RECEIVE the return calls.
How agonizingly tedious. Is there any reason for this design choice?