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
+{
+}