Tournament Checkers
Client
The client allows the user to chat or play checkers with anyone else connected to the server. Users also have the option of watching games in progress. The game and player lists and the checkers windows are all conveniently packaged in a Swing GUI.
A new client starts up in a passive state. Its entry is announced (by GameNet) to the rest of the clients, but it cannot yet interact with anyone. The server responds to this event by sending the current state, which consists of a game list and a player list. The client then sends his nickname to the server, and the server announces his entry, placing him in active state. Since nicknames should be unique (in order to avoid confusion), the server appends a number to any duplicate nicknames.
In order to use GameNet’s failover support, the client must be able to handle player exits without communicating with the server. Clean exits and dropouts are both treated in the same way. GameNet reports a player exit event, and everyone, including the server, updates the game and player lists independently. The client must also be able to package its local state to send it to the new server. For each game that it’s a part of, it sends a copy of the game board, the unique game ID, the current turn, and the players involved. The client’s own player info is also sent, since the user may not always be playing a game.
During a failover, the client displays a message to the user in the chat window that a failover is occurring. At this time, inputs are automatically queued up by Swing, so they are correctly sent to the new server as soon as the failover completes. The client then re-transmits all observe game requests. The new server does not know what games each individual client is watching, since only the previous server had the list of observers for each game.
Server
The server’s main purpose is to act as a central authority for all of the checkers games in progress, to keep the state of all games so that players can "observe" them, and to handle the joining of new clients. Although the clients check the validity of moves locally, the server verifies the legality of moves. A valid move is not necessarily a legal move. Available jumps must be taken before any normal moves. Also, jump sequences must be taken to completion. By having the server be the final authority on when a move is actually executed, it becomes much harder for the clients to cheat by modifying an individual client. The server also decides when a game is won or lost and notifies all of the clients. The clients do not do any win condition checks of their own. With the exception of chat messages, all communication goes through the server.
During a failover, an empty server may be asked to join an existing game and take over server duties. It receives a start failover event from the GameNet API. It then clears it’s current state and waits for an event from the GameNet API to receive a list of all the clients that are in the game and a packaging of their corresponding states. The server is then responsible for reconstructing the game state. First it adds all of the clients to its player pool. For each client’s state, it goes through the list of games that the client is playing and adds them to the game pool. If the game already exists in the game pool (because it was added when processing that client’s partner), then the server verifies that both clients have the same "view" of the game. If this is not the case, then one of the clients was attempting to cheat, and the server queues up a message to cancel the game. This provides some protection against cheating, since if either client modifies his game board for a given game when packaging the state, then the server should detect it.
The Protocol
The client/server protocol attempts to be as asynchronous as possible, since the client may be processing many games at the same time and a blocking style protocol would bring this to a halt. Challenges are sent to the server, which forwards them to the recipient. The challenger’s client is then free to process other events. When the challenge is accepted, the server announces a new game message, and a new game is started. If the challenge is rejected, then the challenger alone is notified. Game play works in a similar fashion. A move request is sent to the server along with the game ID. The server checks the move, and then sends a move update to the two players and any observers. If a move is rejected, only the player who requested the move is notified of the rejection.