diff --git a/docs/micasa/design.txt b/docs/micasa/design.txt new file mode 100644 index 000000000..16f07894e --- /dev/null +++ b/docs/micasa/design.txt @@ -0,0 +1,11 @@ +Mi Casa Design -*- mode: outline -*- + +* Overview + +The Mi Casa service is a combination of a game server and a client +framework for hosting relatively simple, networked, multiplayer games. The +service is designed for hosting games implemented using the Parlor +services and built on top of the Cocktail networking platform. + +The Mi Casa service is comprised of a server that can be configured to +have any number of lobbies in which users can get together to play games. diff --git a/rsrc/config/micasa/dbmap.properties b/rsrc/config/micasa/dbmap.properties new file mode 100644 index 000000000..bd488e640 --- /dev/null +++ b/rsrc/config/micasa/dbmap.properties @@ -0,0 +1,13 @@ +# +# $Id: dbmap.properties,v 1.1 2001/10/03 23:24:09 mdb Exp $ +# +# This provides information on the JDBC connections that are used by +# MiCasa server services. + +# +# The database mapping for the user database. +# +userdb.driver = org.gjt.mm.mysql.Driver +userdb.url = jdbc:mysql://depravity:3306/usermgmt +userdb.username = www +userdb.password = Il0ve2PL@Y diff --git a/rsrc/config/micasa/server.properties b/rsrc/config/micasa/server.properties new file mode 100644 index 000000000..43024a5b8 --- /dev/null +++ b/rsrc/config/micasa/server.properties @@ -0,0 +1,4 @@ +# +# $Id: server.properties,v 1.1 2001/10/03 23:24:09 mdb Exp $ +# +# Configuration for the MiCasa server diff --git a/src/java/com/threerings/micasa/Log.java b/src/java/com/threerings/micasa/Log.java new file mode 100644 index 000000000..fc03bcc99 --- /dev/null +++ b/src/java/com/threerings/micasa/Log.java @@ -0,0 +1,54 @@ +// +// $Id: Log.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa; + +/** + * A placeholder class that contains a reference to the log object used by + * the MiCasa package. This is a useful pattern to use when using the + * samskivert logging facilities. One creates a top-level class like this + * one that instantiates a log object with an name that identifies log + * messages from that package and then provides static methods that + * generate log messages using that instance. Then, classes in that + * package need only import the log wrapper class and can easily use it to + * generate log messages. For example: + * + *
+ * import com.threerings.micasa.Log;
+ * // ...
+ * Log.warning("All hell is breaking loose!");
+ * // ...
+ * 
+ * + * @see com.samskivert.util.Log + */ +public class Log +{ + /** The static log instance configured for use by this package. */ + public static com.samskivert.util.Log log = + new com.samskivert.util.Log("micasa"); + + /** Convenience function. */ + public static void debug (String message) + { + log.debug(message); + } + + /** Convenience function. */ + public static void info (String message) + { + log.info(message); + } + + /** Convenience function. */ + public static void warning (String message) + { + log.warning(message); + } + + /** Convenience function. */ + public static void logStackTrace (Throwable t) + { + log.logStackTrace(com.samskivert.util.Log.WARNING, t); + } +} diff --git a/src/java/com/threerings/micasa/client/ChatPanel.java b/src/java/com/threerings/micasa/client/ChatPanel.java new file mode 100644 index 000000000..dd9bc4a2f --- /dev/null +++ b/src/java/com/threerings/micasa/client/ChatPanel.java @@ -0,0 +1,267 @@ +// +// $Id: ChatPanel.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa.client; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.*; +import javax.swing.text.*; +import java.util.StringTokenizer; + +import com.samskivert.swing.*; +import com.threerings.cocktail.party.chat.*; +import com.threerings.cocktail.party.client.*; +import com.threerings.cocktail.party.data.OccupantInfo; +import com.threerings.cocktail.party.data.PlaceObject; +import com.threerings.cocktail.party.util.PartyContext; + +import com.threerings.micasa.Log; + +public class ChatPanel + extends JPanel + implements ActionListener, LocationObserver, ChatDisplay, OccupantObserver +{ + public ChatPanel (PartyContext ctx) + { + // keep this around for later + _ctx = ctx; + + // create our chat director and register ourselves with it + _chatdtr = new ChatDirector(_ctx); + _chatdtr.addChatDisplay(this); + + // register as a location observer + _ctx.getLocationDirector().addLocationObserver(this); + _ctx.getOccupantManager().addOccupantObserver(this); + + GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH); + gl.setOffAxisPolicy(GroupLayout.STRETCH); + setLayout(gl); + + // create our scrolling chat text display + _text = new JTextPane(); + _text.setEditable(false); + add(new JScrollPane(_text)); + + // create our styles and add those to the text pane + createStyles(_text); + + // add a label for the text entry stuff + add(new JLabel("Type here to chat:"), GroupLayout.FIXED); + + // create a horizontal group for the text entry bar + gl = new HGroupLayout(GroupLayout.STRETCH); + JPanel epanel = new JPanel(gl); + epanel.add(_entry = new JTextField()); + _entry.setActionCommand("send"); + _entry.addActionListener(this); + _entry.setEnabled(false); + + _send = new JButton("Send"); + _send.setEnabled(false); + _send.addActionListener(this); + _send.setActionCommand("send"); + epanel.add(_send, GroupLayout.FIXED); + add(epanel, GroupLayout.FIXED); + + // add a logoff button + gl = new HGroupLayout(GroupLayout.NONE); + gl.setJustification(GroupLayout.RIGHT); + JPanel bpanel = new JPanel(gl); + + JButton logoff = new JButton("Logoff"); + logoff.addActionListener(this); + logoff.setActionCommand("logoff"); + bpanel.add(logoff, GroupLayout.FIXED); + + add(bpanel, GroupLayout.FIXED); + + // focus the chat input field by default + _entry.requestFocus(); + } + + protected void createStyles (JTextPane text) + { + StyleContext sctx = StyleContext.getDefaultStyleContext(); + Style defstyle = sctx.getStyle(StyleContext.DEFAULT_STYLE); + + _nameStyle = text.addStyle("name", defstyle); + StyleConstants.setForeground(_nameStyle, Color.blue); + + _msgStyle = text.addStyle("msg", defstyle); + StyleConstants.setForeground(_msgStyle, Color.black); + + _errStyle = text.addStyle("err", defstyle); + StyleConstants.setForeground(_errStyle, Color.red); + + _noticeStyle = text.addStyle("notice", defstyle); + StyleConstants.setForeground(_noticeStyle, Color.magenta); + } + + public void actionPerformed (ActionEvent e) + { + String cmd = e.getActionCommand(); + if (cmd.equals("send")) { + sendText(); + + } else if (cmd.equals("logoff")) { + // request that we logoff + _ctx.getClient().logoff(true); + + } else { + System.out.println("Unknown action event: " + cmd); + } + } + + public boolean locationMayChange (int placeId) + { + // we're always amenable to change + return true; + } + + public void locationDidChange (PlaceObject place) + { + Log.info("We be here: " + place); + + // enable our chat input elements since we're now somewhere that + // we can chat + _entry.setEnabled(true); + _send.setEnabled(true); + _entry.requestFocus(); + } + + public void locationChangeFailed (int placeId, String reason) + { + Log.warning("Unable to change to location [plid=" + placeId + + ", reason=" + reason + "]."); + } + + public void occupantEntered (OccupantInfo info) + { + displayOccupantMessage("*** " + info.username + " entered."); + } + + public void occupantLeft (OccupantInfo info) + { + displayOccupantMessage("*** " + info.username + " left."); + } + + public void occupantUpdated (OccupantInfo info) + { + } + + protected void displayOccupantMessage (String message) + { + // stick a newline on the message + message = message + "\n"; + + Document doc = _text.getDocument(); + try { + doc.insertString(doc.getLength(), message, _noticeStyle); + } catch (BadLocationException ble) { + Log.warning("Unable to insert text!? [error=" + ble + "]."); + } + } + + protected void sendText () + { + String text = _entry.getText(); + + // if the message to send begins with /tell then parse it and + // generate a tell request rather than a speak request + if (text.startsWith("/tell")) { + StringTokenizer tok = new StringTokenizer(text); + // there should be at least three tokens: '/tell target word' + if (tok.countTokens() < 3) { + displayError("Usage: /tell username message"); + return; + } + + // skip the /tell and grab the username + tok.nextToken(); + String username = tok.nextToken(); + + // now strip off everything up to the username to get the + // message + int uidx = text.indexOf(username); + String message = text.substring(uidx + username.length()).trim(); + + // request to send this text as a tell message + _chatdtr.requestTell(username, message); + + } else { + // request to send this text as a chat message + _chatdtr.requestSpeak(text); + } + + // clear out the input because we sent a request + _entry.setText(""); + } + + public void displaySpeakMessage (String speaker, String message) + { + // wrap the speaker in brackets + speaker = "<" + speaker + "> "; + // stick a newline on the message + message = message + "\n"; + + Document doc = _text.getDocument(); + try { + doc.insertString(doc.getLength(), speaker, _nameStyle); + doc.insertString(doc.getLength(), message, _msgStyle); + } catch (BadLocationException ble) { + Log.warning("Unable to insert text!? [error=" + ble + "]."); + } + } + + protected void displayError (String message) + { + // stick a newline on the message + message = message + "\n"; + + Document doc = _text.getDocument(); + try { + doc.insertString(doc.getLength(), message, _errStyle); + } catch (BadLocationException ble) { + Log.warning("Unable to insert text!? [error=" + ble + "]."); + } + } + + public void displayTellMessage (String speaker, String message) + { + // wrap the speaker in brackets + speaker = "[" + speaker + " whispers] "; + // stick a newline on the message + message = message + "\n"; + + Document doc = _text.getDocument(); + try { + doc.insertString(doc.getLength(), speaker, _nameStyle); + doc.insertString(doc.getLength(), message, _msgStyle); + } catch (BadLocationException ble) { + Log.warning("Unable to insert text!? [error=" + ble + "]."); + } + } + + public void handleResponse (int reqid, String status) + { + if (!status.equals(ChatCodes.SUCCESS)) { + displayError(status); + } + } + + protected PartyContext _ctx; + protected ChatDirector _chatdtr; + + protected JComboBox _roombox; + protected JTextPane _text; + protected JButton _send; + protected JTextField _entry; + + protected Style _nameStyle; + protected Style _msgStyle; + protected Style _errStyle; + protected Style _noticeStyle; +} diff --git a/src/java/com/threerings/micasa/client/ClientController.java b/src/java/com/threerings/micasa/client/ClientController.java new file mode 100644 index 000000000..10ea7fda5 --- /dev/null +++ b/src/java/com/threerings/micasa/client/ClientController.java @@ -0,0 +1,189 @@ +// +// $Id: ClientController.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa.client; + +import java.awt.event.ActionEvent; +import com.samskivert.swing.Controller; + +import com.threerings.cocktail.cher.dobj.*; +import com.threerings.cocktail.cher.client.*; +import com.threerings.cocktail.cher.net.Credentials; +import com.threerings.cocktail.cher.net.UsernamePasswordCreds; + +import com.threerings.cocktail.party.client.*; +import com.threerings.cocktail.party.data.*; + +import com.threerings.media.sprite.SpriteManager; + +import com.threerings.micasa.Log; +import com.threerings.micasa.util.MiCasaContext; + +/** + * The client controller is responsible for top-level control of the + * client user interface. It deals with locating and displaying the proper + * panels and controllers for particular user interface modes (walking + * around the world, puzzling, etc.) and it manages the side-bar controls + * as well. + */ +public class ClientController + extends Controller + implements ClientObserver, LocationObserver, OccupantObserver, Subscriber +{ + /** + * Creates a new client controller. The controller will set everything + * up in preparation for logging on. + */ + public ClientController (MiCasaContext ctx, MiCasaFrame frame) + { + // we'll want to keep these around + _ctx = ctx; + _frame = frame; + + // we want to know about logon/logoff + _ctx.getClient().addObserver(this); + + // we want to know about location changes + _ctx.getLocationDirector().addLocationObserver(this); + + // we also want to know about occupant changes + _ctx.getOccupantManager().addOccupantObserver(this); + + // create our main panel which we'll use once we're logged on + _mainPanel = new MainPanel(); + + // create the chat ui + ChatPanel panel = new ChatPanel(_ctx); + _mainPanel.setNavigation(panel); + + // create the logon panel and display it + _logonPanel = new LogonPanel(_ctx); +// _frame.setPanel(_logonPanel); + + // create a sprite manager + _spritemgr = new SpriteManager(); + + // configure the client with some credentials and logon + String username = "bob" + + ((int)(Math.random() * Integer.MAX_VALUE) % 500); + Credentials creds = new UsernamePasswordCreds(username, "test"); + Client client = _ctx.getClient(); + client.setCredentials(creds); + client.logon(); + } + + // documentation inherited + public boolean handleAction (ActionEvent action) + { + Log.info("Got action: " + action); + return false; + } + + // documentation inherited + public void clientDidLogon (Client client) + { + Log.info("Client did logon [client=" + client + "]."); + + // keep the body object around for stuff + _body = (BodyObject)client.getClientObject(); + + // we're logged on, so we lose the login panel and move to our + // primary display + _frame.setPanel(_mainPanel); + } + + // documentation inherited + public void clientFailedToLogon (Client client, Exception cause) + { + Log.info("Client failed to logon [client=" + client + + ", cause=" + cause + "]."); + _logonPanel.logonFailed(cause); + } + + // documentation inherited + public void clientConnectionFailed (Client client, Exception cause) + { + Log.info("Client connection failed [client=" + client + + ", cause=" + cause + "]."); + } + + // documentation inherited + public boolean clientWillLogoff (Client client) + { + Log.info("Client will logoff [client=" + client + "]."); + return true; + } + + // documentation inherited + public void clientDidLogoff (Client client) + { + Log.info("Client did logoff [client=" + client + "]."); + System.exit(0); + } + + // documentation inherited + public boolean locationMayChange (int placeId) + { + return true; + } + + // documentation inherited + public void locationDidChange (PlaceObject place) + { + Log.info("Moved to new location [place=" + place + "]."); + + // we wants to subscribe to the location + if (_place != null) { + _place.removeSubscriber(this); + } + place.addSubscriber(this); + _place = place; + } + + // documentation inherited + public void locationChangeFailed (int placeId, String reason) + { + Log.info("Location change failed [plid=" + placeId + + ", reason=" + reason + "]."); + } + + public void occupantEntered (OccupantInfo info) + { + Log.info("New occupant " + info + "."); + } + + public void occupantLeft (OccupantInfo info) + { + } + + public void occupantUpdated (OccupantInfo info) + { + } + + public void objectAvailable (DObject object) + { + // don't care + } + + public void requestFailed (int oid, ObjectAccessException cause) + { + // don't care + } + + public boolean handleEvent (DEvent event, DObject target) + { + return true; + } + + protected MiCasaContext _ctx; + protected MiCasaFrame _frame; + protected BodyObject _body; + protected PlaceObject _place; + + // managers + protected SpriteManager _spritemgr; + + // our panels + protected LogonPanel _logonPanel; + protected MainPanel _mainPanel; +} diff --git a/src/java/com/threerings/micasa/client/LogonPanel.java b/src/java/com/threerings/micasa/client/LogonPanel.java new file mode 100644 index 000000000..63f022f9a --- /dev/null +++ b/src/java/com/threerings/micasa/client/LogonPanel.java @@ -0,0 +1,131 @@ +// +// $Id: LogonPanel.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa.client; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.*; + +import com.samskivert.swing.*; + +import com.threerings.cocktail.cher.client.Client; +import com.threerings.cocktail.cher.net.*; + +import com.threerings.micasa.util.MiCasaContext; + +public class LogonPanel + extends JPanel implements ActionListener +{ + public LogonPanel (MiCasaContext ctx) + { + // keep this around for later + _ctx = ctx; + + GroupLayout gl = new VGroupLayout(GroupLayout.NONE); + gl.setOffAxisPolicy(GroupLayout.EQUALIZE); + setLayout(gl); + + // give ourselves a wee bit of a border + setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + // create a big fat label + JLabel title = new JLabel("Mi Casa!"); + title.setFont(new Font("Helvetica", Font.BOLD, 24)); + add(title); + + // create the username bar + JPanel bar = new JPanel(new HGroupLayout(GroupLayout.STRETCH)); + bar.add(new JLabel("Username"), GroupLayout.FIXED); + _username = new JTextField(); + _username.setActionCommand("skipToPassword"); + _username.addActionListener(this); + bar.add(_username); + add(bar); + + // create the password bar + bar = new JPanel(new HGroupLayout(GroupLayout.STRETCH)); + bar.add(new JLabel("Password"), GroupLayout.FIXED); + _password = new JPasswordField(); + _password.setActionCommand("logon"); + _password.addActionListener(this); + bar.add(_password); + add(bar); + + // create the logon button bar + gl = new HGroupLayout(GroupLayout.NONE); + gl.setJustification(GroupLayout.RIGHT); + bar = new JPanel(gl); + _logon = new JButton("Logon"); + _logon.setActionCommand("logon"); + _logon.addActionListener(this); + bar.add(_logon); + add(bar); + + add(new JLabel("Status")); + _status = new JTextArea() { + public Dimension getPreferredScrollableViewportSize () + { + return new Dimension(10, 100); + } + }; + _status.setEditable(false); + JScrollPane scroller = new JScrollPane(_status); + add(scroller); + + // start with focus in the username field + _username.requestFocus(); + } + + public void actionPerformed (ActionEvent e) + { + String cmd = e.getActionCommand(); + if (cmd.equals("skipToPassword")) { + _password.requestFocus(); + + } else if (cmd.equals("logon")) { + logon(); + + } else { + System.out.println("Unknown action event: " + cmd); + } + } + + protected void logon () + { + // disable further logon attempts until we hear back + setLogonEnabled(false); + + String username = _username.getText().trim(); + String password = _password.getText().trim(); + + System.out.println("Logging on " + username + "/" + password); + + // configure the client with some credentials and logon + Credentials creds = new UsernamePasswordCreds(username, password); + Client client = _ctx.getClient(); + client.setCredentials(creds); + client.logon(); + } + + protected void setLogonEnabled (boolean enabled) + { + _username.setEnabled(enabled); + _password.setEnabled(enabled); + _logon.setEnabled(enabled); + } + + protected void logonFailed (Exception cause) + { + _status.append("Logon failed: " + cause.getMessage() + "\n"); + setLogonEnabled(true); + } + + protected MiCasaContext _ctx; + protected JTextField _username; + protected JPasswordField _password; + protected JButton _logon; + protected JTextArea _status; +} diff --git a/src/java/com/threerings/micasa/client/MiCasaApp.java b/src/java/com/threerings/micasa/client/MiCasaApp.java new file mode 100644 index 000000000..66e543254 --- /dev/null +++ b/src/java/com/threerings/micasa/client/MiCasaApp.java @@ -0,0 +1,51 @@ +// +// $Id: MiCasaApp.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa.client; + +import java.io.IOException; +import com.samskivert.swing.util.SwingUtil; +import com.threerings.micasa.Log; + +/** + * The micasa app is the main point of entry for the MiCasa client + * application. It creates and initializes the myriad components of the + * client and sets all the proper wheels in motion. + */ +public class MiCasaApp +{ + public void init () + throws IOException + { + // create a frame + _frame = new MiCasaFrame(); + + // create our client instance + _client = new MiCasaClient(_frame); + } + + public void run () + { + // position everything and show the frame + _frame.setSize(800, 600); + SwingUtil.centerWindow(_frame); + _frame.show(); + } + + public static void main (String[] args) + { + MiCasaApp app = new MiCasaApp(); + try { + // initialize the app + app.init(); + } catch (IOException ioe) { + Log.warning("Error initializing application."); + Log.logStackTrace(ioe); + } + // and run it + app.run(); + } + + protected MiCasaClient _client; + protected MiCasaFrame _frame; +} diff --git a/src/java/com/threerings/micasa/client/MiCasaClient.java b/src/java/com/threerings/micasa/client/MiCasaClient.java new file mode 100644 index 000000000..e2ea460e5 --- /dev/null +++ b/src/java/com/threerings/micasa/client/MiCasaClient.java @@ -0,0 +1,130 @@ +// +// $Id: MiCasaClient.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa.client; + +import java.awt.event.*; +import java.io.IOException; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +import com.samskivert.util.Config; + +import com.threerings.cocktail.cher.client.*; +import com.threerings.cocktail.cher.dobj.DObjectManager; +import com.threerings.cocktail.cher.net.*; + +import com.threerings.cocktail.party.client.LocationDirector; +import com.threerings.cocktail.party.client.OccupantManager; + +import com.threerings.parlor.client.ParlorDirector; + +import com.threerings.micasa.Log; +import com.threerings.micasa.util.MiCasaContext; + +/** + * The MiCasa client takes care of instantiating all of the proper + * managers and loading up all of the necessary configuration and getting + * the client bootstrapped. + */ +public class MiCasaClient + implements Client.Invoker +{ + /** + * Creates a new client and provides it with a frame in which to + * display everything. + */ + public MiCasaClient (MiCasaFrame frame) + throws IOException + { + // keep this for later + _frame = frame; + + // log off when they close the window + _frame.addWindowListener(new WindowAdapter() { + public void windowClosing (WindowEvent evt) { + _client.logoff(true); + } + }); + + // create our context + _ctx = new MiCasaContextImpl(); + + // create the handles on our various services + _config = new Config(); + _client = new Client(null, this); + + // create our managers and directors + _locdir = new LocationDirector(_ctx); + _occmgr = new OccupantManager(_ctx); + _pardtr = new ParlorDirector(_ctx); + + // for test purposes, hardcode the server info + _client.setServer("bering", 4007); + + // create our client controller and stick it in the frame + _frame.setController(new ClientController(_ctx, _frame)); + } + + /** + * Returns a reference to the context in effect for this client. This + * reference is valid for the lifetime of the application. + */ + public MiCasaContext getContext () + { + return _ctx; + } + + // documentation inherited + public void invokeLater (Runnable run) + { + // queue it on up on the swing thread + SwingUtilities.invokeLater(run); + } + + /** + * The context implementation. This provides access to all of the + * objects and services that are needed by the operating client. + */ + protected class MiCasaContextImpl implements MiCasaContext + { + public Config getConfig () + { + return _config; + } + + public Client getClient () + { + return _client; + } + + public DObjectManager getDObjectManager () + { + return _client.getDObjectManager(); + } + + public LocationDirector getLocationDirector () + { + return _locdir; + } + + public OccupantManager getOccupantManager () + { + return _occmgr; + } + + public ParlorDirector getParlorDirector () + { + return _pardtr; + } + } + + protected MiCasaContext _ctx; + protected MiCasaFrame _frame; + + protected Config _config; + protected Client _client; + protected LocationDirector _locdir; + protected OccupantManager _occmgr; + protected ParlorDirector _pardtr; +} diff --git a/src/java/com/threerings/micasa/client/MiCasaFrame.java b/src/java/com/threerings/micasa/client/MiCasaFrame.java new file mode 100644 index 000000000..a92f13795 --- /dev/null +++ b/src/java/com/threerings/micasa/client/MiCasaFrame.java @@ -0,0 +1,55 @@ +// +// $Id: MiCasaFrame.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa.client; + +import java.awt.BorderLayout; +import javax.swing.*; + +import com.samskivert.swing.Controller; +import com.samskivert.swing.ControllerProvider; + +/** + * The micasa frame contains the user interface for the MiCasa client + * application. It divides the screen into space for the primary panel and + * the side-bar controls and allows user interface elements to be placed + * in either region. + */ +public class MiCasaFrame + extends JFrame implements ControllerProvider +{ + public MiCasaFrame () + { + super("MiCasa Client"); + // for now, quit if we're closed + // setDefaultCloseOperation(EXIT_ON_CLOSE); + } + + public void setPanel (JPanel panel) + { + // remove the old panel + getContentPane().removeAll(); + // add the new one + getContentPane().add(panel, BorderLayout.CENTER); + // swing doesn't properly repaint after adding/removing children + validate(); + } + + /** + * Sets the controller for the outermost scope. This controller will + * handle all actions that aren't handled by controllers of tigher + * scope. + */ + public void setController (Controller controller) + { + _controller = controller; + } + + // documentation inherited + public Controller getController () + { + return _controller; + } + + protected Controller _controller; +} diff --git a/src/java/com/threerings/micasa/lobby/LobbyPanel.java b/src/java/com/threerings/micasa/lobby/LobbyPanel.java new file mode 100644 index 000000000..18cd725c1 --- /dev/null +++ b/src/java/com/threerings/micasa/lobby/LobbyPanel.java @@ -0,0 +1,86 @@ +// +// $Id: LobbyPanel.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa.client; + +import javax.swing.*; +import com.samskivert.swing.*; + +/** + * The main panel is the top level component in the UI. It encloses the + * primary user interface display and the sidebar displays. The sidebar + * contains a navigation display, a management display (where various + * management panels can be added), and the chat interface. + */ +public class MainPanel extends JPanel +{ + public MainPanel () + { + GroupLayout gl = new HGroupLayout(GroupLayout.STRETCH); + gl.setOffAxisPolicy(GroupLayout.STRETCH); + gl.setJustification(GroupLayout.RIGHT); + gl.setGap(0); + setLayout(gl); + + // create our sidebar panel + gl = new VGroupLayout(GroupLayout.STRETCH); + gl.setOffAxisPolicy(GroupLayout.STRETCH); + _sidePanel = new JPanel(gl); + _sidePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + // stick some stuff in our sidebar for now + JLabel label = new JLabel("Sidebar views"); + _sidePanel.add(label, GroupLayout.FIXED); + add(_sidePanel, GroupLayout.FIXED); + } + + /** + * Sets the primary view. This is the large view that displays the + * primary activity going on in the client (the iso view when they're + * walking around, the puzzle view when they're puzzling, etc.). + */ + public void setPrimary (JPanel view) + { + // ignore requests to set the same view. it's simplest to deal + // with this here + if (view == _primView) { + return; + } + + // remove the previous primary view + if (_primView != null) { + remove(_primView); + } + + // add the new view + _primView = view; + add(_primView, 0); + validate(); + } + + /** + * Sets the navigation view. This is the small map-like view in the + * upper right corner of the display. + */ + public void setNavigation (JPanel view) + { + // remove the old view + if (_navView != null) { + _sidePanel.remove(_navView); + } + + // add the new one + _navView = view; + _sidePanel.add(_navView); + _sidePanel.validate(); + } + + /** The sidebar panel. */ + protected JPanel _sidePanel; + + /** The primary view. */ + protected JPanel _primView; + + /** The navigation view. */ + protected JPanel _navView; +} diff --git a/src/java/com/threerings/micasa/server/MiCasaServer.java b/src/java/com/threerings/micasa/server/MiCasaServer.java new file mode 100644 index 000000000..7e4a0e225 --- /dev/null +++ b/src/java/com/threerings/micasa/server/MiCasaServer.java @@ -0,0 +1,72 @@ +// +// $Id: MiCasaServer.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa.server; + +import com.samskivert.jdbc.ConnectionProvider; +import com.samskivert.jdbc.StaticConnectionProvider; +import com.samskivert.util.Config; + +import com.threerings.cocktail.party.server.PartyServer; +import com.threerings.parlor.server.ParlorManager; + +import com.threerings.micasa.Log; + +/** + * This class is the main entry point and general organizer of everything + * that goes on in the MiCasa game server process. + */ +public class MiCasaServer extends PartyServer +{ + /** The namespace used for server config properties. */ + public static final String CONFIG_KEY = "micasa"; + + /** The database connection provider in use by this server. */ + public static ConnectionProvider conprov; + + /** The parlor manager in operation on this server. */ + public static ParlorManager parmgr = new ParlorManager(); + + /** + * Initializes all of the server services and prepares for operation. + */ + public void init () + throws Exception + { + // do the cher server initialization + super.init(); + + // bind the whirled server config into the namespace + config.bindProperties(CONFIG_KEY, CONFIG_PATH, true); + + // initialize our parlor manager + parmgr.init(config, invmgr); + + // create our connection provider + String dbmap = config.getValue(DBMAP_KEY, DEF_DBMAP); + conprov = new StaticConnectionProvider(dbmap); + + Log.info("MiCasa server initialized."); + } + + public static void main (String[] args) + { + MiCasaServer server = new MiCasaServer(); + try { + server.init(); + server.run(); + } catch (Exception e) { + Log.warning("Unable to initialize server."); + Log.logStackTrace(e); + } + } + + // the path to the config file + protected final static String CONFIG_PATH = + "rsrc/config/micasa/server"; + + // connection provider related configuration info + protected final static String DBMAP_KEY = CONFIG_KEY + ".dbmap"; + protected final static String DEF_DBMAP = + "rsrc/config/micasa/dbmap.properties"; +} diff --git a/src/java/com/threerings/micasa/util/MiCasaContext.java b/src/java/com/threerings/micasa/util/MiCasaContext.java new file mode 100644 index 000000000..e1d7ebc2b --- /dev/null +++ b/src/java/com/threerings/micasa/util/MiCasaContext.java @@ -0,0 +1,17 @@ +// +// $Id: MiCasaContext.java,v 1.1 2001/10/03 23:24:09 mdb Exp $ + +package com.threerings.micasa.util; + +import com.threerings.parlor.util.ParlorContext; + +/** + * The micasa context encapsulates the contexts of all of the services + * that are used by the micasa client so that we can pass around one + * single context implementation that provides all of the necessary + * components to all of the services in use. + */ +public interface MiCasaContext + extends ParlorContext +{ +}