Sync only on specific clients with UNET?

I would like to discriminate between clients when it comes to network synchronization of transforms and possibly other data.

Example:

3 players on a server all have vision cones, network IDs and network transforms. Player 3 is currently visible to players 1 and 2. Player 3 leaves the vision cone of player 1 but not player 2.

Is there any way using unity’s networking API to tell the server to stop sending network transform information about player 3 to player 1? If player 1 told player 3 their name was john, could I specifically update player 3’s client player 1 gameobject with player 1’s name?

Currently I’ve tried turning off the network transform of player 3 at player 1’s client, but player 1 still receives and implements that information. Turning off the network transform at the server would obviously stop sending data to player 2 as well.

I want to ensure this functionality is not built in, and I’m just missing it, before I attempt a custom script for it.

I’ve looked at the Proximity checker, but that I can tell I’m limited to using it in a sphere/circle, and the only tutorial I found using it was in german so I’ve been having a bit of difficulty following in a way that I can use it for myself. The page says we can reconfigure it to make your own visual tests to change observers, but I’ve not seen any examples anywhere of how this is done.

Thanks in advance

Edit: As an attempt at a hack, I tried deleting the network transform at the client side, which stopped them from at least using the network transform information, then restoring it. However, the new network transform doesn’t hook up making it useless.

This is currently not possible using the HLAPI, but you can download the Networking source code and change it to use the network proximity checker. Also, creating a custom script for it isn’t that hard.

Helper class:

class MyMsgType
{
	public const short PositionChange = MsgType.Highest + 1;
}

Client class:

class Client : NetworkBehaviour
{
	void Start()
	{
		NetworkManager.singleton.client.RegisterHandler(MyMsgType.PositionChange, OnGetPositionFromServer);
	}

	// Called automaticaly by the NetworkManager
	// because we registered in on the start.
	void OnGetPositionFromServer(NetworkMessage netMsg)
	{
		var msg = netMsg.ReadMessage<PositionChangeNetMsg>();

		if (msg.player != gameObject)
			msg.player.transform.position = msg.newPosition;
	}

	// Call this when you recive the input.
	void OnPositionChange()
	{
		var msg = new PositionChangeNetMsg()
		{
			player = gameObject,
			newPosition = transform.position
		};

		// We are sending unreliable because
		// the position is going to change a lot
		// so if one messege is lost, it is going
		// to be corrected by the next one.
		NetworkManager.singleton.client.SendUnreliable(MyMsgType.PositionChange, msg);
	}
}

Server class:

class Server : NetworkBehaviour
{
	void Start()
	{
		NetworkServer.RegisterHandler(MyMsgType.PositionChange, OnGetPositionFromClient);
	}

	void OnGetPositionFromClient(NetworkMessage netMsg)
	{
		var msg = netMsg.ReadMessage<PositionChangeNetMsg>();

		var networkIdentity = msg.player.GetComponent<NetworkIdentity>();

		// The observers are built automatically if
		// you have the NetworkProximityChecker
		var observers = networkIdentity.observers;

		// each observer is just a NetworkConnection
		foreach (var observer in observers)
		{
			var connection = NetworkServer.connections[observer.connectionId];

			// again, we are sending on the unreliable
			// because its faster.
			connection.SendUnreliable(MyMsgType.PositionChange, msg);
		}
	}
}

The actual message that is going to be sent:

class PositionChangeNetMsg : MessageBase
{
	public GameObject player;
	public Vector3 newPosition;
}

Notes:

  • I didn’t test it but in theory it should work.
  • You should remove the network transform if you use this script.