06jul09 CmdrZin

Understanding DarkMud - Darkstar Communications

One of the major elements of the Darkstar system is the Server-Client Communications system.
Understanding its basic operation can take you a long way into understanding a game designed around Darkstar.
This discussion will look at communications after logon has been completed.

The figure below shows the key elements of the Darkstar Server-Client Communications setup.
Darkstar Comm Classes
Each message sending class has a matching message receiving class.

Client Side

Simple Communications

Per Lesson 1 of the Client Tutorial, a game needs to have (1a) a Class that implements SimpleClientListener and
then (1b) create a SimpleClient object and pass the Class to it. The Class will then received messages though its
receiveMessage() method and send messages through its object's send() method.
NOTE: The tutorial still show byte arrays being used, but the code uses ByteBuffers.

Channel Communications

Per Lesson 2 of the Client Tutorial, if a game is to use Channel based messages, then the Client is notified
through the joinedChannel() method of the Class that (2a) implemented SimpleClientListener. This method will (2b)
receive a ClientChannel object to be used for sending channel messages to the Server. The method returns
an object that (2c) implements ClientChannelListener. The ClientChannelListener has at least two methods:
receivedMessage() and leftChannel(). These two objects provide channel message support to the game.

DarkMud Communications - Client

The DarkMud MudClient class is set up to provide support for both simple and channel messages. It
implements SimpleClientListener (1a) to be able to receive simple messages and it (2a) implements
ClientChannelListener to receive channel messages. No law against that. Now it needs some way to send
messages. It (1b) makes a SimpleClient object simpleClient inside its doConnect() method. This will allow it to send
simple messages using simpleClient.send(). For channel messages, it allows two ways to handle them.
In joinedChannel(), it will (2c) return the MudClient for all channels except the MAP_CHANNEL. For this
it (2c) returns a new MapFrame object.
This allows the MapFrame to handle all map display related messages and the MudClient to handle the rest.
Apparently, the client never sends back channel messages to the server because the ClientChannel object (2b) is
not saved.

So, this is how it looks
    MudClient.receiveMessage(ByteBuffer) gets all non-channel messages
    MudClient.receiveMessage(ClientChannel, ByteBuffer) gets all channel messages other than MAP_CHANNEL type
    MapFrame.receiveMessage(ClientChannel, ByteBuffer) gets all channel messages of the MAP_CHANNEL type
    MudClient.simpleClient.send(ByteBuffer) is used to send non-channel messages. (see Client API docs)
    No ClientChannel object is retained. So no channel messages are sent out.
    NOTE: The "yell" command is sent to the Server as a simple message and then sent back on a channel.

Server Side

Simple Communications

Per Lesson 5 of the Server Tutorial, a game (3a) needs a Class that implements AppListener and is Serializable.
This Class has a method loggedIn() that the PDS Core calls when a Client logs in.
NOTE: The PDS Core knows to call this Class because it is set in the properties file. For DarkMud it's
The loggedIn() method should (3b) return an object that that implements ClientSessionListener and is Serializable. This
means a new class is needed with those properties. In the tutorial, they made a HelloUserSessionListener class. The
new object of this class takes the ClientSession session as a parameter and saves its ManagedReference since a
ManagedObject can not be saved directly. This class has a receivedMessage(ByteBuffer) method that will now get all
simple messages sent by the Client. Simple messages are sent out using the session.send(ByteBuffer) method. (see
Server API docs)
NOTE: To send a message, use the ManagedReference to get the session back, then use session.send(ByteBuffer).

Channel Communications

Per Lesson 6 of the Server Tutorial, to support channel messages, a game (4a) uses a ChannelManager. The Server (4b) creates
channels and (4c) assignes Users to them. The User (i.e. session) is added to the Channel by using the channel.join(session) method.
A User can be assigned to more than one channel. The game can manage its channels by either (4d) creating a reference and saving
the reference and/or by (4e) getting the reference by looking up the channel by name.
There are two ways to use the HelloChannelSessionListener. If, (4f) passed a null ChannelListener, the server will not process that
channel's messages. It just sends them along to all Clients on the channel. If passed a (4g) ChannelListener object, the server will call the
objects receivedMessage() method to intercept the message. To have the message continue on its way to the clients, the serve has
to call send(). (see examples in Server tutorial)

DarkMud Communications - Server

The DarkMud game uses (3a) the MudMain Class to set up a server.
NOTE: The SimpleServer class is only used to verify the development environment.
The MudMain.loggedIn() method returns (3b) MudUser object reference sessionRef to the PDS server core so it can keep this user
logged in and managed with the databease. The sessionRefs receivedMessage() method will be called whenever its Client sends a simple
non-channel message.
The game sets up one channel (BROADCAST) in initialize() and uses (4e) name look up (see loggedIn()) to use it to send out a messages
to all Clients. The MudUser class sets up a channel (CHAT) as a static process (so its only done once) to support the YELL command
and the Mapper class sets up a channel to support the map generation data transfer.
NOTE: Since the YELL channel was created with a (4f) null ChannelListener, the server never responds to anything entered with the yell
command. The yell message is just sent through to the other users.

Hopefully, this has provided some insight about the internal workings of the DarkMud game and client.