FileDocCategorySizeDatePackage
MudClient.javaAPI DocExample21334Sat Jan 24 10:44:42 GMT 2004je3.rmi

MudClient

public class MudClient extends Object
This class is a client program for the MUD. The main() method sets up a connection to a RemoteMudServer, gets the initial RemoteMudPlace object, and creates a MudPerson object to represent the user in the MUD. Then it calls runMud() to put the person in the place, begins processing user commands. The getLine() and getMultiLine() methods are convenience methods used throughout to get input from the user.

Fields Summary
static BufferedReader
in
This static input stream reads lines from the console
static final String
help
This is the usage string that explains the available commands
Constructors Summary
Methods Summary
public static java.lang.StringgetLine(java.lang.String prompt)
A convenience method for prompting the user and getting a line of input. It guarantees that the line is not empty and strips off whitespace at the beginning and end of the line.

    
                                              
         
        String line = null;
        do {                      // Loop until a non-empty line is entered
            try {
                System.out.print(prompt);             // Display prompt
                System.out.flush();                   // Display it right away
                line = in.readLine();                 // Get a line of input
                if (line != null) line = line.trim(); // Strip off whitespace
            } catch (Exception e) {}                // Ignore any errors
        } while((line == null) || (line.length() == 0));
        return line;
    
public static java.lang.StringgetMultiLine(java.lang.String prompt)
A convenience method for getting multi-line input from the user. It prompts for the input, displays instructions, and guarantees that the input is not empty. It also allows the user to enter the name of a file from which text will be read.

        String text = "";
        for(;;) {  // We'll break out of this loop when we get non-empty input
            try {
                BufferedReader br = in;       // The stream to read from 
                System.out.println(prompt);   // Display the prompt
                // Display some instructions
                System.out.println("You can enter multiple lines.  " + 
				   "End with a '.' on a line by itself.\n" +
				   "Or enter a '<<' followed by a filename");
                // Make the prompt and instructions appear now.
                System.out.flush();
                // Read lines
                String line;
                while((line = br.readLine()) != null) {    // Until EOF
                    if (line.equals(".")) break;  // Or until a dot by itself
                    // Or, if a file is specified, start reading from it 
                    // instead of from the console.
                    if (line.trim().startsWith("<<")) {      
                        String filename = line.trim().substring(2).trim();
                        br = new BufferedReader(new FileReader(filename));
                        continue;  // Don't count the << as part of the input
                    }
		    // Add the line to the collected input
                    else text += line + "\n";  
                }
                // If we got at least one line, return it.  Otherwise, chastise
                // the user and go back to the prompt and the instructions.
                if (text.length() > 0) return text;
                else System.out.println("Please enter at least one line.");
            }
            // If there were errors, for example an IO error reading a file,
            // display the error and loop again, displaying prompt and
            // instructions
            catch(Exception e) { System.out.println(e); }
        }
    
public static voidlook(RemoteMudPlace p)
This convenience method is used in several places in the runMud() method above. It displays the name and description of the current place (including the name of the mud the place is in), and also displays the list of things, people, and exits in the current place.

        String mudname = p.getServer().getMudName(); // Mud name
        String placename = p.getPlaceName();         // Place name
        String description = p.getDescription();     // Place description
        Vector things = p.getThings();               // List of things here
        Vector names = p.getNames();                 // List of people here
        Vector exits = p.getExits();                 // List of exits from here

        // Print it all out
        System.out.println("You are in: " + placename +
			   " of the Mud: " + mudname);
        System.out.println(description);
        System.out.print("Things here: ");
        for(int i = 0; i < things.size(); i++) {      // Display list of things
            if (i > 0) System.out.print(", ");
            System.out.print(things.elementAt(i));
        }
        System.out.print("\nPeople here: ");
        for(int i = 0; i < names.size(); i++) {       // Display list of people
            if (i > 0) System.out.print(", ");
            System.out.print(names.elementAt(i));
        }
        System.out.print("\nExits are: ");
        for(int i = 0; i < exits.size(); i++) {       // Display list of exits
            if (i > 0) System.out.print(", ");
            System.out.print(exits.elementAt(i));
        }
        System.out.println();                         // Blank line
        System.out.flush();                           // Make it appear now!
    
