Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question NetworkVariable OnValueChanged isn't invoked on clients

Discussion in 'Netcode for GameObjects' started by XyeCkr, Oct 30, 2022.

  1. XyeCkr

    XyeCkr

    Joined:
    Apr 21, 2018
    Posts:
    3
    I'm having an issue and can't really find what I am doing wrong.
    In my project, there are two teams that can collect points. I'm storing those points inside NetworkVariables of type int. The problem is, only the server is actually registering these Value-Changes. The clients are not.

    Scene placed Object containing the Network Variables:
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using Unity.Netcode;
    4. using UnityEngine;
    5.  
    6. public class GameModeArtifactHunt : NetworkBehaviour
    7. {
    8.     public delegate void OnPointsChangedDelegate(Team team, int previousValue, int newValue);
    9.     public delegate void OnRoundsChangedDelegate(Team team, int previousValue, int newValue);
    10.     public delegate void OnWinConditionFulfilledDelegate();
    11.  
    12.     public OnPointsChangedDelegate OnPointsChanged;
    13.     public OnRoundsChangedDelegate OnRoundsChanged;
    14.     public OnWinConditionFulfilledDelegate OnWinConditionFulfilled;
    15.  
    16.     [SerializeField] private float pointsPerSecond = 5f;
    17.     public int pointsPerRound = 1200;
    18.     public int roundsForWin = 3;
    19.  
    20.     public Dictionary<Team, NetworkVariable<int>> teamPointsDict = new Dictionary<Team, NetworkVariable<int>>();
    21.     public Dictionary<Team, NetworkVariable<int>> teamRoundDict = new Dictionary<Team, NetworkVariable<int>>();
    22.  
    23.     private bool artifactIsHeld;
    24.     private Team teamHoldingArtifact;
    25.     private float currentTimer;
    26.  
    27.     void Start()
    28.     {
    29.         foreach (Team team in Enum.GetValues(typeof(Team)))
    30.         {
    31.             NetworkVariable<int> points = new NetworkVariable<int>();
    32.             NetworkVariable<int> rounds = new NetworkVariable<int>();
    33.             points.Value = 0;
    34.             rounds.Value = 0;
    35.             points.OnValueChanged += (prev, curr) =>
    36.             {
    37.                 Debug.Log("lol"); //<--- Does not get printed on clients
    38.                 OnPointsChanged.Invoke(team, prev, curr);
    39.             };
    40.             rounds.OnValueChanged += (prev, curr) => OnRoundsChanged.Invoke(team, prev, curr);
    41.             teamPointsDict.Add(team, points);
    42.             teamRoundDict.Add(team, rounds);
    43.         }
    44.  
    45.         DontDestroyOnLoad(this);
    46.  
    47.     }
    48.  
    49.     public void Update()
    50.     {
    51.         if (IsServer && artifactIsHeld)
    52.         {
    53.             currentTimer += Time.deltaTime;
    54.             if (currentTimer >= 1 / pointsPerSecond)
    55.             {
    56.                 currentTimer = 0;
    57.                 AddPoint();
    58.             }
    59.         }
    60.     }
    61.  
    62.     private void AddPoint()
    63.     {
    64.         teamPointsDict[teamHoldingArtifact].Value += 1;
    65.         if (teamPointsDict[teamHoldingArtifact].Value >= pointsPerRound)
    66.         {
    67.             teamPointsDict[Team.ORANGE].Value = 0;
    68.             teamPointsDict[Team.PURPLE].Value = 0;
    69.             teamRoundDict[teamHoldingArtifact].Value += 1;
    70.             if (teamRoundDict[teamHoldingArtifact].Value >= roundsForWin)
    71.             {
    72.                 OnWinConditionFulfilled.Invoke();
    73.             }
    74.         }
    75.     }
    76.  
    77.     [ServerRpc(RequireOwnership = false)]
    78.     public void NotifyArtifactOwnershipServerRpc(string team, ServerRpcParams serverRpcParams = default)
    79.     {
    80.         artifactIsHeld = true;
    81.         teamHoldingArtifact = Enum.Parse<Team>(team);
    82.         Debug.Log(teamHoldingArtifact);
    83.     }
    84.  
    85.     [ServerRpc(RequireOwnership = false)]
    86.     public void NotifyArtifactDroppedServerRpc(ServerRpcParams serverRpcParams = default)
    87.     {
    88.         artifactIsHeld = false;
    89.     }
    90. }
    91.  
    92. public enum Team
    93. {
    94.     ORANGE, PURPLE
    95. }
     
  2. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    676
    The problem may be due to the network variables being created in Start(), I've only ever seen them declared as class fields.
     
  3. XyeCkr

    XyeCkr

    Joined:
    Apr 21, 2018
    Posts:
    3
    That was the problem, thank you!

    Although it's really weird that that would be an issue... Seems strange to me.
     
  4. cerestorm

    cerestorm

    Joined:
    Apr 16, 2020
    Posts:
    676
    Start is called quite late on in the creation of the network object, I would guess the network manager isn't aware of any network variables there. It's likely it doesn't expect to find them anywhere except at the class level.
     
  5. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,576
    An older version (0.1) of the NetworkVariable manual page actually states that the NetworkVariable has to be declared as a field.

    The doc also mentions that the variable should only be set in Awake or during or in OnNetworkSpawn or after spawn.