- Home /
Unity networking Command-function not being called
Hi!
I've been making a multiplayer card game-thingy and have almost successfully managed to make the game work. Now I'm working on the end of the game and I've run into a problem that I just can't figure out myself. The game ends when there are no more cards in a certain deck after which the clients and the server communicate. So here's the problem itself: If the game ends when a client gets the last card of the deck (by clicking on it) all the clients and the server get the correct scores from each other, but when the server gets the last card only the server's score gets passed around, no matter who actually wins. There are no errors, just nothing happening.
I have a network manager with a "game master" prefab as player prefab and the deck as a spawnable prefab. The prefabs have the network identity component, local player authority has no effect on the problem. The "game master" has a script "game" that handles all the networking stuff. I've done testing on unity editor and a standalone exe, using unity as both host and client. Below are all the relevant functions and some comments.
public class Game : NetworkBehaviour
{
public Text scoretxt;
public int[] pelaajienPisteet = new int[4];
public int playerNumber = 0;
//This function gets called from a script in the deck.
//This is the start
public void GameEnded()
{
CmdAnnounceEnd();
}
//Now we're in the server and we'll tell all the clients that the game has ended
[Command]
void CmdAnnounceEnd()
{
RpcAnnounceEnd();
}
//Now we're in the client and count the score
[ClientRpc]
void RpcAnnounceEnd()
{
//Manager has the network manager component
//GetLocalPlayer returns the "game"-script of the local player
//Player handles the actual game
int score= Manager.GetComponent<PlayerManager>
().GetLocalPlayer().players[0].GetComponent<Player>().CalculateScore();
//This prints the correct score and playerNumber when unity editor is server and client
print("Client's score " + score+ " " + Manager.GetComponent<PlayerManager>
().GetLocalPlayer().playerNumber);
//This used to be Cmd but I changed it to see if calling a command from
//Rpc caused the problem
SendScore(score, Manager.GetComponent<PlayerManager>().GetLocalPlayer().playerNumber);
}
//This sends the score and playerNumber of each client's local player
void SendScore(int score, int nmbr)
{
CmdSendScore(score, nmbr);
}
//This is where I think the problems start
//In the SendScore function above I can print each client's own score, but it appears as if the
CmdSendScore function doesn't get called
//Now we're in the server and we should receive scores from players
[Command]
void CmdSendScore(int score, int nmbr)
{
//When a client gets the last card this prints the score of the player who sent it, and every client
sent their score
//When the server gets the last card this prints only the server's score, only the server's score got
sent?
print("Here's the score: " + score+ " " + nmbr);
//Sends the clients this particular player's score
RpcSendScore(score, nmbr);
}
//Now we're in the client
[ClientRpc]
void RpcSendScore(int score, int nmbr)
{
//Client last => prints everyone's score (not all at the same time)
//Server last=> prints only server's score
print(score+ " " + nmbr);
Manager.GetComponent<PlayerManager>().GetLocalPlayer().DisplayScore(score, nmbr);
}
//On the client, shows players' score in a text box
//Function needs improvement but it works
public void DisplayScore(int score, int nmbr)
{
//Client last => prints everyone's score (not all at the same time)
//Server last=> prints only server's score
print("Player" + nmbr + " score: " + score);
playerScores[nmbr - 1] = score; //Playernumbers start from 1
scoretxt.enabled = true;
string k = "";
for (int i = 0; i < playerScores.Length; i++)
{
if (playerScores[i] != 0)
{
if (i == playerNumber - 1) k += "This is you: ";
k += "Player " + i + " score: " + playerScores[i] + "\n";
}
print("score" + nmbr + " " + playerScores[i]);
}
//Client last => Server and clients show all the scores correctly
//Server last=> Only server's score shown on everyone
scoretxt.text = k;
}
}
Thanks for any help!
Answer by Bunny83 · Mar 22, 2018 at 02:02 PM
You have a strange setup here. First of all all relevant game data should be stored any managed by the server. Second "GameEnded" should be invoked by the server so there's no need for a command. Commands are methods that are meant to be called by clients. Finally keep in mind that clients can only send commands to objects they have authority over. This is by default only the player object. I'm pretty sure your Game script is not attached to every player object, right? So it's most likely located on a server owned object and therefore a player can't send commands to that object.
Currently it looks like each client manages his own score. That means a client can simply tell the server it has 1000000 points. Most of the logic and bookkeeping of the game should happen on the server side where the server can vertify and validate everything. Using syncvars can really simplify some of the event and data flow.
It's hart to give specific advice as we don't know your setup, where which script is attached to and who owns which object(s).
Yeah I basically just slapped some networking functions on a singleplayer game I made (plus I'm a networking newbie) so the end result is quite strange. I guess I should make it properly so that I would actually learn something. When you say that the client could tell the server it has a lot of points, how would the client manage to do that? Would the user exploit faults in the game's code or could they somehow change some values using another program or something? I think I'm asking more about games in general than about my game.
Well anyway, I managed to solve the problem. I'm using the "Game" script on the server's local player to store the info but what I did wrong was that I sent the score to the "Game" that the clients spawned on the server, not the local player.