Search code examples
c#unity-game-engineunity-networking

How Client / Server RPC works with global variables?


I am quite new to Unity and i can't find any logical answer to the behaviour i am seeing.

I have written a basic script such as :


public class PlayerPosition : NetworkBehaviour
{

    private Dictionary<string, int> testDict = new();

    [ServerRpc(RequireOwnership = false)]
    private void HitServerRpc(string key, int value)
    {
        RefreshClientRpc(key, value);
    }

    [ClientRpc]
    private void RefreshClientRpc(string key, int value)
    {
        testDict[key] = value;
        foreach (var item in testDict)
            {
                Debug.Log($"Item in current dict {item}");
            }
    }

   // Other logical code that calls only HitServerRpc().

}

I am using this script on my player Prefab in a client / host situation.
I have one client and one host (server + client) for the test and the question.

My question is : Why testDict has only one key and one value when at least 2 different keys and value were added through 2 different RPC calls, one from each client ?

The log Item in current dict is shown only once even if the HitServerRpc() was called on two different clients :

  • HitServerRpc("user1", 3)
  • HitServerRpc("user2", 4)

All clients should have testDict equaled to : {{"user1", 3}, {"user2", 4}}

PS : Weirdest thing, i have tried to move the testDict in a static class and update it internally inside the static class instead of the class handling the RPC calls, it now has the correct values on the host but still not on the client.


Solution

  • All clients should have testDict equaled to : {{"user1", 3}, {"user2", 4}}

    I see why you think that, but no! Each of those calls accordig to you comes from a different client -> and thus from/to a different instance of your PlayerPosition.

    Let's say as in your description you have two players user1 and user2.

    Each of these is calling HitServerRpc on their respective local authority instance of PlayerPosition. Which then gets relayed as a ClientRPC to the other connected clients but still only to their respective instance.

    Trying to visualize this

    user 1 Device              Server       user 2 Device
    
    user 1 (local auth) ---->  user 1 ----> user1
    user 2              <----  user 2 <---- user 2 (local auth)
    

    The result would be that the respective dictionaries are indeed synced, however, PlayPosition belonging to user 1 would only know the key user1 and accordingly the other instance only have the user2 key.

    So I think in your use case actually rather using a static would make sense. There is no need though to put it into a different class. You could use

    private static readonly Dictionary<string, int> testDict = new();
    

    so all the local instances of PlayerPosition use the same dictionary instance.