public static voidmain(java.lang.String[] args)
The main program. It expects two or three arguments: 0) the name of the host on which the mud server is running 1) the name of the MUD on that host 2) the name of a place within that MUD to start at (optional). It uses the Naming.lookup() method to obtain a RemoteMudServer object for the named MUD on the specified host. Then it uses the getEntrance() or getNamedPlace() method of RemoteMudServer to obtain the starting RemoteMudPlace object. It prompts the user for a their name and description, and creates a MudPerson object. Finally, it passes the person and the place to runMud() to begin interaction with the MUD.

        try {
            String hostname = args[0]; // Each MUD is uniquely identified by a 
            String mudname = args[1];  //   host and a MUD name.
            String placename = null;   // Each place in a MUD has a unique name
            if (args.length > 2) placename = args[2];
	    
            // Look up the RemoteMudServer object for the named MUD using
            // the default registry on the specified host.  Note the use of
            // the Mud.mudPrefix constant to help prevent naming conflicts
            // in the registry.
            RemoteMudServer server = 
                (RemoteMudServer)Naming.lookup("rmi://" + hostname + "/" +
					       Mud.mudPrefix + mudname);

            // If the user did not specify a place in the mud, use
            // getEntrance() to get the initial place.  Otherwise, call
            // getNamedPlace() to find the initial place.
            RemoteMudPlace location = null;
            if (placename == null) location = server.getEntrance();
            else location = (RemoteMudPlace) server.getNamedPlace(placename);
	    
            // Greet the user and ask for their name and description.
            // This relies on getLine() and getMultiLine() defined below.
            System.out.println("Welcome to " + mudname);
            String name = getLine("Enter your name: ");
            String description = getMultiLine("Please describe what " +
					  "people see when they look at you:");

            // Define an output stream that the MudPerson object will use to
            // display messages sent to it to the user.  We'll use the console.
            PrintWriter myout = new PrintWriter(System.out);
	    
            // Create a MudPerson object to represent the user in the MUD.
            // Use the specified name and description, and the output stream.
            MudPerson me = new MudPerson(name, description, myout);
	    
            // Lower this thread's priority one notch so that broadcast
            // messages can appear even when we're blocking for I/O.  This is
            // necessary on the Linux platform, but may not be necessary on all
            // platforms.
            int pri = Thread.currentThread().getPriority();
            Thread.currentThread().setPriority(pri-1);
	    
            // Finally, put the MudPerson into the RemoteMudPlace, and start
            // prompting the user for commands.
            runMud(location, me);
        }
        // If anything goes wrong, print a message and exit.
        catch (Exception e) {
            System.out.println(e);
            System.out.println("Usage: java MudClient <host> <mud> [<place>]");
            System.exit(1);
        }
    
