Settings variables after spawn on clients

Hi,

I’m currently working on a network project and I did not found a simple way to set variable on spawned gameobject on clients.

If I do something like this :

GameObject go = Instantiate(prefab);
go.GetComponent<AnyComponent>().anyVariable = anyValue;
NetworkServer.Spawn(go);

The anyVariable will be set only on host.

I know about

, and it work on some situations, for exemple if it always spawn with the same values to change (you cannot add custom parameters), or for pooling, and you have to parse all assetId each time. But it does not help if you want dynamic values.

Anyone know a way to pass a changing parameter on spawn that will be also changed in all client? for exemple if Server decided to spawn an enemy prefab wich have 5 attackPoints, but sometime spawn it with 10 or 20 (not for players, for any kind of object)?

Thanks in advance

Is your variable a [SyncVar]? There is a NetworkBehaviour [SyncVar] attribute that can be used.

Only NetworkBehaviour SyncVar’s are automatically sync’d to client. Any other field will have a unique local value.

Thank i’ll try that.
Can a SyncVar be a link to an another gameobject (with networkIdentity)? I’ll try with a netwotkId

Is this the normal way to do for initialization? this variables will not change during game after the spawn so…

SyncVar’s are primitive types (integers, floats, etc.) and cannot be object reference handles.

You can send an uint NetworkID and then do lookups on the client.

uint syncVarParentNetID;
ClientScene.FindLocalObject(new NetworkInstanceId(syncVarParentNetID));

I know syncvar are not sent on network for initial state, only when value change on server, or on spawn.

Do you know a way to share initial syncvar values?

And again : set a variable only existing for initial setup (like max life, color) to syncvar , even if it does not change during gameplay, and change it during the spawning command is the only way to set initial values on client after spawning?

I’m not sure I completely follow, but I’ll tell you what I know.

The client will call…
Client NetworkBehaviour.Awake() //the syncVar is not updated yet
Client NetworkBehaviour.OnStartClient() //the syncVar now has the proper value EDIT Use OnStartClient() not Start()

But the SyncVar does not call the hook during initialization regardless if the value has changed. You must manually call the hook if you want something to happen.

So the order might look something like this
Server.Awake() //set SyncVar value here
SpawnObject()
Server.Start()
Client.Awake()
Client.OnStartClient() //on the client use the SyncVar value here… because it is guaranteed to be updated.

So to recap there are 2 rules:
1: On the server set SyncVar values BEFORE calling spawn()
2: On the client only use SyncVar values AFTER OnStartClient() has been called (not during Awake because they will not be updated yet)

Hope this helps.

Ok thank you, usefull to know for initialisation. I’m still a bit confused to use SyncVar for init values only that will not change during the game, but if it works why not.

But if things happen in this order:

  • server call spawn()
  • server change syncvar values during gameplay
  • later during the game a new client connect : the spawned objects seems to not have the correct syncvar values (after start) until the values are modified again on server.
    What do you mean by call Hook manually? on client or server? on client it would be impossible since the hook have the right value need in parameter, and on server how to send the current values again? re affectation on the same value? and how to detect on server a new client instance has been spawned on a new client? (as Command cannot be call on client whitout authority)?

For SyncVar’s that are init values that never change
You can use SyncVar’s but use NetworkSettingsAttribute.sendInterval = 99999999 (~inf) to prevent any future updates or bandwidth. Unfortunately the sendInterval is common to the entire NetworkBehaviour so you cannot mix send intervals of 0.1s (the default) with send intervals of 99999999 (~inf) without having 2 separate NetworkBehaviour scripts.

http://docs.unity3d.com/Manual/UNetSpawning.html

“- later during the game a new client connect : the spawned objects seems to not have the correct syncvar values (after start) until the values are modified again on server.” This seems bugged. The client should always have the latest values by the time Start() is called on the client. Note that even though the value may have changed the SYNCVAR HOOK WILL NOT BE CALLED DURING INITIALIZATION! So during client OnStartClient() you must manually check to see if the SyncVar value has changed (or manually call the SyncVar hook on the client)

***EDIT: SyncVars will have correct values after OnStartClient() not Start()

The client is not guaranteed to have the latest value in Start().

See: http://docs.unity3d.com/ScriptReference/Networking.NetworkBehaviour.OnStartClient.html

“The values of SyncVars on object are guaranteed to be initialized correctly with the latest state from the server when this function is called on the client”

1 Like

I’m still curious about “call hook manually”.

If I have this kind of code :

[SyncVar(Hook = "MyHook")]
float variableToSync;

public void MyHook(float newValue)
{
    variableToSync = newValue;
}

What should I do to call hook on client?

void AnyFct()
{
    //hook call ?
    MyHook(whatValueToSetToParameter);
}

A SyncVar cann only be Changed on the server.
The “Hook” is called on the Client when the SyncVar Changes it value.

To Set a SyncVar by the client you need a Command, Like:

[SyncVar]
float mySyncVar;

[Command]
public void CmdSetMyVar(float myVar)
{
    mySncVar = myVar;
}

Ok, but how do you do that on a object on client that does not have authority? You cannot call command. And I don’t want to set a syncVar but to “ask server to send me the last value” of the syncVar.

I don’t know a way to send or recipe commands or rpc’s form objects that does NOT have a NetworkAuthority.

The only was is to send raw messages in this case.

What kind of object you have?

Any kind of object, player, enemies, managers. anything that have a networkidentity and is on client.

I need to have any value correctly initialized when joining a existing party (where values on server may have changed). Seems that client have to wait server object change the sync value again, or to send a raw message to ask for this values.

During OnStartClient you have the latest updated value. Just look for it.

[SyncVar]
int mySyncVarInt;

void OnStartClient()
{
   MethodToDoSomethingWithSyncVar(mySyncVarInt)
}