Command cannot pass GameObject parameter from remote client to server.

I’m trying to pass a GameObject as a command parameter so that it can be instantiated on the server and then spawned on the network. The object has a network identity and is registered as a spawnable prefab. The code below works perfectly well when the host client executes the command. But when the CmdExecuteLaunch is called from the remote client, the inst parameter inexplicably arrives as ‘null.’

Note: This code does not spawn inst, but it spawns the vessel that will later spawn inst. I have tracked the prefab reference loss definitively to this command.

[Command]
public void CmdExecuteLaunch(Vector3 coord, GameObject inst, Quaternion stationRot) {
    	GameObject capsule = Instantiate (capsulePrefap);
    	capsule.transform.rotation = stationRot;
    	capsule.transform.Translate (0, 0, -150);
    	capsule.GetComponent<Capsule_Behavior> ().CapsuleSetup(coord, inst);
    	NetworkServer.Spawn(capsule);
}

I set up a test project, and was able to replicate the issue. The command delivers game objects as null.

Does anyone know why this is happening?

[Command] functions will only accept primitive parameters (like int,float,).You cannot pass a GameObject from a client to server(or host) like that.Store the gameobject in server.Pass a unique number id for that gameobject so it can be instantiated in server.

So what I’ve found is that if it’s a Prefab then passing it using a [Command] seems to cause things to not go well. I got Null Errors when trying to pass a Prefab GameObject using a command to the server for it to Instantiate and Spawn.

A quick workaround for this is that I had the [Command] instantiate the Prefab on it’s own without passing the Prefab as a parameter to the [Command].

I went from:

 // I attach a prefab here, must be set in editor
 public GameObject prefabToInstantiate;
 // I call this somewhere in my code
 CmdInstantiatePrefabOnServer(prefabToInstantiate);

[Command]
void CmdInstantiatePrefabtOnServer(GameObject prefabToInstantiate)
{
    GameObject tempGo = Instantiate(progressionCanvas);
    NetworkServer.Spawn(tempGo);
}

To:

CmdInstantiatePrefabOnServer();

[Command]
void CmdInstantiatePrefabtOnServer()
{
    GameObject tempGo = Instantiate(progressionCanvas);
    NetworkServer.Spawn(tempGo);
}

You can pass GameObjects with NetworkIdenties from and to the Server but it seems for uninstantiated Prefabs it might cause some problems.

Hi. I have exactly the same issue, and likewise am perplexed as to why I can’t send a GameObject from a client (no issue sending from the host) to the server through a Command, when the Unity API explicitly states that one of the arguments that can be sent through commands is:
“GameObject with a NetworkIdentity component attached”

https://docs.unity3d.com/Manual/UNetActions.html

Here is the code that is returning a null gameobject on the server when it is sent by a client:

public void ICreatedAnExplosion(GameObject explosion, Vector3 position, Quaternion rotation)
{
CmdICreatedAnExplosion(expl, position, rotation);
}

[Command]
void CmdICreatedAnExplosion(GameObject explosion, Vector3 position, Quaternion rotation)
{
    GameObject expl = (GameObject)Instantiate(explosion, position, rotation);
    NetworkServer.Spawn(expl);
}

However, I HAVE succeeded in sending a GameObject from a client to the host through a command, where I am referencing an object that already exists, as opposed to one I am just instantiating (eg: an enemy I hit in the level, rather than an explosion I just created). This works:

public void IHitAnObject(GameObject hitObj, float damage)
{
CmdIHitAnEnemy(hitObj, damage);
}

[Command]
void CmdIHitAnEnemy(GameObject hitObj, float damage)
{       
    hitObj.GetComponent<EnemyController>().TakeDamage(damage);        
}

I am thinking that perhaps this is because the enemy has already been allocated a networkID number (which I presume is what is really passed when a ‘gameobject’ is passed through a Command, as the server already has a networkID for all the objects and would explain why it has to be an object with a NetworkID component attached). So perhaps the explosion can’t go through because the NetworkID reference is for a prefab and not an instantiated object. I tried to solve this by briefly creating the object, passing it, and then destroying it, like this:

public void ICreatedAnExplosion(GameObject explosion, Vector3 position, Quaternion rotation)
{
GameObject expl = (GameObject)Instantiate(explosion, position, rotation);
CmdICreatedAnExplosion(expl, position, rotation);
Destroy(expl);
}

However it didn’t work either, I’m thinking because the NetworkIdentity didn’t have time to create the ID before destroying it. I am all out of ideas, would appreciate any thoughts.

As already described by some answers and comments here:
Remote Actions (including Commands) cannot receive a GameObject as a parameter, only primitive types (list of allowed types in the documentation).

I think a good solution for this is, for instance, to use the list of spawnable objects that you need to set in the NetworkManager. Below there’s an example of this.

void Fire()
{
    CmdSpawnObject(0, transform.position - transform.forward, Quaternion.identity);
}
    
    
[Command]
public void CmdSpawnObject(int spawnablePrefab, Vector3 pos, Quaternion rotation)
{
    GameObject prefab = nm.spawnPrefabs[spawnablePrefab];
    
    GameObject o = Instantiate(prefab, pos, rotation);
    
    NetworkServer.Spawn(o);
}

There is a tweak here. You CAN pass the gameObject reference if that gameobject is networked i.e. has a Network Identity component. But if it doesn’t have network identity null would be passed and it would spam “Not set to an instance of the object” error. So use if (is not null) to check if using this method.