Skip to content

How to disable "NetworkVariable is written to, but doesn't know its NetworkBehaviour yet" LogWarning? #2561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
andreyshade opened this issue May 15, 2023 · 8 comments
Labels
type:support Questions or other support

Comments

@andreyshade
Copy link

I'm using NetworkVariables for configuring some NetworkObjects before spawning and a lot of LogWarnings:

NetworkVariable is written to, but doesn't know its NetworkBehaviour yet. Are you modifying a NetworkVariable before the NetworkObject is spawned?

in my game server logs.

I tried to set log level in the NetworkManager component to error level but it didn't help me and warnings still appear in the logs.
image

@andreyshade andreyshade added stat:awaiting-triage Status - Awaiting triage from the Netcode team. type:support Questions or other support labels May 15, 2023
@NoelStephensUnity
Copy link
Collaborator

@andreyshade
Setting the value directly before the associated NetworkObject is spawned will typically yield this error message.
It is recommended to set the value when it is instantiated or when NetworkBehaviour.OnNetworkSpawn is invoked.

As an example:

    public class MyNetworkBehaviour : NetworkBehaviour
    {
        [HideInInspector]
        public NetworkVariable<int> SomeNetworkVariable;

        [HideInInspector]
        public NetworkVariable<int> SomeOtherNetworkVariable = new NetworkVariable<int>();

        public int SomeValue;
        public int SomeOtherValue;

        private void Awake()
        {
            SomeNetworkVariable = new NetworkVariable<int>(SomeValue);
        }


        public override void OnNetworkSpawn()
        {
            if (IsServer)
            {
                SomeOtherNetworkVariable.Value = SomeOtherValue;
            }
            base.OnNetworkSpawn();
        }
    }

The first approach (SomeNetworkVariable), the value is set when it is instantiated on all instances (clients or server).
The second approach (SomeOtherNetworkVarialbe), the property is instantiated when it is declared (defaults to server write permissions) but is set when the server spawns the associated NetworkObject. Since the server is authority over spawning, it will always spawn (locally) first on the server-host instance and then the spawn message is generated and sent to the clients. Because of this, having the server set the value during OnNetworkSpawn still guarantees that any value set will be replicated when spawned on the clients.

Let me know if this helps you with the issue you are experiencing?

@NoelStephensUnity NoelStephensUnity added the stat:awaiting-response Awaiting response from author. This label should be added manually. label May 17, 2023
@CodeSmile-0000011110110111
Copy link

CodeSmile-0000011110110111 commented Feb 27, 2024

Glad this can be worked around but it adds unnecessary overhead to a component and complicates the Spawn/Init process by having to have more code. I would expect setting initial NetworkVariables from outside the component to be a common use-case. I frequently see user questions asking how to initialize NetworkVariable with a value, respectively wondering why the initial value is 0.

I would expect to be able to do the following without raising a warning, in line with my feature suggestions to add a pre-spawn callback to InstantiateAndSpawn:

Server:

  • var obj = Instantiate(prefab)
  • var t = obj.GetComponent
  • t.SomeNetworkVariable.Value = 123;
  • SpawnWithOwnership(obj, owner)

To write the above without causing the warning, component T would need to have an additional temporary value property that holds the value so it can be assigned to the NetworkVariable in the component's OnNetworkSpawn by the server - which compared to the code above adds unnecessary complexity.

Overall working around this warning complicates the code, adds more chance for creating initialization bugs, and adds memory overhead to affected components due to temporary value fields.

Alternatively the OnNetworkSpawn could look up the initial value elsewhere, but this may add undesirable coupling and may simply shift the complexity elsewhere.

@NoelStephensUnity
Copy link
Collaborator

NoelStephensUnity commented Mar 1, 2024

This has been something we are looking into fixing.
Using the following example script:

public class InitializeNetworkVariable : NetworkBehaviour
{
    private NetworkVariable<int> m_NetworkVariableInitA = new NetworkVariable<int>(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
    public NetworkVariable<int> NetworkVariableInitB;

    public void SetValue(int value)
    {
        m_NetworkVariableInitA.Initialize(this);
        m_NetworkVariableInitA.Value = value;
    }


    public override void OnNetworkSpawn()
    {
        Debug.Log($"NetVarA: {m_NetworkVariableInitA.Value}");
        Debug.Log($"NetVarB: {NetworkVariableInitB.Value}");
        base.OnNetworkSpawn();
    }
}

Then your code to spawn would look like this:

        if (Input.GetKeyDown(KeyCode.S))
        {
            var instance = Instantiate(Prefab);
            var networkVarInit = instance.GetComponent<InitializeNetworkVariable>();
            networkVarInit.SetValue(100);
            networkVarInit.NetworkVariableInitB = new NetworkVariable<int>(200, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);

            instance.GetComponent<NetworkObject>().SpawnWithOwnership(someClientId);
        }

Where there are two options currently to apply a value prior to spawning:

  • Setting it in a method after initializing with the associated NetworkBehaviour component instance
  • Constructing the NetworkVariable prior to spawning and passing in the default value.

Taking your expected behavior usage pattern, it would look like this with the above approach:

  • var obj = Instantiate(prefab)
  • var t = obj.GetComponent
  • Either option to set variable value prior to spawning:
    • Setter method
    • Construct NetworkVariable
  • SpawnWithOwnership(obj, owner)

I think the approach you might be looking for would be more like:

