Individual NetworkVariables vs serializable struct

What is the overhead of many NetworkVariable?
Do they constantly synchronize across the network? or only when they change?
When a player joins, do they get synchronized? or does the player need to wait for the variable to change before it’s synchronized?

I have a list of game settings that you configure in the lobby, like

internal sealed class GameSettings : NetworkBehaviour
{
    public GameTypes GameType;
    public bool IsPrivate;
    public FixedString128Bytes Name;
    public FixedString128Bytes PasswordHash;
    public int CurrentPlayerCount;
    public int MaxPlayerCount;
    public int TeamCount;
    public bool RequiresPassword;
    public bool IsTimed;
    public int MatchDurationMinutes;
    public bool SpawnNeutralTowers;
    public bool FriendlyFire;
    public bool ExtremeDamageMultiplier;
    public bool InfiniteVehicles;
    public int MapIndex;
    public int MaxPoints;
}

Wondering whether to store this in one struct OR to have a NetworkBehaviour that contains each of these as a NetworkVariable.

If they’re all in one serializable struct, it might get nasty… changing a simple boolean toggle like ‘friendly fire’ will probably send the whole object across the network.

What is the recommended way to share variables across the network?

I also need to consider some kind of Dictionary<ulong, int> that has [client Id] and [vehicle count]. Not sure how I am going to synchronize that. it doesnt look like there’s network dictionaries. can you have something like Dictionary<ulong, NetworkVariable> ?

They sync only when changed. New clients get all the netvar states right away. But all of it at once, which could be many kilobytes quickly.

You first have to ask yourself: does this need to be synchronized?
If the host toggles friendly fire then clients shouldn‘t care. At best they need to display that setting in their Lobby GUI momentarily. I would hide those settings to clients, or have them click a game settings panel which requests this info once via rpc.
But for convenience in the Lobby only you could make those netvars or a INetworkSerializable struct. It really boils down to how frequently any of these values change, so you may want to split those into info (eg name and password should already be set and remain unchangeable) and settings.

And consider your data types. Are you going to have billions of players and teams? Make those byte, not int. And put all the bool (also 4 bytes each) into a single BitArray32 (see Collections package). Suddenly you‘re only sending one tenth of the original bytes to get the same state across. :wink:

Dictionaries: typically you just track change over time. A player gets a new vehicle? Send an RPC so every client and server can +1 this in the dictionary. Late joining clients? That‘s more complicated but hey, a dictionary is the same as two lists (keys and values). Just keep them in sync.

That’s some great points. I haven’t gotten around to optimizing the properties (using the most optimal value types to keep the network data small) - but i will. Or, I should probably do it “as i go”. Right now I’m just in deep waters exploring how to use NGO haha.

I think these initial game settings only need to be transmitted once, at the start of the game.
So yeah maybe this should just be one serializable struct which is transmitted at the start of a game OR if a client joins. Thanks for all of your constant help CodeSmile. How long did it take you to get a good grasp on unity/netcode?

It’s an ongoing process. :smile:

I did about a month worth of prototyping with v1.0/1.1 about a year ago. It was most confusing to understand the roles at first: client, host, server, owner. And how those affect how the code is supposed to work and be structured.

This February I got back into it and it was a breeze, the most time I spent debugging nasty MPPM issues due to the fact that virtual players also communicate over the network, thus responses may be delayed. I still have this nagging issue where one player on shutdown wants to load an editor scene but it’s technically still in playmode. Probably a MPPM bug but I have yet to find a way to reliably reproduce or work around this.

It did bring about an important point: every bit of progress you make towards something that runs over the network needs to be tested thoroughly in all variations (server, client, host) and repeatedly (host, then join and vice versa).

I also separate a lot of the code so each script remains small and dedicated. Down to “change weapon” and “fire weapon” being separate components. It helps to ensure that one thing that works won’t be affected when you work on that other thing, even if closely related.

Still, surprises happen. Scripts and prefabs need to be carefully maintained. Any time something unexpected happens, I investigate. Because it may point to some deeper issue that could affect anything. The more reliable everything is the easier it gets going forward. I spent the last six months mainly setting up the project structure. Gameplay wise I can run around, shoot, detect hits. But structurally I can run all roles in any combination, I can join splitscreen players for every client, I can test with MPPM, simulate and monitor. Also the whole first-person (with shadows) vs third-person split personality issues, compounded by splitscreen, and the usual FPS layering like avoiding the weapon clipping into walls and firing at the crosshair.

Six weeks worth of building a foundation, now I’m looking forward to implementing more gameplay features for MultiPal.

1 Like