home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / enxle1f6 / src / games / battle / client / europaclient / europaclient.java < prev    next >
Encoding:
Java Source  |  1996-08-14  |  16.3 KB  |  755 lines

  1. /*
  2.  * @(#)EuropaClient.java
  3.  */
  4. package games.Battle.client.EuropaClient;
  5.  
  6. import java.applet.*;
  7. import java.awt.*;
  8. import java.net.*;
  9. import java.io.*;
  10.  
  11. import win.ClosableFrame.*;
  12. import games.Battle.client.ClientApplet.*;
  13. import games.Battle.shared.sys.*;
  14. import games.Battle.shared.comm.*;
  15.  
  16. /*
  17.  * CommandPanel processes methods generated by button
  18.  * presses from the buttons across the top of the Europa client
  19.  * window. The buttons are added outside of this class,
  20.  * we just handle the events here.
  21.  *
  22.  * @author Alex Nicolaou
  23.  * @author Jay Steele
  24.  */
  25. class CommandPanel extends Panel {
  26.  
  27.     /**
  28.      * The game client applet.
  29.      */
  30.     EuropaClient client;
  31.  
  32.     /**
  33.      * Construct a ComandPanel attached to the given EuropaClient applet.
  34.      * @param client the EuropaClientApplet
  35.      */
  36.     public CommandPanel(EuropaClient client) {
  37.         super();
  38.         this.client = client;
  39.     }
  40.  
  41.  
  42.     /**
  43.      * Process button presses.
  44.      */
  45.     public boolean handleEvent(Event e) {
  46.         if (e.arg != null) {
  47.             if (e.arg.equals("Quit")) {
  48.                 client.quit();
  49.             }
  50.             else if (e.arg.equals("Shutdown")) {
  51.                 client.shutdownServer();
  52.             }
  53.             else if (e.arg.equals("Change Info")) {
  54.                 client.changeInfo();
  55.             }
  56.             else if (e.arg.equals("Toggle Chat")) {
  57.                 client.toggleChatWindow();
  58.             }
  59.         }
  60.         return super.handleEvent(e);
  61.     }
  62. }
  63.  
  64. /**
  65.  * The Chat window for the Europa client. The Chat window consists
  66.  * of a large multiline read-only text field which scrolls previous
  67.  * messages upwards, and a small editable text field on the bottom
  68.  * which allows the use to edit a message and send the message
  69.  * to all of the other players by pressing the return key.
  70.  * @author Alex Nicolaou
  71.  * @author Jay Steele
  72.  */
  73. class ChatWindow extends Frame {
  74.  
  75.     /**
  76.      * The game client applet.
  77.      */
  78.     EuropaClient client;
  79.  
  80.     /**
  81.      * The scrollable readonly area for display messages.
  82.      */
  83.     TextArea chatscreen;
  84.  
  85.     /**
  86.      * The input field used to collect chat messaged from the user.
  87.      */
  88.     TextField input;
  89.  
  90.     /**
  91.      * The maximum number of allowed buffered characters in the
  92.      * scrollable chatscren.
  93.      */
  94.     static final int HISTORYLIMIT = 1024*8;
  95.  
  96.     /**
  97.      * Construct the chat window by adding the large read-only text area
  98.      * and a smaller editable text field on the bottom. We pass a 
  99.      * reference to the EuropaClient applet, who is responsible for
  100.      * actually sending the message to the server and receiving
  101.      * messages from the server.
  102.      * @param client the EuropaClient applet from which we send/rcv messages
  103.      */
  104.     ChatWindow(EuropaClient client) {
  105.         super("Chat Window");
  106.         this.client = client;
  107.  
  108.         chatscreen = new TextArea();
  109.         chatscreen.setEditable(false);
  110.  
  111.         add("Center", chatscreen);
  112.  
  113.         input = new TextField();
  114.         add("South", input);
  115.     }
  116.  
  117.  
  118.     /**
  119.      * Defines the minimum size of the frame.
  120.      */
  121.     public Dimension minimumSize() {
  122.         return new Dimension(200, 100);
  123.     }
  124.  
  125.  
  126.     /**
  127.      * Defines the preferred size of the frame.
  128.      */
  129.     public Dimension preferredSize() {
  130.         return new Dimension(700, 400);
  131.     }
  132.  
  133.  
  134.     /**
  135.      * Handle events in the chat window, primary the WINDOW_DESTROY
  136.      * event (which instructs the parent applet to simply toggle
  137.      * the chat window off), and a carriage return, which instructs
  138.      * the EuropaClientApplet to send the message contained in the
  139.      * text field to the server.
  140.      * @param e the event to process
  141.      */
  142.     public boolean handleEvent(Event e) {
  143.         if (e.id == Event.WINDOW_DESTROY) {
  144.             client.toggleChatWindow();
  145.         }
  146.         else if (e.id == Event.KEY_RELEASE) {
  147.             if ((char)e.key == '\n') {
  148.                 client.sendChat(input.getText());
  149.                 input.setText("");
  150.             }
  151.         }
  152.  
  153.         return super.handleEvent(e);
  154.     }
  155.  
  156.  
  157.     /**
  158.      * Adds a message to the read-only area of the chat window, scrolling
  159.      * all other messages up. If the size of the scrolled window buffer
  160.      * reaches the maximum HISTORYLIMIT, the amount of scrolled text
  161.      * is reduced by 1/2.
  162.      * @param msg the message to add to the chat window
  163.      */
  164.     public void chatMsg(String msg) {
  165.         chatscreen.appendText(msg + "\r\n");
  166.         int numchars = chatscreen.getText().length();
  167.         if (chatscreen.getText().length() > HISTORYLIMIT) {
  168.             chatscreen.replaceText("", 0, HISTORYLIMIT/2);
  169.         }
  170.     }
  171. }
  172.  
  173. /**
  174.  * EuropaClient is the main applet for the "lobby" of the Europa
  175.  * game. Sets up the game queue graphics, the who-list and the
  176.  * chat window. This applet also initiates conversations with
  177.  * the game server, logs users in, and spawns game board
  178.  * clients when the server instructs it that a game is about to
  179.  * begin.
  180.  * @author Alex Nicolaou
  181.  * @author Jay Steele
  182.  */
  183. public class EuropaClient extends Applet implements Runnable {
  184.  
  185.     /**
  186.      * The socket to the server.
  187.      */
  188.     Socket s = null;
  189.  
  190.     /**
  191.      * The output stream to the server.
  192.      */
  193.     OutputStream os = null;
  194.  
  195.     /**
  196.      * The input stream from the server.
  197.      */
  198.     InputStream is = null;
  199.  
  200.     /**
  201.      * The execution thread for this applet.
  202.      */
  203.     Thread appletThread = null;
  204.  
  205.     /**
  206.      * The client container frame for this applet.
  207.      */
  208.     Frame clientFrame = null;
  209.  
  210.     /**
  211.      * The game id, if a game is executing (-1 otherwise).
  212.      */
  213.     public int gameId = -1;
  214.  
  215.     /**
  216.      * The container for the row of buttons at the top of the window.
  217.      */
  218.     Panel buttonBar;
  219.  
  220.     /**
  221.      * The quit button.
  222.      */
  223.     Button quitButton;
  224.  
  225.     /**
  226.      * The change info button.
  227.      */
  228.     Button infoButton;
  229.  
  230.     /**
  231.      * The toggle chat window button.
  232.      */
  233.     Button chatButton;
  234.  
  235.     /**
  236.      * The shutdown server button. 
  237.      */
  238.     Button shutdownButton;
  239.  
  240.  
  241.     /**
  242.      * A component that displays the available games
  243.      */
  244.     QueuePanel gamePanel = null;
  245.  
  246.     /**
  247.      * The chat window component.
  248.      */
  249.     ChatWindow chatWindow = null;
  250.  
  251.     /**
  252.      * Construct an EuropaClient window, and set an internal reference
  253.      * to an encapsulating frame. 
  254.      * @param f the frame window
  255.      */
  256.     public EuropaClient(Frame f) {
  257.         clientFrame = f;
  258.     }
  259.  
  260.  
  261.     /**
  262.      * Construct a EuropaClient instance free from the bonds of a 
  263.      * frame window. 
  264.      */
  265.     public EuropaClient() {
  266.     }
  267.  
  268.     String host;
  269.     TextArea whoList;
  270.  
  271.     /**
  272.      * Performs a list of inititialization routines, including contacting
  273.      * the game server, and building all of the components which are
  274.      * inside the EuropaClient (including the various game queues and
  275.      * the who list)
  276.      */
  277.     public void init() {
  278.         appletThread = Thread.currentThread();
  279.  
  280.         URL url = getDocumentBase();
  281.  
  282.         host = url.getHost();
  283.  
  284.         if (host.equals("")) {
  285.             // we're running locally under the applet viewer; assume server
  286.             // is local.
  287.             host = "127.0.0.1";
  288.         }
  289.  
  290.         int port = 5000;
  291.  
  292.         try {
  293.             s = new Socket(host, port);
  294.         } catch (Exception e) {
  295.             Window err;
  296.             err = new ErrorWindow(this, "Could not connect to "+host+":"+port);
  297.             err.show();
  298.             suspend();
  299.             Common.exit(1);
  300.         }
  301.  
  302.         // bind an i/o stream
  303.         try {
  304.             os = s.getOutputStream();
  305.             is = s.getInputStream();
  306.         } catch ( Exception e ) {
  307.             Window err;
  308.             err = new ErrorWindow(this,"Connection to "+host+":"+port+" lost.");
  309.             err.show();
  310.             suspend();
  311.             Common.exit(1);
  312.         }
  313.  
  314.         // read server banner
  315.         InfoPacket banner = new InfoPacket();
  316.         try {
  317.             banner.readFrom(is);
  318.         }
  319.         catch (Exception e) {
  320.             Window err;
  321.             err = new ErrorWindow(this,"Connection to "+host+":"+port+" lost.");
  322.             err.show();
  323.             suspend();
  324.             Common.exit(1);
  325.         }
  326.  
  327.         if (clientFrame == null) {
  328.             clientFrame = new ClosableFrame("Europa");
  329.             getParent().remove(this);
  330.             clientFrame.add("Center", this);
  331.         }
  332.  
  333.         buttonBar = new CommandPanel(this);
  334.         buttonBar.setLayout(new FlowLayout(FlowLayout.LEFT, 2, 2));
  335.         buttonBar.setBackground(Color.lightGray);
  336.         quitButton = new Button("Quit");
  337.         infoButton = new Button("Change Info");
  338.         chatButton = new Button("Toggle Chat");
  339.         shutdownButton = new Button("Shutdown");
  340.         buttonBar.add(quitButton);
  341.         buttonBar.add(infoButton);
  342.         buttonBar.add(chatButton);
  343.  
  344.         whoList = new TextArea(30, 25);
  345.         whoList.setEditable(false);
  346.         whoList.setBackground(Color.black);
  347.         whoList.setForeground(Color.yellow);
  348.         whoList.setFont(new Font("Helvetica", Font.PLAIN, 12));
  349.         clientFrame.add("East", whoList);
  350.         clientFrame.add("North", buttonBar);
  351.         gamePanel = new QueuePanel(16, this);
  352.         clientFrame.add("Center", gamePanel);
  353.  
  354.         // load the media components
  355.         ClientImages.loadAll(this);
  356.         ClientSounds.loadAll(this);
  357.     }
  358.  
  359.     PlayerInfo id = null;
  360.  
  361.     /**
  362.      * Sends PlayerInfo information to the server so the server
  363.      * can save the info for future reference.
  364.      * @param r the PlayerInfo instance
  365.      * @see PlayerInfo
  366.      */
  367.     public void setPlayerInfo(PlayerInfo r) {
  368.         if (id == null) {
  369.             id = r;
  370.         }
  371.         else {
  372.             // send an update request
  373.             try {
  374.                 ShellCommand cmd = new ShellCommand(ShellCommand.UPDATEID, 0);
  375.                 cmd.writeTo(os);
  376.                 id.setPassword(r.getPassword());
  377.                 id.setName(r.getName());
  378.                 id.setMail(r.getMail());
  379.                 id.writeTo(os);
  380.             }
  381.             catch (Exception e) {
  382.                 Window err;
  383.                 err = new ErrorWindow(this,"Connection lost.");
  384.                 err.show();
  385.                 suspend();
  386.                 Common.exit(1);
  387.             }
  388.         }
  389.     }
  390.  
  391.  
  392.     /**
  393.      * Starts up the applet thread of execution. This includes:
  394.      * a) trying to log into the game, b) registering this
  395.      * player (based on their login id) with the server. If all is 
  396.      * successful, then the run() method is called to start the
  397.      * game, otherwise the applet execution ends.
  398.      */
  399.     public void start() {
  400.         appletThread = Thread.currentThread();
  401.  
  402.         // send a registration
  403.         InfoPacket loginResult = new InfoPacket();
  404.         int tries = 0;
  405.         do {
  406.             id = null;
  407.             LoginWindow login = new LoginWindow(this);
  408.             login.show();
  409.             suspend();
  410.  
  411.             if (id == null) {
  412.                 Window err;
  413.                 err = new ErrorWindow(this, "Login cancelled. Exiting.");
  414.                 err.show();
  415.                 suspend();
  416.                 Common.exit(0);
  417.             }
  418.  
  419.             try {
  420.                 id.writeTo(os);
  421.             } 
  422.             catch (Exception e) {
  423.                 Window err;
  424.                 err = new ErrorWindow(this,"Connection lost.");
  425.                 System.out.println(e.toString());
  426.                 e.printStackTrace();
  427.                 err.show();
  428.                 suspend();
  429.                 Common.exit(1);
  430.             }
  431.  
  432.             try {
  433.                 loginResult.readFrom(is);
  434.             }
  435.             catch (Exception e) {
  436.                 Window err;
  437.                 err = new ErrorWindow(this,"Connection lost.");
  438.                 System.out.println(e.toString());
  439.                 e.printStackTrace();
  440.                 err.show();
  441.                 suspend();
  442.                 Common.exit(1);
  443.             }
  444.  
  445.             if (loginResult.isFatal()) {
  446.                 Window err;
  447.                 err = new ErrorWindow(this, loginResult.toString());
  448.                 err.show();
  449.                 suspend();
  450.             }
  451.             tries++;
  452.         } while (loginResult.isFatal() && tries < 3);
  453.  
  454.         if (loginResult.isFatal()) {
  455.             Common.exit(0);
  456.         }
  457.  
  458.         // read in all the info on this user
  459.         try {
  460.             id.readFrom(is);
  461.         }
  462.         catch (Exception e) {
  463.             Window err;
  464.             err = new ErrorWindow(this,"Connection lost.");
  465.             System.out.println(e.toString());
  466.             e.printStackTrace();
  467.             err.show();
  468.             suspend();
  469.             Common.exit(1);
  470.         }
  471.  
  472.         if (id.isWizard())
  473.             buttonBar.add(shutdownButton);
  474.  
  475.         setLayout(new BorderLayout());
  476.  
  477.         clientFrame.setBackground(Color.orange);
  478.         clientFrame.pack();
  479.         clientFrame.show();
  480.  
  481.         run();
  482.     }
  483.  
  484.  
  485.     /**
  486.      * Overloaded stop method to do nothing.
  487.      */
  488.     public void stop() {
  489.     }
  490.  
  491.     /**
  492.      * Read all of the game information from the server, and use
  493.      * the information to properly update the contents of the game
  494.      * queue window. This method is also responsible for 
  495.      * recognizing when a game queue has been successfull filled
  496.      * and starting the game clients.
  497.      * @param numGames the number of games to read from the server
  498.      */
  499.     public void readGames(int numGames) throws java.io.IOException {
  500.         boolean getGoing = false;
  501.  
  502.         while (numGames-- > 0) {
  503.             GameInfo game = new GameInfo();
  504.             game.readFrom(is);
  505.  
  506.             gamePanel.setGameInfo(game);
  507.             if (gameId == game.getId() && game.isRunning()) {
  508.                 getGoing = true;
  509.             }
  510.         }
  511.  
  512.         //clientFrame.removeAll();
  513.         //clientFrame.add("Center", gamePanel);
  514.         //clientFrame.add("East", whoList);
  515.         //clientFrame.add("North", buttonBar);
  516.  
  517.         clientFrame.pack();
  518.  
  519.         if (getGoing) {
  520.             // time to actually start the game
  521.             ClientApplet client;
  522.             client = new ClientApplet(id, this, host, 5100+gameId);
  523.             Frame f = new ClientFrame("Europa Control", client);
  524.  
  525.             client.init();
  526.             f.add("Center", client);
  527.             f.pack();
  528.             f.show();
  529.  
  530.             client.start();
  531.             f.pack();
  532.  
  533.             // make sure we never start two clients for the same game
  534.             gameId = -1;
  535.         }
  536.     }
  537.  
  538.  
  539.     /**
  540.      * Read numplayers WhoInfo packets from the server and
  541.      * display them in the who list.
  542.      * @param numplayers the number of players to read
  543.      */
  544.     public void readWho(int numplayers) throws java.io.IOException {
  545.         whoList.setText("Handle\t\tRating\tName/Email\r\n");
  546.         while (numplayers-- > 0) {
  547.             WhoInfo p = new WhoInfo();
  548.             p.readFrom(is);
  549.             whoList.appendText(p.toString() + "\r\n");
  550.         }
  551.     }
  552.  
  553.  
  554.     /**
  555.      * Read numlines of chat window messages from the server and
  556.      * display them in the chat window (if the chat window exists).
  557.      * @param numlines the number of lines to read
  558.      */
  559.     public void readChat(int numlines) throws java.io.IOException {
  560.         while (numlines-- > 0) {
  561.             InfoPacket p = new InfoPacket();
  562.             p.readFrom(is);
  563.             if (chatWindow != null)
  564.                 chatWindow.chatMsg(p.toString());
  565.         }
  566.     }
  567.  
  568.  
  569.     /**
  570.      * The main execution loop for this applet's thread. The thread
  571.      * basically waits for input from the server and updates the 
  572.      * contents of all of the info window when information is
  573.      * received.
  574.      */
  575.     public void run() {
  576.         try {
  577.             ShellCommand type = new ShellCommand();
  578.             CountPacket count = new CountPacket();
  579.  
  580.             while (true) {
  581.                 try {
  582.                     type.readFrom(is);
  583.                     count.readFrom(is);
  584.                 
  585.                     if (type.getCommand() == ShellCommand.GAMES) {
  586.                         readGames(count.getCount());
  587.                     }
  588.                     else if (type.getCommand() == ShellCommand.WHO) {
  589.                         readWho(count.getCount());
  590.                     }
  591.                     else if (type.getCommand() == ShellCommand.CHATMSG) {
  592.                         readChat(count.getCount());
  593.                     }
  594.                 }
  595.                 catch (java.io.EOFException e) {
  596.                     System.out.println("Exception: "+e);
  597.                     System.out.println("Server must have disappeared. Stop");
  598.                     return;
  599.                 }
  600.                 catch (Exception e) {
  601.                     System.out.println("Ignoring Exception: "+e);
  602.                     e.printStackTrace();
  603.                 }
  604.             }
  605.         }
  606.         catch (Exception e) {
  607.             System.out.println("Exception: "+e);
  608.             e.printStackTrace();
  609.         }
  610.     }
  611.  
  612.  
  613.     /**
  614.      * Sends a request to the server to join the given game.
  615.      * @param game the game to join
  616.      */
  617.     public void join(int game) throws java.io.IOException {
  618.         if (gameId > -1) {
  619.             ShellCommand cmd = new ShellCommand(ShellCommand.QUIT, gameId);
  620.             cmd.writeTo(os);
  621.         }
  622.         if (game != gameId) {
  623.             gameId = game;
  624.             ShellCommand cmd = new ShellCommand(ShellCommand.JOIN, gameId);
  625.             cmd.writeTo(os);
  626.         }
  627.         else
  628.             gameId = -1;
  629.     }
  630.  
  631.  
  632.     /**
  633.      * Return the currently executing game Id, -1 if there is no
  634.      * game in progress.
  635.      */
  636.     public int getGameId() { 
  637.         return gameId; 
  638.     }
  639.  
  640.  
  641.     /**
  642.      * Suspends this applet's main thread.
  643.      */
  644.     public void suspend() {
  645.         appletThread.suspend();
  646.     }
  647.  
  648.  
  649.     /**
  650.      * Resumes this applet's main thread.
  651.      */
  652.     public void resume() {
  653.         appletThread.resume();
  654.     }
  655.  
  656.  
  657.     /**
  658.      * Quits this applet, cleaning up any lingering windows and
  659.      * informing the server that we are quitting.
  660.      */
  661.     public void quit() {
  662.         if (chatWindow != null) {
  663.             chatWindow.dispose();
  664.             chatWindow = null;
  665.         }
  666.         try {
  667.             ShellCommand cmd = new ShellCommand(ShellCommand.DISCONNECT, 0);
  668.             cmd.writeTo(os);
  669.         }
  670.         catch (Exception e) {}
  671.  
  672.         clientFrame.dispose();
  673.         Common.exit(0);
  674.     }
  675.  
  676.  
  677.     /**
  678.      * Sends a message to the server to shut itself down. This method
  679.      * is really only accessible by wizards from their display consoles.
  680.      */
  681.     public void shutdownServer() {
  682.         try {
  683.             ShellCommand cmd = new ShellCommand(ShellCommand.SHUTDOWN, 0);
  684.             cmd.writeTo(os);
  685.         }
  686.         catch (Exception e) {}
  687.  
  688.         quit();
  689.     }
  690.  
  691.  
  692.     /**
  693.      * Creates a dialog box allowing the user to change his or her
  694.      * user information.
  695.      */
  696.     public void changeInfo() {
  697.         LoginWindow login = new LoginWindow(this, id);
  698.         login.show();
  699.         suspend();
  700.     }
  701.  
  702.  
  703.     /**
  704.      * Turns the chat window on if it is off, and off if
  705.      * it is on.
  706.      */
  707.     public void toggleChatWindow() {
  708.         if (chatWindow == null) {
  709.             chatWindow = new ChatWindow(this);
  710.             chatWindow.pack();
  711.             chatWindow.show();
  712.         }
  713.         else {
  714.             chatWindow.dispose();
  715.             chatWindow = null;
  716.         }
  717.     }
  718.  
  719.  
  720.     /**
  721.      * Sends the given chat message to the server.
  722.      * @param msg the message to send to the server
  723.      */
  724.     public void sendChat(String msg) {
  725.         try {
  726.             ShellCommand cmd = new ShellCommand(ShellCommand.CHATMSG, 0);
  727.             cmd.writeTo(os);
  728.             InfoPacket info = new InfoPacket(msg, InfoPacket.Info);
  729.             info.writeTo(os);
  730.         }
  731.         catch (Exception e) {
  732.             Window err;
  733.             err = new ErrorWindow(this,"Connection lost.");
  734.             System.out.println(e.toString());
  735.             e.printStackTrace();
  736.             err.show();
  737.             suspend();
  738.             Common.exit(1);
  739.         }
  740.     }
  741.  
  742.  
  743.     /**
  744.      * The main routine for an applet-less execution.
  745.      */
  746.     public static void main(String argv[]) {
  747.         Frame f = new ClosableFrame("Europa");
  748.         EuropaClient client = new EuropaClient(f);
  749.         client.init();
  750.         f.add("Center", client);
  751.         client.start();
  752.     }
  753.  
  754. }
  755.