The following files have been attached to this tutorial:
This tutorial is licensed under CC BY 4.0. Please refer to the license text if you wish to reuse, share or remix the content contained within this tutorial.
Part 3 - Creating a multiplayer tic-tac-toe game, utilizing a lobby server.
This is a continuation of my tic-tac-toe series. We're making a jump here from beginner to advanced, so there's going to be much less hand-holding, and some complex communication mechanisms, although at is base, there is very little communication needed to make a two-player board game, so hopefully it won't be so bad. Please review all of the official multiplayer documentation and tutorials first! I'm not going to re-explain all of the multiplayer plugin details, just the implementation of a lobby/alternating-player game.
C2's multiplayer plugin allows fairly simple connections between two people to play a game, but doesn't deal with people choosing who they play against. This is where the concept of a lobby comes in. Each player starts their game, and rather than immediately playing some random person, they enter a lobby first, where they can see other players and choose to play against someone chosen specifically. I'm not promoting a very complicated mechanism, just one at its simplest. There's lots of ways to expand on how a nice lobby would work - these are just the basics.
As people join the lobby, each peer is automatically updated via Multiplayer: On peer connect, and the peer adds the new player to their own list of players. Once a player picks someone else to play against, they send a message to the host (lobby server) which forwards a message to the other player telling them the details of how to connect to the first player. Both players actually disconnect from the lobby at this point, which removes them from all lists of available players, and they set up their own private connection to each other so that they can play their game. The lobby is out of the loop at this point.
The lobby is a dedicated server/host that must be running at all times. There can only be one, and steps must be taken in the server code and the peer code to enforce this. The lobby itself is just a list showing all of the people who are logged in. Even that isn't necessary, but is convenient for testing. The GUI is just a status field (TextStatus) and a list (PeerList).
The lobby code follows the standard connect/log-in/join-room model of all multiplayer implementations. The only main difference is that when On signalling joined room is triggered, we check that we are the host, and that MyAlias is exactly the name we passed in to Log in with alias. This ensures that there is one, and only one, active lobby. If a second was run, it would have a different alias, so we need to ignore that instance and shut it down.
Next we deal with the lobby leaving the room. Here we just wait 3 second, and if we are still connected, just join the lobby room again. Otherwise, we disconnect from the signalling server.
When we do get a disconnect triggered, we clear our list, wait 5 seconds, and start the connect process all over again.
On an error we log the error. Frankly, I'm not sure what else to do here at the moment.
Now we start dealing with peer events. When a peer connects, we just add them to our GUI list so that we can see what is going on.
When a peer disconnects, we search for that peer in our GUI list and remove it.
Next we just log any message that comes in.
Finally, we get to the meat of the lobby, which isn't all that much. When we get a StartGameWithClient message, the Message text will contain just the PeerID of the X player, an underscore, and the PeerID of the O player. Event 21 just decodes this into its separate parts. Next we see if the peer sending the message has the same ID as the X player, and if so, send the GameRequest message to the O player. Otherwise, the sender must be O, so we need to send the message to the X player. We send the same message we received so that the other player clearly knows who is X and who is O.
The remaining events are just some testing code to test disconnects and recovery.