  • var obj = Instantiate(prefab)
  • var t = obj.GetComponent
  • t.SomeNetworkVariable.Initialize(t); <---- pre-initialize with the NetworkBehaviour component
  • t.SomeNetworkVariable.Value = 123; <---- then set the value directly
  • SpawnWithOwnership(obj, owner)

@CodeSmile-0000011110110111
Copy link

CodeSmile-0000011110110111 commented Mar 2, 2024

Thanks for the detailed explanation! Works perfectly!
I tried both ways and prefer the Init method which makes it clearer that this is init-only behaviour and the property setter remains trivial (no branching).

@Nikmazza
Copy link

Nikmazza commented May 5, 2024

This has been something we are looking into fixing. Using the following example script:

public class InitializeNetworkVariable : NetworkBehaviour
{
    private NetworkVariable<int> m_NetworkVariableInitA = new NetworkVariable<int>(default, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
    public NetworkVariable<int> NetworkVariableInitB;

    public void SetValue(int value)
    {
        m_NetworkVariableInitA.Initialize(this);
        m_NetworkVariableInitA.Value = value;
    }


    public override void OnNetworkSpawn()
    {
        Debug.Log($"NetVarA: {m_NetworkVariableInitA.Value}");
        Debug.Log($"NetVarB: {NetworkVariableInitB.Value}");
        base.OnNetworkSpawn();
    }
}

Then your code to spawn would look like this:

        if (Input.GetKeyDown(KeyCode.S))
        {
            var instance = Instantiate(Prefab);
            var networkVarInit = instance.GetComponent<InitializeNetworkVariable>();
            networkVarInit.SetValue(100);
            networkVarInit.NetworkVariableInitB = new NetworkVariable<int>(200, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);

            instance.GetComponent<NetworkObject>().SpawnWithOwnership(someClientId);
        }

Where there are two options currently to apply a value prior to spawning:

  • Setting it in a method after initializing with the associated NetworkBehaviour component instance
  • Constructing the NetworkVariable prior to spawning and passing in the default value.

Taking your expected behavior usage pattern, it would look like this with the above approach:

  • var obj = Instantiate(prefab)

  • var t = obj.GetComponent

  • Either option to set variable value prior to spawning:

    • Setter method
    • Construct NetworkVariable
  • SpawnWithOwnership(obj, owner)

I think the approach you might be looking for would be more like:

  • var obj = Instantiate(prefab)
  • var t = obj.GetComponent
  • t.SomeNetworkVariable.Initialize(t); <---- pre-initialize with the NetworkBehaviour component
  • t.SomeNetworkVariable.Value = 123; <---- then set the value directly
  • SpawnWithOwnership(obj, owner)

Hi Noel! how are you?
I tried this approach and whilst the log does dissapear, syncronization between server and client does not occur.
I fear it might be due to our pipeline working against us.
We are trying to allow our modders to add network behaviours in their mods so they can add complex mechanics into the game

Our mod has a folder which contains a network object prefab
when mod is loaded, we load the prefab into the network manager network prefab list using
NetworkManager.Singleton.PrefabHandler.AddNetworkPrefab(prefab);
when client presses button 1, we send an rpc to server
server then instantiates and spawns the network object loaded from the mod
it then tries to update a network variable from the spawned network object 

i read somewhere that networkbehaviours cannot be added during runtime, and while we are not specifically adding NB during runtime, maybe importing them and their network objects/prefabs from a mod is a similar case?

@NoelStephensUnity NoelStephensUnity added stat:Investigating Issue is currently being investigated Tracking Has been added to tracking and removed stat:awaiting-response Awaiting response from author. This label should be added manually. labels Jan 8, 2025
@NoelStephensUnity
Copy link
Collaborator

@Nikmazza
Your scenario is added to our tracking and will be reviewed as to whether we can provide an example (there is a way to do this with a
"Generic" network prefab that you then define what components and/or settings you want and assign/set those within NetworkBehaviour.OnSynchronize.

@michalChrobot michalChrobot added stat:awaiting-response Awaiting response from author. This label should be added manually. and removed stat:awaiting-triage Status - Awaiting triage from the Netcode team. labels Apr 1, 2025
@michalChrobot michalChrobot removed the stat:awaiting-response Awaiting response from author. This label should be added manually. label Apr 10, 2025
@Forelone
Copy link

Forelone commented Apr 27, 2025

I might be late but when you try to define variable on OnNetworkSpawn like;

Health = new NetworkVariable<float>(100);

it can cause this issue. Try this instead:

Health.Value = 100

It might be because when object is initialized that syncronized variable is created again. so it becomes de-synced.

@github-actions github-actions bot added the stat:reply-needed Awaiting reply from Unity account label Apr 27, 2025
@EmandM EmandM added stat:awaiting-response Awaiting response from author. This label should be added manually. and removed stat:reply-needed Awaiting reply from Unity account labels May 26, 2025
@EmandM
Copy link
Collaborator

EmandM commented May 26, 2025

Closing this issue as a duplicate of #2279

@EmandM EmandM closed this as completed May 26, 2025
@github-actions github-actions bot removed stat:awaiting-response Awaiting response from author. This label should be added manually. stat:Investigating Issue is currently being investigated Tracking Has been added to tracking labels May 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:support Questions or other support
Projects
None yet
Development

No branches or pull requests

7 participants