Unity UNET - calling [Command] outside of player object

James picture James · Jul 28, 2015 · Viewed 13.1k times · Source

So I understand that [command] does not work on non-player objects, however ...why? how am I supposed to sync data of non-player objects, such as NPC locations. The ability to call Command on non-player objects would save a lot of repeated computation time on each client.

Has anyone come up with a workaround to this design decision?

Also, it seems that SyncVars aren't being synced if not on player objects as-well.

Right now my best strategy is to store a whoooole lot of data on the player objects and have to keep making references to it from outer classes

EDIT: OOps my mistake, as pointed out SyncVars are working on non-player objects, just only when updated on the server

Answer

peterept picture peterept · Jul 28, 2015

Yes, [Command] is for sending player RPC's to server.

However, SyncVars will sync the state from server to client on any object with a NetworkBehaviour (not just a player object).

The authoritative server approach is to have the server spawn your NPC locations with NetworkServer.Spawn() and then update the NPC Syncvars, and they automatically will update on all clients.

If you really need to send a [Command] from a client, with new versions of Unity you can grant a scene object local player authority using AssignClientAuthority():

If you have a PRO license and can access the Unity 5.2 beta builds then they added this in 5.2b1

Networking: Added support for client-side authority for non-player objects. The new function NetworkServer.SpawnWithClientAuthority(GameObject obj, NetworkConnection conn) allows authority to be assigned to a client by its connection when an object is created. This would typically be used in a command handler for a client asking to spawn an object, then the client's connection would be passed in. For example:

[Command] 
void CmdSpawn() { 
    var go = (GameObject)Instantiate(otherPrefab,
    transform.position + new Vector3(0,1,0), Quaternion.identity);
    NetworkServer.SpawnWithClientAuthority(go, base.connectionToClient); 
}

For setting the authority on objects after they are created, there are the new functions AssignClientAuthority(NetworkConnection conn) and RemoveClientAuthority(NetworkConnection conn) on the NetworkIdentity class. Note that only one client can be the authority for an object at a time. On the client that has authority, the function OnStartAuthority() is called, and the property hasAuthority will be true. The set of objects that is owned by a client is available in the new property NetworkConnection.clientOwnedObjects which is a set of NetworkInstanceIds. This set can be used on the server when a message is received to ensure that the client that sent the message actually owns the object. When a client disconnects, the function DestroyPlayersForConnection now destroys all the objects owned by that connection, not just the player object. Objects which have their authority set to a client must have LocalPlayerAuthority set in their NetworkIdentity. Previously only player objects could have local authority, which meant that the NetworkTransform (and other components) could only be used for controlling the single player object for a connection on a client. With these changes it is possible to have multiple objects on a client that are locally controlled.