- Home /
server command works from host, but not from remote client
Hello, I have been trying to figure this out for days now, no luck, maybe someone can help me out.
Basically I am trying to instantiate an ammo prefab, using an empty object already in scene as transform reference.
[Command]
void CmdPlayerShootingControl()
{
Debug.Log("CMD Firing.");
GameObject ammoShoot = Instantiate(ammoPrefab, tempFireTS.position, tempFireTS.rotation);
NetworkServer.Spawn(ammoShoot);
}
This is the cmd code Im calling on GetKeyDown. As you can see I am instantiating ammoPrefab, at tempFireTS. position/rotation.
Heres the problem, it works fine on host client, but nothing happens on remote client. The confusing part is, if I use transform.position/rotation to reference the script object itself it will work, but in that case my shoots arent getting fired were they need to be fired.
In short, cmd works if using transform.poistion/rotation, but not if using any other transform.
Here is the whole code.
public GameObject ammoPrefab;
public List<Transform> firePoints;
private Transform tempFireTS;
private int fireIndex = 0;
void Update ()
{
if (!hasAuthority)
return;
if (Input.GetKeyDown(KeyCode.Mouse0))
{
Debug.Log("ButtonPressed.");
tempFireTS = firePoints[fireIndex];
InstantiateAmmo();
}
}
void InstantiateAmmo()
{
Debug.Log(" 'InstantiateAmmo' called, calling CMD.");
CmdPlayerShootingControl();
fireIndex++;
if (fireIndex <= firePoints.Count - 1)
{
tempFireTS = firePoints[fireIndex];
Invoke("InstantiateAmmo", Random.Range(0.02f, 0.2f));
Debug.Log("'InstantiateAmmo' if end.");
}
else
{
Debug.Log("'InstantiateAmmo' else end.");
fireIndex = 0;
}
}
[Command]
void CmdPlayerShootingControl()
{
Debug.Log("CMD Firing.");
GameObject ammoShoot = Instantiate(ammoPrefab, tempFireTS.position, tempFireTS.rotation);
NetworkServer.Spawn(ammoShoot);
}
And, all the NetworkIdentity, local Authority ..etc are set up, Ive checked a thousand times.
P.S. This is my first time asking on unity forums, srry if Im asking in wrong place.
Answer by Bunny83 · Mar 14, 2018 at 04:10 PM
You have several issues here. First of all you haven't mentioned to which object this script is attached to. It has to be attached to the playerobject of each player. Only the playerobjects can actually send commands to the server.
The next issue is that you set your client - local variable "tempFireTS" to some transform but the command method is executed on the server so it will use the "tempFireTS" variable on the server.
Since this seems to be some sort of "burst fire" since you will iterate through all "firePoints" when you click once it would make much more sense to only send the command once and let the server do the burst fire. This has several advantages. First of all you don't need to send a seperate command across the network for each bullet fired. Second you prevent a cheating user from simply reducing the burst fire rate.
I assume that the "firePoints" list are some sort of child objects of the player to act as spawn points for each shot? In this case each player object should have it's own spawn point list. So when executing the code on the server, the server has access to the same spawn point list.
You may want to do something like this:
public GameObject ammoPrefab;
public List<Transform> firePoints;
private bool readyToFire = true;
void Update ()
{
if (!hasAuthority)
return;
if (Input.GetKeyDown(KeyCode.Mouse0))
{
CmdPlayerShootingControl();
}
}
[Server]
IEnumerator BurstFire()
{
readyToFire = false;
foreach (var spawnPoint in firePoints)
{
GameObject ammoShoot = Instantiate(ammoPrefab, spawnPoint.position, spawnPoint.rotation);
NetworkServer.Spawn(ammoShoot);
yield return new WaitForSeconds(Random.Range(0.02f, 0.2f));
}
readyToFire = true;
}
[Command]
void CmdPlayerShootingControl()
{
if (readyToFire)
{
StartCoroutine(BurstFire())
}
}
This will just send the command of the action the user want to perform to the server. The server will start a coroutine (unless one is already running) which does the actual spawning of the objects.
That way the server has full control over the actual burst fire action.
Answer by CapSovaa · Mar 14, 2018 at 08:23 PM
Thank you very much, this does indeed make the command do something, but Im not quite there yet.
Due to the nature of the project, I have a player object (the one in network manager) wich spawns a player character for the player to control. That is because of the multiple character choices for the player.
In my case player charater is a ship with cannons. On player character object I use camera ray to chose wether to shoot left or right set of cannons depending on which way the player is looking, and I store appropriate cannon transforms (firePoints) in a list.
You said only player objects can call commands, so I modified my scripts so the playerObject script makes a reference to playerCharacter script.
public GameObject characterPrefab;
public PlayerCharaterScript playerChar;
[Command]
CmdSpawnPlayerCharater()
{
GameObject tempCharacter = instantiate(characterPrefab);
NetworkServer.SpawnWithClientAuthority(tempCharacter, connectionToClient);
playerChar = tempCharacter.GetComponent<PlayerCharacterScript>();
}
and now within that same playerObject script I am trying to get the freshest list of transforms just before calling the command, like this.
private List<Transform> firePoints;
void Update()
{
if(Input mouse)
{
firePoints = playerChar.firePoints;
CmdPlayerShootControl();
}
}
Now the problem which shows itself is this: Again, on host it works, on client(which I run in editor) it gives me "null reference, objetc not set...etc" error. Basically, on the host firePoints in playerObject script get updated from playerCharacter script, on the client nothing.
My guess....actually, the fact is, I believe, I'm not updating the server about this change of transforms in the list.
So to summarise, different characters will have different number of cannons, so I cant put a fixed list on playerObject prefab, but I can spawn a character from prefabs, and and check for cannon transforms on those character objects during runtime, but I'm stuck at how to update the server about that new list.
I apologize for making a big deal out of something probably basic, Im just geting into networked scripting, and just like in games, playing singleplayer dosent quite prepare you for multiplayer :D Still tryin to make sense in my head about client/server connections.
Thanks in advance.
Well, if you spawn your ship with client authority the player will own that object and is the only one who can send commands to that objectwhich are executed on the server.
However this piece of code doesn't make sense again:
void Update()
{
if(Input mouse)
{
firePoints = playerChar.firePoints;
CmdPlayerShootControl();
}
}
Even though you seem to call the "CmdPlayerShootControl" method locally, actually you don't. Commands are actually RPC calls that are send to the server and that method is actually executed on the server. Setting local variables on the client is pointless as the server doesn't see those changes.
Almost all your game logic should be executed on the server anyways. If you look at the code in my answer, only the update method will be called on the client. Everything else will be executed on the server.
If the ship is owned by the client you can simply send the command directly to that ship. However the selection of spawn points should be done on the server.
Alternatively you can send "parameters" to command method but you have to be careful. Sending a Transform reference does only work if that transform is actually a "networked object" itself. So it has to have a NetworkIdentity and has to be spawned properly. You can't magically transfer a reference to an arbitrary object which doesn't have a NetworkIdentity onto another PC. Each client does have the same objects but Unity doesn't have a clue the transform on client A is the same as on Client B.
After all it should be the server who decides which cannon of your ship is able to fire and not the client. The first rule in and server - client model is: Never trust the client. The server is THE authority when it comes to game state decisions. A client just tells the server what he want to do and the server does it.
Your answer
Follow this Question
Related Questions
How can I spawn a GameObject on all players in my multiplayer game? 0 Answers
PhotonNetwork.Instantiate 2 problems. 3 Answers
Client interact with World Objects 0 Answers
Passing random values to a client. 0 Answers
Network.Instantiate is CHAOS. 1 Answer