I have got a project where each character in the game has a target which they can cast spells upon. I also want the other players in the game to be aware of which target every player is currently targeting at the moment (think WoW, target of target).
I am currently struggling with the networking part for each client. The code I have written works well for the host, but for the client, it takes a few updates before one’s target has been set. Below, I have pasted two pictures illustrating my code, cut away some unnecessary parts that aren’t crucial to the problem.
This is the simple part of a Player connection script, which on connecting, instantiates a character prefab and gets authority over it.
void Start()
{
if (!isLocalPlayer)
return;
CmdSpawnCharacter();
}
[Command]
private void CmdSpawnCharacter()
{
GameObject go = Instantiate(myCharacterPrefab, this.transform);
NetworkServer.SpawnWithClientAuthority(go, connectionToClient);
}
The next part of code is part of my Character Script. I have understood that I can set the target variable as a Syncvar, so that the server automatically updates which target is being targeted by that character for each client on the server. So whenever I left mouse click on a targetable target (private void RaycastNewTarget()), I need to tell the server that I am switching target. Hence the function CmdSetTarget().
(All targets that are targetable have a Network Identity, so I can pass a GameObject as variable to Cmd function)
If I have hit a target, the function CmdSetTarget() prints out the true if-statement, but on the third line in the if-statement of RaycastNewTarget() I get an error that myTarget is null. However, if I try again straight after, it will work, since myTarget has been set to what I tried clicking the first time.
It seems as if the server updates my own target as if it was a client as well, a few frames later.
[SyncVar]
private GameObject myTarget;
void Update()
{
if (!hasAuthority)
return;
if (Input.GetMouseButtonDown(0))
{
RaycastNewTarget();
}
}
private void RaycastNewTarget()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
LayerMask layerMask = LayerMask.GetMask("Targetable");
if (Physics.Raycast(ray, out hit, 100.0f, layerMask))
{
CmdSetTarget(hit.collider.transform.gameObject);
myTarget.GetComponentInChildren<Projector>().enabled = true;
SetTargetHUD();
}
}
[Command]
private void CmdSetTarget(GameObject aTarget)
{
myTarget = aTarget;
if (myTarget)
Debug.Log("Target is: " + myTarget.name);
else
Debug.Log("Target is null now!");
}
I am a bit unsure how I should solve this problem. Should I set myTarget to the raycast hit first, and then afterwards alert the CmdSetTarget() again, basically doing the same code? Or should I rewrite it to another way?
Hope it was clear enough. Cheers