public static voidrunMud(RemoteMudPlace entrance, MudPerson me)
This method is the main loop of the MudClient. It places the person into the place (using the enter() method of RemoteMudPlace). Then it calls the look() method to describe the place to the user, and enters a command loop to prompt the user for a command and process the command

        RemoteMudPlace location = entrance;  // The current place
        String myname = me.getName();        // The person's name
        String placename = null;             // The name of the current place
        String mudname = null;             // The name of the mud of that place

        try { 
            // Enter the MUD
            location.enter(me, myname, myname + " has entered the MUD."); 
            // Figure out where we are (for the prompt)
            mudname = location.getServer().getMudName();
            placename = location.getPlaceName();
            // Describe the place to the user
            look(location);
        }
        catch (Exception e) {
            System.out.println(e);
            System.exit(1);
        }
	
        // Now that we've entered the MUD, begin a command loop to process
        // the user's commands.  Note that there is a huge block of catch
        // statements at the bottom of the loop to handle all the things that
        // could go wrong each time through the loop.
        for(;;) {  // Loop until the user types "quit"
            try {    // Catch any exceptions that occur in the loop
                // Pause just a bit before printing the prompt, to give output
                // generated indirectly by the last command a chance to appear.
                try { Thread.sleep(200); } catch (InterruptedException e) {}

                // Display a prompt, and get the user's input
                String line = getLine(mudname + '." + placename + "> ");
		
                // Break the input into a command and an argument that consists
                // of the rest of the line.  Convert the command to lowercase.
                String cmd, arg;
                int i = line.indexOf(' ");
                if (i == -1) { cmd = line; arg = null; }
                else {
                    cmd = line.substring(0, i).toLowerCase();
                    arg = line.substring(i+1);
                }
                if (arg == null) arg = "";
		
                // Now go process the command.  What follows is a huge repeated
                // if/else statement covering each of the commands supported by
                // this client.  Many of these commands simply invoke one of
                // the remote methods of the current RemoteMudPlace object.
                // Some have to do a bit of additional processing.

                // LOOK: Describe the place and its things, people, and exits
                if (cmd.equals("look")) look(location);
                // EXAMINE: Describe a named thing
                else if (cmd.equals("examine")) 
                    System.out.println(location.examineThing(arg));
                // DESCRIBE: Describe a named person
                else if (cmd.equals("describe")) {
                    try { 
                        RemoteMudPerson p = location.getPerson(arg);
                        System.out.println(p.getDescription()); 
                    }
                    catch(RemoteException e) {
                        System.out.println(arg + " is having technical " +
					   "difficulties. No description " +
					   "is available.");
                    }
                }
                // GO: Go in a named direction
                else if (cmd.equals("go")) {
                    location = location.go(me, arg);
                    mudname = location.getServer().getMudName();
                    placename = location.getPlaceName();
                    look(location);
                }
                // SAY: Say something to everyone 
                else if (cmd.equals("say")) location.speak(me, arg);
                // DO: Do something that will be described to everyone
                else if (cmd.equals("do")) location.act(me, arg);
                // TALK: Say something to one named person
                else if (cmd.equals("talk")) {
                    try {
                        RemoteMudPerson p = location.getPerson(arg);
                        String msg = getLine("What do you want to say?: ");
                        p.tell(myname + " says \"" + msg + "\"");
                    }
                    catch (RemoteException e) {
                        System.out.println(arg + " is having technical " +
			   	         "difficulties. Can't talk to them.");
                    }
                }
                // CHANGE: Change my own description 
                else if (cmd.equals("change"))
                    me.setDescription(
			    getMultiLine("Describe yourself for others: "));
                // CREATE: Create a new thing in this place
                else if (cmd.equals("create")) {
                    if (arg.length() == 0)
                        throw new IllegalArgumentException("name expected");
                    String desc = getMultiLine("Please describe the " +
					       arg + ": ");
                    location.createThing(me, arg, desc);
                }
                // DESTROY: Destroy a named thing
                else if (cmd.equals("destroy")) location.destroyThing(me, arg);
                // OPEN: Create a new place and connect this place to it
                // through the exit specified in the argument.
                else if (cmd.equals("open")) {
                    if (arg.length() == 0) 
                      throw new IllegalArgumentException("direction expected");
                    String name = getLine("What is the name of place there?: ");
                    String back = getLine("What is the direction from " + 
					  "there back to here?: ");
                    String desc = getMultiLine("Please describe " +
					       name + ":");
                    location.createPlace(me, arg, back, name, desc);
                }
                // CLOSE: Close a named exit.  Note: only closes an exit
                // uni-directionally, and does not destroy a place.
                else if (cmd.equals("close")) {
                    if (arg.length() == 0) 
                      throw new IllegalArgumentException("direction expected");
                    location.close(me, arg);
                }
                // LINK: Create a new exit that connects to an existing place
                // that may be in another MUD running on another host
                else if (cmd.equals("link")) {
                    if (arg.length() == 0) 
                      throw new IllegalArgumentException("direction expected");
                    String host = getLine("What host are you linking to?: ");
                    String mud =
			getLine("What is the name of the MUD on that host?: ");
                    String place =
			getLine("What is the place name in that MUD?: ");
                    location.linkTo(me, arg, host, mud, place);
                    System.out.println("Don't forget to make a link from " +
				       "there back to here!");
                }
                // DUMP: Save the state of this MUD into the named file,
                // if the password is correct
                else if (cmd.equals("dump")) {
                    if (arg.length() == 0) 
                       throw new IllegalArgumentException("filename expected");
                    String password = getLine("Password: ");
                    location.getServer().dump(password, arg);
                }
                // QUIT: Quit the game
                else if (cmd.equals("quit")) {
                    try { location.exit(me, myname + " has quit."); } 
                    catch (Exception e) {}
                    System.out.println("Bye.");
                    System.out.flush();
                    System.exit(0);
                }
                // HELP: Print out a big help message
                else if (cmd.equals("help")) System.out.println(help);
                // Otherwise, this is an unrecognized command.
                else System.out.println("Unknown command.  Try 'help'.");
            }
            // Handle the many possible types of MudException
            catch (MudException e) {
                if (e instanceof NoSuchThing) 
                    System.out.println("There isn't any such thing here."); 
                else if (e instanceof NoSuchPerson) 
                   System.out.println("There isn't anyone by that name here.");
                else if (e instanceof NoSuchExit) 
                  System.out.println("There isn't an exit in that direction.");
                else if (e instanceof NoSuchPlace) 
                    System.out.println("There isn't any such place."); 
                else if (e instanceof ExitAlreadyExists)
                    System.out.println("There is already an exit " +
				       "in that direction.");
                else if (e instanceof PlaceAlreadyExists)
                    System.out.println("There is already a place " +
				       "with that name.");
                else if (e instanceof LinkFailed)
                    System.out.println("That exit is not functioning.");
                else if (e instanceof BadPassword) 
                    System.out.println("Invalid password."); 
                else if (e instanceof NotThere)      // Shouldn't happen
                    System.out.println("You can't do that when " +
				       "you're not there."); 
                else if (e instanceof AlreadyThere)  // Shouldn't happen
                    System.out.println("You can't go there; " +
				       "you're already there.");
            }
            // Handle RMI exceptions
            catch (RemoteException e) {
               System.out.println("The MUD is having technical difficulties.");
               System.out.println("Perhaps the server has crashed:");
               System.out.println(e);
            }
            // Handle everything else that could go wrong.
            catch (Exception e) {
                System.out.println("Syntax or other error:");
                System.out.println(e);
                System.out.println("Try using the 'help' command.");
            }
        }