Why does my server RPC sometimes execute on the client?

I’m learning Netcode for GameObjects and have been spending a few hours simply trying to send a movement command from my client to the server, and have it execute only on the server. During testing with ParrelSync, I’m not sure why, but sometimes when I instantiate a client I notice the client GameObject has also moved. I only call the Move() function in the SendToServerRpc function - which as I understand, executes server side. If anyone can shed some light on what I’m doing wrong here I’d be extremely grateful. For context I’m using Unity version 2023.3.0b7.

Here’s what I’m working with:

public class Player: NetworkBehaviour
{
    public override void OnNetworkSpawn(){
        if(IsOwner && IsClient){
            SendToServerRpc("Message from client");
        }
    }

    void Move(){
        transform.position = new Vector3(1, 1, 1);
    }

    [Rpc(SendTo.Server)]
    public void SendToServerRpc(string msg) {
        if(IsServer){
            Debug.Log($"Player position on server before moving: {transform.position}");
            Move();
            Debug.Log($"Player position on server after moving: {transform.position}");
            SendToClientRpc("Message from server");
        }
    }

    [Rpc(SendTo.NotServer)]
    public void SendToClientRpc(string msg){
        Debug.Log("In Client RPC, message sent from server: " + msg);
    }
}

Your setup is presumably only for testing purposes but just in case, the position can be set by the server when instantiating the network object. Perhaps this is what’s happening?

For this to work the Player object also needs to have a NetworkTransform. Otherwise the position won’t be synchronized back to clients.

In any case, logging should help and when it gets trickier be sure to use the debugger to step through your code.

Btw, unless you do something out of the ordinary, the IsClient check is superfluous. It may actually get in the way depending on whether it’s true or false for the host player (can’t recall, I think it should be true but these checks are a major source of confusion even for me).

It would also fail to work if you are running a dedicated server and the server is the owner of the player objects, in that case the RPC isn’t sent because the server is the owner but not a client. Be very careful with these checks as they are easily misleading or may stop to work in some scenarios, particularly when combined like here (owner + client).

Please do upgrade to Unity 6 preview (aka 2023.3 non-beta).
This will also allow you to ditch ParrelSynch in favor of Multiplayer Playmode which is far more fun to work with. :wink:

1 Like

I have upgraded my project to Unity 6 preview, after the usual upgrade error debugging this issue has seemingly been resolved. Instead, now when the GameObject instantiates, sometimes it does not appear to execute on the server. I’m not sure if this is just a visual thing with the local server, because the transform when logged shows that the position has changed, just in the Unity editor for the server instance, the move isn’t always reflected in the game view/inspector.

If anyone else has the issue, it was because I was updating the transform once in a single frame, I still don’t know why but I guess somtimes the process of updating the transform got skipped. I was simply just trying to test so I didn’t think that would be an issue, but processing the movement over multiple frames allowed the transform to reliably update as expected.

EDIT: calling Physics.SyncTransforms manually forced the transform to update, still no idea why it wasn’t doing this automatically though.