Unity Networking: Object only spawning on the Host client.

Hello,

So I’m trying to spawn an object on all the clients connected in a game yet it only spawns on the Host. It used to work perfectly now I’m not quite sure what happened for it to stop working.

  • The Spear prefab has a Network Identity (Local Player Authority) and a Network Behavior Script.
  • The Spear prefab is registered as a spawnable prefab.
  • Channel 0 is “Reliable Sequenced”.
  • I’m using the NetworkServer.Spawn() through a Command call to spawn the prefab.
  • I am getting the Warning: Did not find target for sync message for X.

At this point after hours of browsing this forum I have yet to find the issue that caused my prefab to stop spawning on clients.

Here’s the small bit of code that’s used to spawn the prefab:

void Update()
    {
        if (!isLocalPlayer)
            return;
        if (Input.GetKeyDown(KeyCode.Space) && Time.time > timeToFire)
        {
            anim.SetTrigger("Spear Attack");
            timeToFire = Time.time + spearCD / reductionCD;
            mousePosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Input.mousePosition.z - Camera.main.transform.position.z));
            CmdThrowSpear(mousePosition, name);
        }

    }

    [Command]
    void CmdThrowSpear(Vector3 _mousePosition, string _player)
    {
        if (spearPrefab == null)
        {
            Debug.Log("No gameobject attached to 'spear' in Warrior Combat Script");
        }
        else
        {
            GameObject _spear = (GameObject)Instantiate(spearPrefab, transform.position, transform.rotation);
            _spear.transform.eulerAngles = new Vector3(0, 0, Mathf.Atan2((_mousePosition.y - transform.position.y), (_mousePosition.x - transform.position.x)) * Mathf.Rad2Deg - 180);

            _spear.GetComponent<WarriorSpear>().player = _player;

            NetworkServer.Spawn(_spear);
        }
    }

If anyone has insight on this issue I would highly appreciate it.

Thank you.

Alright so to make this short, the string variable “Player” that had to check whether or not it was the owner of the spear that threw the spear (so he wouldn’t get damaged) had to be a SyncVar since the Spawn method cannot on its own update variable values for the client side. Also made the Destroy gameObject call only if (isServer) so you wont get the “Warning: Did not find target for sync message for X” because the server is trying to update things for a matter of small frames on an object that’s already destroyed client side.

TLDR: [SyncVar] everything and handle object Destruction server side as much as possible.

Hope this helped.

You should use NetworkIdentity and the isLocalPlayer attribute to identify players. Relying on tags and names in a multiplayer environment will eventually fall over itself.

I think the proper way to do this, if you want the client to have control, is to use the SpawnWithClientAuthority method.

Basically, you grab the NetworkIdentity of your ‘gun’ or Player or whatever is firing the spawn code and use netID.connectionToClient to grab your own connection reference. You then stick that into the spawn call. Dont put any object specific stuff in this part of the call as this part should only be running on the server.

Basically what we’ve got here is a Client telling the Server to Spawn an Object and give control to that Client. Notice at the end of the Command code there is an RPC call. This is the server then, telling ALL clients to run that code on the Spear (of which we have passed the object reference).

If the spear prefab has its own movement script then this is ideal as they, largely, wont even need to be synced on the network. I use that RPC call, as an example, to activate a movement script for my bullets. All bullets have the same script so all make the same movements. No position syncing involved. This only works for simple scripted, non-reactive movements.

[Command]
void CmdThrowSpear(Vector3 _mousePosition)
{
    if (spearPrefab == null)
    {
        Debug.Log("No gameobject attached to 'spear' in Warrior Combat Script");
    }
    else
    {
        GameObject _spear = (GameObject)Instantiate(spearPrefab, transform.position, transform.rotation);
        NetworkServer.SpawnWithClientAuthority(_spear, netID.connectionToClient);
		if(isServer) OtherStuff(_spear);
    }
}
 
[ClientRpc]
void OtherStuff(GameObject projObject)
{
	projObject.transform.eulerAngles = new Vector3(0, 0, Mathf.Atan2((_mousePosition.y - transform.position.y), (_mousePosition.x - transform.position.x)) * Mathf.Rad2Deg - 180);
	//projObject.GetComponent<WarriorSpear>().player = _player;
	//Activate a script perhaps, fire a function...whatever.
}

If you do want the spear to be synced on the network, the spear should have its own sync script. Thats the only place you will need the SyncVars.