- Home /
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?
What about storing the 'inst' Gameobject on the Server and tying it to an unique ID, like a string or int. When the player calls the [Command] they pass the ID ins$$anonymous$$d of the GameObject, and the server uses that ID to pull the appropriate GameObject reference?
Indeed, that is the workaround I am currently using. It is actually very elegant because I can pass the name of the GameObject and then look it up in the Network $$anonymous$$anager's spawnable prefab list.
So I have a usable workaround. I'm just a little concerned because the original way should work, and the fact that it does not might be a sign that there is something wrong in my project that may cause other problems down the road.
Could you find an answer for this? I'm having the same issue.
Answer by Guhanesh · Feb 05, 2016 at 02:45 AM
[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.
THAN$$anonymous$$S SO $$anonymous$$UCH! This saved me!
from [Command] API docs.
Arguments to Remote Actions
The arguments passed to commands and ClientRpc calls are serialized and sent over the network. These arguments can be:
basic types (byte, int, float, string, UInt64, etc) arrays of basic types structs containing allowable types built-in unity math types (Vector3, Quaternion, etc) NetworkIdentity NetworkInstanceId NetworkHash128 GameObject with a NetworkIdentity component attached
GameObject with a Networkid is possible!!!
but i try this. but it receive with null...
it there someone help me??
sorry, i am poor at english
This reply helped me more than you can ever know, haha, thank you.
Answer by stenfeio · Jan 26, 2017 at 11:32 AM
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.
Yes, you saved me :)...we need to do the Server Spawn, and only after set the game object variable of a certain object.
Answer by Glicknork · Dec 08, 2016 at 06:46 AM
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.
I took the solution that some people suggested above. The network manager has a list of all the network objects, so you can send an int that is the index of the object in that list and just look up the prefab server-side and spawn it.
Yeah, so am I. It's just a cumbersome method as you can't for example pass through altered instances of an object, as the server can only instantiate prefabs. It's also frustrating as Unity says that you can do it in the documentation, yet you can't in reality. I wonder if it's an issue they're aware of.
I think it's by design. I'm pretty sure that you can pass a networked object that has been spawned. I think the problem with your last bit of code is that you are trying to pass an object that has been instantiated on the client, but hasn't been spawned on the server (so it isn't actually a networked object, even though it has a networkID component).
Answer by correia55 · Feb 25, 2018 at 10:50 AM
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);
}
Answer by ratneshpatel · Sep 15, 2018 at 08:39 AM
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.