Search Unity

Resolved Help with NetworkVariable.OnValueChanged callback

Discussion in 'Multiplayer' started by GuirieSanchez, Dec 20, 2022.

  1. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452
    My setup is a little weird, but stay with me on this one for a moment.

    I have a bunch of NetworkVariables (let's say, 10) that I use to communicate between the server and clients. When a certain event happens, I want to copy and paste whatever parameters the server has at that very moment and send it to the client. In order to do so, I update the NetworkVariables' values with the server parameters in this fashion:

    Code (CSharp):
    1. // NetworkVariables:
    2. netVar1.Value = serverValue1;
    3.  
    4. // and NetworkLists:
    5. netList1.Clear();
    6.         for (int i = 0; i < serverList1.Count; i++)
    7.         {
    8.             netList1.Add(serverList1[i]);
    9.         }
    10.  
    11.  
    It works fine, but I have 2 problems with this method:

    (1) I noticed that, when updating the NetworkVariable's value, let's say
    netVar1.Value
    , if its value is the same as the
    serverValue1
    , then the OnValueChange callback does not get called. Which makes sense, but I was wondering if there's a way to force the callback if I'm updating it with the same value for the purposes that I'll mention in (2).

    (2) I want to trigger a second event on the client side only when all NetworkVariables' values have been updated, and not before because otherwise, the client will be outdated when the event takes place. I was wondering if there's a known way to accomplish something similar to what I'm looking for. Since I have no idea about it, I coded an alternative that is really shaky: I just made a parameter (integer) (for instance
     _counter = 0;
    ) to count up whenever a NetworkVariable is updated. Since in this example I have 10 NetworkVariables, let's say that, whenever a NetworkVariable.OnValueChanged callback is triggered, I count up and check if the counter value is equal to 10 (to check whether all values have been updated yet or not):

    Code (CSharp):
    1. _counter++;
    2. if(_counter >= 10)
    3. {
    4.     // trigger the second event
    5.     _counter = 0;
    6. }
    On paper, it works fine. However, the problem is that, as I mentioned, if one of the NetworkVariables' values is the same as the Server's parameter, then the OnValueChanged callback won't be called, and therefore the
    _counter
    parameter won't reach 10, so the second event never gets triggered.
    Another problem that comes to mind is that if two clients trigger the first event (for updating the NetworkVariables) at the same time (or close in time), since the NetworkVariables callbacks are being called on each client, I imagine that the
    _counter
    method can get really messy.

    Any idea is highly appreciated
     
    Last edited: Dec 20, 2022
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,890
    You are doing yourself a disservice trying to implement this with NetworkVariables.

    Instead, use an RPC call. Send a custom INetworkSerializable struct that contains all of the values. In fact, this should be the same struct the server uses to store all these values locally.

    You then send this struct by calling a ClientRpc method with this struct as a parameter. Client receives all values at once. If needed, you can determine which values actually changed by comparing it with the client's current set of values, before replacing them with the values from the server.

    If you still need individual network variables to sync whenever a change occurs, you can keep using them but the struct will be the authoritative data storage for these values. Meaning: the server applies a value change to both struct and Netvar, the client upon receiving a netvar change also updates its local struct and only uses that for retrieving the current value.
     
    GuirieSanchez likes this.
  3. GuirieSanchez

    GuirieSanchez

    Joined:
    Oct 12, 2021
    Posts:
    452
    Thank you for the explanation. I've considered JSON, structs, and finally NetworkVariables for this purpose. And I'm the first to admit that the NetworkVariable method looks horrible for my use case.

    Using a struct was my first attempt, but I stopped because I didn't know how to set it up and send it.

    I guess though I'm going to be studying structs and INetworkSerializable and use them since they look the most suitable.

    Thanks again. I'll open a new thread if beat my head against the wall.