MudClientpublic 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 | inThis static input stream reads lines from the console |
Methods Summary |
---|
public static java.lang.String | getLine(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.String | getMultiLine(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 << line as part of the input
}
else text += line + "\n"; // Add the line to the collected input
}
// 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 void | look(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 void | main(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 within a MUD has a unique name
if (args.length > 2) placename = args[2];
// Set the RMI security manager so that untrusted stub objects loaded
// over the network can't cause havoc.
System.setSecurityManager(new RMISecurityManager());
// 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(new OutputStreamWriter(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 void | runMud(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")) {
String help =
"Commands are:\n" +
"look: Look around\n" +
"examine <thing>: examine the named thing in more detail\n" +
"describe <person>: describe the named person\n" +
"go <direction>: go in the named direction (i.e. a named exit)\n" +
"say <message>: say something to everyone\n" +
"do <message>: tell everyone that you are doing something\n" +
"talk <person>: talk to one person. Will prompt for message\n" +
"change: change how you are described. Will prompt for input\n" +
"create <thing>: create a new thing. Prompts for description \n" +
"destroy <thing>: destroy a thing.\n" +
"open <direction>: create an adjoining place. Prompts for input\n"+
"close <direction>: close an exit from this place.\n" +
"link <direction>: create an exit to an existing place,\n" +
" perhaps on another server. Will prompt for input.\n" +
"dump <filename>: save server state. Prompts for password\n" +
"quit: leave the Mud\n" +
"help: display this message";
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.");
}
}
|
|