I have a question on networking. In particular, I want to use an array-based data structure that needs to be synched across the network between server and clients. While it is possible to implement the synchronization mechanism using both SyncVars and ClientRPCs, I am not sure which approach is better suited respectively more efficient for this task.
Background:
I’m working on a multiplayer game. During runtime, I want to store all player objects with unique IDs and names in a global array-based data structure called PlayerTable. When a player joins or leaves the game, the server is notified and updates the PlayerTable. Then, the server needs to sync the updated PlayerTable across the clients so that clients can use the table as well. Considering each client has an up-to-date version of the PlayerTable, player data is easily and efficiently accessible using this table without the need of Find functions and such. For example, if a client knows just the unique ID of a player, he can easily retrieve the related game object and name of that player from the PlayerTable.
This approach can be implemented with SyncVars [1] and ClientRPCs [2].
[1] When using SyncVars, I can set up the PlayerTable as a networked object and use SyncVars for the arrays used in this Table. When updated on the server, the table is automatically updated on the clients. This solution seems to be pretty straight-forward and requires little code.
[2] When using ClientRPCs, I would send a ClientRpc when the PlayerTable is updated on the server and pass the required information as parameters. I will need a mechanism to find the appropriate player objects on the clients of course.
Do you know arguments in favor for one or the other of these two alternative approaches? Are there some significant general rules of thumb when to use SyncVars and when to use ClientRPCs?
SyncLists
SyncLists are like SyncVars but they are lists of values instead of individual values. SyncList contents are included in initial state updates with SyncVar state. SyncLists do not require the SyncVar attributes, they are specific classes. There are built-in SyncList types for basic types:
SyncListString
SyncListFloat
SyncListInt
SyncListUInt
SyncListBool
There is also SyncListStruct which can be used for lists of user-defined structs. The struct used SyncListStruct derived class can contain members of basic types, arrays, and common Unity types. They cannot contain complex classes or generic containers.
SyncLists have a SyncListChanged delegate named Callback that allows clients to be notified when the contents of the list change. This delegate is called with the type of operation that occurred, and th eindex of the item that the operation was for.
public class MyScript : NetworkBehaviour
{
public struct Buf
{
public int id;
public string name;
public float timer;
};
public class TestBufs : SyncListStruct<Buf> {}
TestBufs m_bufs = new TestBufs();
void BufChanged(Operation op, int itemIndex)
{
Debug.Log("buf changed:" + op);
}
void Start()
{
m_bufs.Callback = BufChanged;
}
}
Not sure if a good approach or not but I accomplished a similar task by having Player objects add themselves to a local player list on Awake() and remove themselves from the local list OnNetworkDestroy(). This avoids having to sync any data across the network.
Thanks for sharing your approach noise256. I guess a crucial aspect here is a deterministic allocation of IDs so that it is ensured that all players have the same IDs across all clients. I will look into this and check if it might work for me as well. However, I think I would need to transfer at least some data across the network, like player names.
Hi seanr,
I know this topic is slightly dated. But it is only 5 months ago and that code now does not work at all.
I am actually getting very frustrated with the UNET system as things that should work don’t, the documentation is lacking and it isn’t as “simple” as it is made out to be. I know how I would have done it in the old system but now I struggle to move forward.
Upshot of it all the error I am getting is one that Operation namespace isn’t available so I create my own custom Operation enum and then I get errors about No overload for BufChanged matches the delegate.
Is there any suggestions you can provide or more up to date documentation that you can link?
I think I solved this one for myself in the end. Synclist are only one way from the server to client. The documentation does state this and I overlooked it.
How I got my desired functionality in the end was to replicate the structure of this post on Reddit (Reddit - Dive into anything)
I created my own message class to handle the struct data and transmit it back to the server when the client makes a change and all seems to be working. If anyone has better suggestion please let me know.