Problems with Command and ClientRpc functions

Hi all, thank you for taking the time to read my post.

I am hoping I can get a little light shed on a problem I am having with Commands and ClientRpc’s.

I’ve read the docs and they tell me that Commands are only run on the server, even as the host it doesn’t get run on the local player. ClientRpc works in the opposite direction, called from the server that get run on each client locally including the host.

My problem is that as the host I am having a function be called twice when I call a Command function. Within that Command function I am calling a ClientRpc function that is replicating what was done on the server. The only way I can get it to stop from calling twice is within the ClientRpc function I do something like.

if (isServer)
    return;

If I read the docs correctly this shouldn’t happen, am I understanding this right?

So if I understand what you’re doing correctly you have something like this:

[Command]
private void CmdExecuteOnServer()
{
    //Do some calculations here
    RpcExecuteOnClient();
}

[ClientRpc]
private void RpcExecuteOnClient()
{
    //Do the same calculations
}

And you are seeing that the calculations are done twice and you don’t want this to happen on the host. Well, a host is both server and client so it will and should execute both of these. You will have to use isServer/isClient in order to handle this in the simplest way.

What you should be doing though is sticking with a server-authoratative design - have the server do whatever calculations you need and only send the result to the clients:

[Command]
private void CmdExecuteOnServer()
{
    float r = /* get the result of your calculations */;
    RpcExecuteOnClient(r);
}

[ClientRpc]
private void RpcExecuteOnClient(float r)
{
    //Do whatever you need to do with the result
}

In general, try to avoid thinking as if you have a host - imagine that all clients are remote clients. If you do this, your code will still work for a host because hosts still execute client code.

1 Like

This was the thinking that created the problem in the first place, treating the host as a client and separate from the server.

So I need to think of the host as the server as well as a client not just a client.

Server authoritative design or not the host is the server and should be treated as such and not only thought of as a client. The host is still a special case, no matter what the docs say.

Can you post your code?

Currently working on another solution that doesn’t cause the problem, so that code is gone.

I was trying to sync an array without SyncVars. So when I wanted to modify a value in the array I would get it to do it on the server then tell the clients to do the same. Now I am trying to get it to work with SyncListStruct having the server modify the list and then the clients would get the results.

This works as the host so far no problems on that end. The problem I am having now is that when a client connects it gets an out of sync exception.

InvalidOperationException: out of sync
System.Collections.Generic.Dictionary2+Enumerator[System.String,System.Int32].VerifyState () (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:912) System.Collections.Generic.Dictionary2+Enumerator[System.String,System.Int32].MoveNext () (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:835)
System.Collections.Generic.Dictionary`2+KeyCollection+Enumerator[System.String,System.Int32].MoveNext () (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:1028)
UnityEngine.Networking.NetworkCRC.Dump (UnityEngine.Networking.NetworkSystem.CRCMessageEntry[ ] remoteScripts) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkCRC.cs:106)
UnityEngine.Networking.NetworkCRC.ValidateInternal (UnityEngine.Networking.NetworkSystem.CRCMessageEntry[ ] remoteScripts, Int32 numChannels) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkCRC.cs:75)
UnityEngine.Networking.NetworkCRC.Validate (UnityEngine.Networking.NetworkSystem.CRCMessageEntry[ ] scripts, Int32 numChannels) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkCRC.cs:66)
UnityEngine.Networking.NetworkClient.OnCRC (UnityEngine.Networking.NetworkMessage netMsg) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkClient.cs:801)
UnityEngine.Networking.NetworkConnection.HandleReader (UnityEngine.Networking.NetworkReader reader, Int32 receivedSize, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:430)
UnityEngine.Networking.NetworkConnection.HandleBytes (System.Byte[ ] buffer, Int32 receivedSize, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:386)
UnityEngine.Networking.NetworkConnection.TransportRecieve (System.Byte[ ] bytes, Int32 numBytes, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:536)
UnityEngine.Networking.NetworkClient.Update () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkClient.cs:648)
UnityEngine.Networking.NetworkClient.UpdateClients () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkClient.cs:861)
UnityEngine.Networking.NetworkIdentity.UNetStaticUpdate () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkIdentity.cs:1059)