-
Notifications
You must be signed in to change notification settings - Fork 437
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
Automatically invoke NetworkVariable.OnValueChanged
when spawning
#3186
Comments
Hi @babaq, The documentation provides the description of the behavior behind NetworkVariables, but I am going to see if we can improve upon that documentation to include additional information that will help clarify the state of NetworkVariables and when OnValueChanged is invoked.
Take the following example into consideration: public class MyNetworkBehaviour : NetworkBehaviour
{
// One way to check for default previous valu
private const int InitialSomeIntValue = 10;
private NetworkVariable<int> m_SomeInt = new NetworkVariable<int>(InitialSomeIntValue);
private int m_InitialSomeIntValue;
protected override void OnNetworkPreSpawn(ref NetworkManager networkManager)
{
m_InitialSomeIntValue = m_SomeInt.Value;
base.OnNetworkPreSpawn(ref networkManager);
}
public override void OnNetworkSpawn()
{
m_SomeInt.OnValueChanged += OnSomeIntChanged;
if (IsServer)
{
m_SomeInt.Value = Random.Range(20, 1000);
}
else
{
// Non-authority (no write permissions) instances can initialize
// from the initial value of the NetworkVariable this way.
// The initial value is when the previous and current values are
// the same.
OnSomeIntChanged(m_InitialSomeIntValue, m_SomeInt.Value);
}
base.OnNetworkSpawn();
}
private void OnSomeIntChanged(int previous, int current)
{
Debug.Log($"SomeInt changed from ({previous}) to ({current})");
}
} What will happen is that the server will invoke OnValueChanged during OnNetworkSpawn because the value (server/authority relative) does indeed change. Why is it this way? I know...it might sound confusing but I can help further clarify. When a NetworkObject is spawned on a non-authority/non-write permission instance the previous state and current state are considered "the same". This is to provide the baseline in which that instance can determine any changes to the state from that point in time forward. Then there is the value assigned to the NetworkVarible when it is instantiated (typically during the declaration portion of the instantiation) that may or may not be a value that a user wants to have as the "previous state" during the spawning of a non-authority instance. Some designs might not even care about the default value as that is configured by the authority instance during OnNetworkSpawn and/or a users script might not want OnValueChanged to be triggered when an instance is spawned and only cares about when it changes from the point of being instantiated and spawned forward. Finally, if you were to have a NetworkObject pool where you are re-using instances, you could eventually end up spawning an instance that was already spawned...which you can't set the value of a NetworkVariable on a non-authority instance... so the "current" value of a despawned pooled object could be some value that you might not want to have as the previous value since it was last used. As such, it made more sense to make the previous state and current state be the same values when spawned and for delta states to only occur after the NetworkObject is spawned. With that said, under the scenario you are describing it is recommended to just invoke the same method you are using to subscribe to the OnValueChanged event when a non-authority instance is spawned (or alternately you can create a third method that is invoked by OnNetworkSpawn and the method used to subscribe to the OnValueChanged event. This is a base behavior of NetworkVariable that we most likely will not change. |
I agree that when spawning, the instance of a prefab in a non-authority client should consider spawned value as current and previous value. The main concern is not about which should be current and previous values, but to sync the game states with server, not just sync For example, if a One easy way to differentiate the two is to register My current solution is to gather all NetworkVaribles and call one of other solutions as the way you suggested, is to call all public override void OnNetworkSpawn()
{
nv1 += Onnv1;
nv2 += Onnv2;
nv3 += Onnv3;
.
.
.
Onnv1(nv1.Value,nv1.Value);
Onnv2(nv2.Value,nv2.Value);
Onnv3(nv3.Value,nv3.Value);
.
.
.
base.OnNetworkSpawn();
} But this is a tedious repeated work which i don't like(especially when there are many NetowrkVariables). I think the first solution is a proper reuse the mechanism Netcode already has. |
@babaq Of course, we could always look into the possibility to add another property to NetworkObject that you could set which would force every NetworkVariable on any associated NetworkBehaviour to trigger OnValueChanged during spawn. Adding something like this to each NetworkVariable would yield close to the same amount of work one would have to run through (typing a few less characters but still having to specify this kind of behavior), and so making it an "all or none" property on NetworkObject seems to be a balance between the two....where you could still have some form of granular control. Would adding another property to NetworkObject that enabled the automatic triggering of NetworkVaraibles on the associated NetworkBehaviours help improve your development experience? |
@NoelStephensUnity Your suggested solution would definitely help a lot of people's developing experience. In the current state of our project, we have ~15 The Documentation have only shown examples where But if user want to invoke their |
Feedback
When load scene with in-scene placed
NetworkObject
or dynamically spawnNetworkObject
, connected client would spawn the object andNetworkVariable
value synced with the server. But theOnValueChanged
is not called, even if the value has been synced with the value of server, and is different from the default value that has been set inNetworkBehaviour
. The current behavior of skippingOnValueChanged
when spawning also doesn't depend on where theOnValueChanged
has been registered, inOnNetworkSpawn
,OnNetworkPreSpawn
or even inAwake
.This caused a lot of problems, because
NetworkVariable
may be a bool that enable/disable a renderer, or set a shader field throughOnValueChanged
. SkippingOnValueChanged
would make render frame inconsistent with what's intended. This is specially annoying when late-join client starts to spawn allNetworkObject
, withoutOnValueChanged
the game states would drastically different from server. The problem also shows up when a previouslyNetworkHide
object become visible again and client respwan the object but with inconsistent states from server.Suggested Changes
When spawning, all
NetworkVariable
should be synchronized, and correspondingOnValueChanged
should all get called, because clients are supposed to keep the same states as server. The server has likely changed the value ofNetworkVariable
and have already called theOnValueChanged
on server side, so when spawning happens, client need to not only sync all values ofNetworkVariable
, but also call allOnValueChanged
to keep the same states as server.An intuitive way is to register
OnValueChanged
inOnNetworkPreSpawn
, so that during subsequent spawning any valid callbacks registered will get called.The text was updated successfully, but these errors were encountered: