However, other apps require some extra, custom server-side logic. This is particularly true for games, because the code being executed on the clients can't be trusted to follow the rules of the game! (There's always some wiseacre who will 'hack' his client to give himself an unfair advantage over the other players, if he can) Because of this, for our game, we'll need to create a specialized FoxRabbitCarrot server that knows the rules of our game, and ensures that the players only make legal moves. Because the MUSCLE server is designed to be customizable, we'll be able to implement this specialized server without modifying any of the MUSCLE code -- we'll do it entirely by subclassing several of the C++ classes that make up a standard MUSCLE server. We'll call our customized server "frcd" (short for "Fox Rabbit Carrot Daemon").
In order to customize the MUSCLE server, we need to understand some of the MUSCLE server's parts and what they do. So, briefly, here is a description of some of the more important C++ classes that together form the guts of a MUSCLE server:
This class represents a single connection from the server to a client. The server maintains a list of StorageReflectSession objects: whenever a new client connects to the server, a StorageReflectSession object is created to represent that client's state; and whenever the TCP connection is broken, the StorageReflectSession object associated with that connection is deleted. It is the StorageReflectSession class that implements most of the server-side database and subscription functionality.
For our app, we want to reuse some of the default StorageReflectSession logic, but also customize it a bit, so we will create our own subclass of StorageReflectSession, called FRCPlayerSession, and use that instead of the vanilla StorageReflectSession class. So in our server, every client who logs in will have an FRCPlayerSession object that will represent him.
This is the Big Class that holds everything. The ReflectServer class represents an entire server, and contains the event loop that makes the server run. In a typical MUSCLE server program, a single ReflectServer object is created and set up, and then the ReflectServer's ServerProcessLoop() method is called. ServerProcessLoop() will typically never return unless/until the server has decided for some reason that it wants to quit running. Our app will subclass the ReflectServer class (with our own FRCServer class), but doing so is largely a place-holder for future growth -- almost all the customization we need to do can be done by calling methods on the basic ReflectServer class.
In our FoxRabbitCarrot server, we'd like to store important information (like the positions of the pieces on game board) in the server-side database, so that they are easily available to all clients. But this raises a problem: where in the server-side database should we put this information? If we place the game-state nodes underneath the session node of a player's session, they will be deleted when the player disconnects from the server. And there is no 'central' area in the database to speak of (except for the root of the tree, and we aren't allowed to put our own nodes there). The solution to this problem is simple enough, however: we'll create a session whose sole purpose is to maintain and administer the state of the game. Unlike the other sessions, this session will not have an associated TCP connection: it will exist as an exclusively a server-side entity. Since the logic necessary to maintain the game board is different from that needed to represent a player, we will provide a separate StorageReflectSession subclass for this session: the FRCGameStateSession. We'll create a single FRCGameStateSession object when the server starts up, and this object will stick around the entire time.
Here is a diagram showing how the internal state of the FRCServer might look if you could put it under an X-Ray while two people are logged in to the server:
- "Foxes, Rabbits, and Carrots"
- "The Game and How to Play it"
- "A Brief Review of the MUSCLE Networking Layer"
- "muscled, The basic MUSCLE server"
- "Customizing the MUSCLE server"
- "How to Set up the Custom Server Logic"
- "The FRCPlayerSession Class"
- "The FRCGameStateSession class"
- "Overview of the FRC server"
- "The FoxRabbitCarrot Client Program"
- "How the Client Handles Database Update Messages"
- "MUSCLE gaming Performance Issues"