By Hugo Scott-Slade, Technical Director
Cone Wars has a lot of player customisation ranging between your weapon and truck to the purely cosmetic. Customisation is an important part of any online multiplayer game and getting all players setup correctly is fundamental. When you join a game lobby you need to see who you’re up against so you can plan for the game ahead and see how your truck stacks up against theirs.
In this post I will cover how to setup an online multiplayer game with a lobby based on Unity’s Networking (UNET) and the high level networking API (HLAPI). The full source code for the HLAPI is available on bitbucket and I highly encourage anyone using UNET to download it and poke around because the code that comes by default is compiled inside a DLL and inaccessible.
Before we jump in I just want to clarify some commonplace terms so we are all on the same page.
- Player – This means the local client. When you’re playing online this is you.
- Remote Player – This is all other clients. Online this would be anyone you’re playing with – allies, enemies and spectators.
- Players – All clients – you and everyone else.
- Server – This handles the management of the data and the game. You send your data to the server and the server sends you data for all other players.
- Host – A host is both a server and a player. Someone who has set up a game and is also participating.
These are our requirements for setting up a lobby and ensuring that each player’s customisation is correct for everyone playing in that game.
- Players send their data to the server for validation and storage
- Players have the data for each player in the Lobby.
- Players can request & receive data for any player from server.
- Each player only sends their data when they join.
- Players are setup in game correctly with their data.
We call the data describing each player a
PlayerDef. Here is a very basic version of what we want to send over the network for each player know how to display. In the full game this is much larger but the principle is identical.
Unity has an out of the box implementation of a lobby called
NetworkLobbyManager. This extends their base
NetworkManager and adds all the functionality needed for managing connections / disconnections and change in ready state. For the purposes of getting started with a lobby in UNET, this is perfect. When using
NetworkLobbyManager each player has two forms they take: either be a lobby player or a game player. Unity gives a base script for the lobby player in the form of
NetworkLobbyPlayer and we will use this as the base for our own.
Syncing the data
UNET has an attribute called a
SyncVar you can give your variables to make them synced over the network. Whatever values are set by the server are sent to each client when they first create that object in their game and then periodically after that. For us this would be ideal, we should send the
PlayerDef to the server and it would distribute to any already connected players as well as players that are yet to join.
However they only work on certain types of variables and despite what is listed in the manual I could not get them to work on user-defined structs like
PlayerDef so I opted for a slightly different solution.
I use a
SyncVar on each player that keeps track of whether or not the server has the full
PlayerDef for that player. When you join the lobby you send your
PlayerDef to the server and it sets a value for all other players that it has a copy of your data. The other players can then request the data from the server.
Newly joining players get an instance of your local player with a little flag indicating that the server has the data for this player, whereas existing players get an update to their instance of your local player saying the server now has your data. This update can be listened for easily by using an attribute on
SyncVars called a hook. This hook is a function that will run on a client anytime the value is changed on the server.
Now players know if the server has the data they still need to ask the server for it. Additionally the server needs to be able to respond to this request and send the data. I handle this by using two
NetworkMessage. There is one message which handles the request and one for sending the data for a specific player.
You don’t need to specify what the message is used for, this is handled when you register your message handler on either the client or the server. In this instance I actually use the
PlayerDefMessage to send the local player’s data to the server as well as sending a player’s data from the server. The
PlayerRequestPlayerDataMessage takes who is asking for the data as well as whom the request is about to make ensure the data is sent to the correct player.
Here is a copy of the key parts of our final lobby script. You will notice an addition of a request cache. This is added because you don’t know your own
netId until your local player is created in your game. It is not guaranteed that your game will create a remote player before it creates your player so you have to keep track of what players you need data for.
This post covers a basic setup for handling the transfer of data for all players and is the first step towards getting your game working. In the next post I will cover getting the data from the lobby player to the game player, correcting Unity’s
OnLevelWasLoaded misfiring between levels as well ensuring the game and players are fully setup for each player before starting the game.