Anyways, when spawning a new object with a NetworkBehaviour, you have a bunch of virtual methods you can override. OnStartServer, OnStartClient, OnStartAuthority. These are all fine and dandy, but it seems the network behaviour properties are actually set after some of these methods are called. For example, let’s say you spawn an object with client authority, for the local client (host). So it will have:
isServer = true
isClient = true
hasAuthority = true
However, if you run this:
public override void OnStartServer()
{
Debug.Log("OnStartServer:" + isClient);
}
You get false! This is because isServer, isClient and hasAuthority are all set just before their respective virtual methods. Is there any reason these properties aren’t set before all the virtual methods are called? I can’t think of any reason you wouldn’t want to have all this information immediately, and weird as it sounds it’s tough to think of a workaround (I need to know if an object has authority in OnStartServer).
On the server, isServer is set and then OnStartServer() is called for each network behaviour, then NetworkIdentity.OnStartClient() is called which sets isClient and calls OnStartClient() for each network behaviour, then it checks if hasAuthority is set and calls NetworkIdentity.OnStartAuthority() if it is. It looks like hasAuthority is set before NetworkBehaviour.OnStartServer() is called. I generally check NetworkServer.active/localClientActive and NetworkClient.active to see if I’m on the server or not
NetworkIdentity.OnStartServer() abridged source:
internal void OnStartServer(bool allowNonZeroNetId)
{
if (m_IsServer)
{
return;
}
m_IsServer = true;
if (m_LocalPlayerAuthority)
{
// local player on server has NO authority
m_HasAuthority = false;
}
else
{
// enemy on server has authority
m_HasAuthority = true;
}
for (int i = 0; i < m_NetworkBehaviours.Length; i++)
{
NetworkBehaviour comp = m_NetworkBehaviours[i];
comp.OnStartServer();
}
if (NetworkClient.active && NetworkServer.localClientActive)
{
// there will be no spawn message, so start the client here too
OnStartClient();
}
if (m_HasAuthority)
{
OnStartAuthority();
}
}
I think the section where authority is set based on m_LocalPlayerAuthority is a bug and a holdover from the very early days of UNET when you couldn’t add and remove authority from non-player objects. The only practical effect is that OnStartAuthority and OnStopAuthority are not called at the appropriate times by ForceAuthority, but they do nothing by default.
I submitted a PR to fix this today. There’s code in some of the OnStartAuthority overrides that probably needs to be run. If nothing else, it lets you use hasAuthority as you would expect.