I’d like to initialize differently local and other clients’ players. And apparently there is no easy way to do it.
For local player I just override OnStartLocalPlayer and everything is cool. But what about players from network? For example if I want a different instantiate animation for local players and network players? Where should I put “StartAwesomeNetworkBzzzztAnimation()”?
I cannot do it in OnStartClient because the isLocalPlayer flag is not set yet.
I think I more or less solved this by using the low level api to send a message to the server any time OnStartClient is called. The server listens for the message and sends a ClientRpc back that calls OnStartNonLocalPlayer:
In my Player script:
public override void OnStartClient()
{
networkManager.client.Send(MsgType.RequestNonLocalPlayerInit, new NetIDMessage(netId));
}
[ClientRpc]
public void RpcStartNonOwner()
{
if (!isLocalPlayer)
{
OnStartNonOwner();
}
}
public void OnStartNonOwner()
{
// Do the thing
}
And then in my NetworkManager
public override void OnMatchCreate(CreateMatchResponse matchResponse)
{
base.OnMatchCreate(matchResponse);
if (matchResponse.success)
{
NetworkServer.RegisterHandler(MsgType.RequestNonLocalPlayerInit, OnRequestNonLocalPlayerInit);
}
}
public void OnRequestNonLocalPlayerInit(NetworkMessage msg)
{
NetIDMessage idMsg = msg.ReadMessage<NetIDMessage>();
GameObject player = ClientScene.FindLocalObject(idMsg.netId);
player.GetComponent<PlayerNetworked>().RpcStartNonOwner();
}
I think this may be a better solution than the one @seanr posted because it handles cases with more than 2 players. @seanr’s solution won’t work since ClientRpc’s aren’t buffered. When the first client connects to the server, the player spawns and the rpc is sent, but when a second client connects they will never receive the rpc to initialize the first non-local player since it was sent before they connected.
There is no built-in hook for that. The best solution is probable to invoke a ClientRpc after the player object is spawned, and run the instantiate animation in that handler - but NOT if isLocalPlayer is set.
I solved the problem by initializing a generic network player inside of OnStartClient() and then overriding the local player settings inside of onStartLocalplayer(), but I think this is also not a great workaround.
I think you can make the assumption OnStartLocalPlayer will happen fairly quickly after OnStartClient.
If you do that you can use coroutines.
private bool isAllSet = false
public override void OnStartLocalPlayer()
{
//reset parameters for local player
}
public override void OnStartClient()
{
//Assume that this is going to be a remote machine
//Set parameters for remote
StartCoroutine(AllSetup());
}
private IEnumerator AllSetup()
{
//Need to wait to see if the local player function triggers
yield return new WaitForSecodns(1); //or some other time.
//Now determine if you are local player or not.
if (!isLocalPlayer)
{
//Local Player Animation
}
else
{
//Remote Player Animation
}
}
Also I think you could use async if you are using C# 5. However, I would have to play around with that one for a bit.