From 06899b8b7aef266af3a7c960360aae41294eb3ae Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Thu, 21 Apr 2005 00:23:41 +0000 Subject: [PATCH] Further massaging of the JME base application; started in on a chat client that will run in happy 3D land. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3515 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- src/java/com/threerings/jme/JmeApp.java | 148 ++++++++------ .../com/threerings/jme/client/JabberApp.java | 106 ++++++++++ .../threerings/jme/client/JabberClient.java | 193 ++++++++++++++++++ .../jme/client/JabberController.java | 19 ++ 4 files changed, 399 insertions(+), 67 deletions(-) create mode 100644 tests/src/java/com/threerings/jme/client/JabberApp.java create mode 100644 tests/src/java/com/threerings/jme/client/JabberClient.java create mode 100644 tests/src/java/com/threerings/jme/client/JabberController.java diff --git a/src/java/com/threerings/jme/JmeApp.java b/src/java/com/threerings/jme/JmeApp.java index 456944d8d..79d59c54b 100644 --- a/src/java/com/threerings/jme/JmeApp.java +++ b/src/java/com/threerings/jme/JmeApp.java @@ -38,6 +38,7 @@ import com.jme.system.lwjgl.LWJGLPropertiesDialog; import com.jme.app.AbstractGame; import com.jme.input.InputHandler; +import com.jme.input.InputSystem; import com.jme.light.PointLight; import com.jme.math.Vector3f; import com.jme.renderer.Camera; @@ -77,74 +78,77 @@ public class JmeApp if (framesPerSecond <= 0) { throw new IllegalArgumentException("FPS must be > 0."); } - _targetFrameTime = (float)_timer.getResolution() / framesPerSecond; + _targetFrameTicks = _timer.getResolution() / framesPerSecond; } /** - * Initializes this application and starts up the main rendering and - * event processing loop. This method will not return until the - * application is terminated with a call to {@link #stop}. + * Does the main initialization of the application. This method should + * be called first, and then the {@link #run} method should be called + * to begin the rendering/event loop. Derived classes can override + * this, being sure to call super before doing their own + * initalization. */ - public void start () + public void init () + { + // load up our renderer configuration + _properties = new PropertiesIO(getConfigPath("jme.cfg")); + if (!_properties.load()) { + LWJGLPropertiesDialog dialog = + new LWJGLPropertiesDialog(_properties, (String)null); + while (dialog.isVisible()) { + try { + Thread.sleep(5); + } catch (InterruptedException e) { + Log.warning("Error waiting for dialog system, " + + "using defaults."); + } + } + } + + // create an appropriate timer + _timer = Timer.getTimer(_properties.getRenderer()); + + // default to 60 fps + setTargetFrameRate(60); + + // initialize the rendering system + initDisplay(); + if (!_display.isCreated()) { + throw new IllegalStateException("Failed to initialize display?"); + } + + // initialize our main camera controls and user input handling + initInput(); + + // initialize the root node + initRoot(); + + // initialize the lighting + initLighting(); + + // update everything for the zeroth tick + _root.updateGeometricState(0f, true); + _root.updateRenderState(); + + // create and add our statistics display + if (displayStatistics()) { + _stats = new StatsDisplay(_display.getRenderer()); + _stats.updateGeometricState(0f, true); + _stats.updateRenderState(); + } + } + + /** + * Starts up the main rendering and event processing loop. This method + * will not return until the application is terminated with a call to + * {@link #stop}. + */ + public void run () { synchronized (this) { _dispatchThread = Thread.currentThread(); } - try { - // load up our renderer configuration - _properties = new PropertiesIO(getConfigPath("jme.cfg")); - if (!_properties.load()) { - LWJGLPropertiesDialog dialog = - new LWJGLPropertiesDialog(_properties, (String)null); - while (dialog.isVisible()) { - try { - Thread.sleep(5); - } catch (InterruptedException e) { - Log.warning("Error waiting for dialog system, " + - "using defaults."); - } - } - } - - // create an appropriate timer - _timer = Timer.getTimer(_properties.getRenderer()); - - // default to 60 fps - setTargetFrameRate(60); - - // initialize the rendering system - initDisplay(); - if (!_display.isCreated()) { - throw new IllegalStateException("Failed to initialize display?"); - } - - // initialize our main camera controls and user input handling - initInput(); - - // initialize the root node - initRoot(); - - // initialize the lighting - initLighting(); - - // update everything for the zeroth tick - _root.updateGeometricState(0f, true); - _root.updateRenderState(); - - // create and add our statistics display - if (displayStatistics()) { - _stats = new StatsDisplay(_display.getRenderer()); - _stats.updateGeometricState(0f, true); - _stats.updateRenderState(); - } - - } catch (Throwable t) { - Log.logStackTrace(t); - exit(); - return; - } - // enter the main rendering and event processing loop while (!_finished && !_display.isClosing()) { try { @@ -277,17 +281,19 @@ public class JmeApp */ protected final void processFrame () { - float frameStart = _timer.getTime(); - // update our simulation and render a frame + long frameStart = _timer.getTime(); update(frameStart); render(frameStart); _display.getRenderer().displayBackBuffer(); _frames++; - // now process events or sleep until the next frame - do { + // now process events or sleep until the next frame (assume zero + // frame duration to start to ensure that we always process at + // least one event per frame) + long frameDuration = 0L; + while (frameDuration < _targetFrameTicks) { Runnable r = (Runnable)_evqueue.getNonBlocking(); if (r == null) { try { @@ -298,14 +304,15 @@ public class JmeApp } else { r.run(); } - } while (_timer.getTime() - frameStart < _targetFrameTime); + frameDuration = _timer.getTime() - frameStart; + } } /** * Called every frame to update whatever sort of real time business we * have that needs updating. */ - protected void update (float frameTime) + protected void update (long frameTick) { // recalculate the frame rate _timer.update(); @@ -351,6 +358,13 @@ public class JmeApp protected void cleanup () { _display.reset(); + + if (InputSystem.getKeyInput() != null) { + InputSystem.getKeyInput().destroy(); + } + if (InputSystem.getMouseInput() != null) { + InputSystem.getMouseInput().destroy(); + } } /** @@ -380,7 +394,7 @@ public class JmeApp protected String getConfigPath (String file) { String cfgdir = ".narya"; - String home = System.getProperty("user.dir"); + String home = System.getProperty("user.home"); if (!StringUtil.blank(home)) { cfgdir = home + File.separator + cfgdir; } @@ -410,7 +424,7 @@ public class JmeApp protected int _frames; protected float _lastFPSStamp; - protected float _targetFrameTime; + protected long _targetFrameTicks; /** If we fail 100 frames in a row, stick a fork in ourselves. */ protected static final int MAX_SUCCESSIVE_FAILURES = 100; diff --git a/tests/src/java/com/threerings/jme/client/JabberApp.java b/tests/src/java/com/threerings/jme/client/JabberApp.java new file mode 100644 index 000000000..8467a9fe6 --- /dev/null +++ b/tests/src/java/com/threerings/jme/client/JabberApp.java @@ -0,0 +1,106 @@ +// +// $Id: JabberApp.java 3098 2004-08-27 02:12:55Z mdb $ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.jme.client; + +import com.threerings.util.Name; + +import com.threerings.presents.client.Client; +import com.threerings.presents.net.UsernamePasswordCreds; + +import com.threerings.jme.Log; +import com.threerings.jme.JmeApp; + +/** + * The main point of entry for the Jabber client application. It creates + * and initializes the myriad components of the client and sets all the + * proper wheels in motion. + */ +public class JabberApp extends JmeApp +{ + // documentation inherited + public void init () + { + super.init(); + + // initialize our client instance + _client = new JabberClient(); + _client.init(this); + } + + public void run (String server, int port, String username, String password) + { + Client client = _client.getContext().getClient(); + + // pass them on to the client + Log.info("Using [server=" + server + ", port=" + port + "]."); + client.setServer(server, port); + + // configure the client with some credentials and logon + if (username != null && password != null) { + // create and set our credentials + client.setCredentials( + new UsernamePasswordCreds(new Name(username), password)); + client.logon(); + } + + // now start up the main event loop + run(); + } + + // documentation inherited + public void stop () + { + // log off before we shutdown + Client client = _client.getContext().getClient(); + if (client.isLoggedOn()) { + client.logoff(false); + } + Log.info("Stopping."); + super.stop(); + } + + public static void main (String[] args) + { + String server = "localhost"; + if (args.length > 0) { + server = args[0]; + } + + int port = Client.DEFAULT_SERVER_PORT; + if (args.length > 1) { + try { + port = Integer.parseInt(args[1]); + } catch (NumberFormatException nfe) { + Log.warning("Invalid port specification '" + args[1] + "'."); + } + } + + String username = (args.length > 2) ? args[2] : null; + String password = (args.length > 3) ? args[3] : null; + + JabberApp app = new JabberApp(); + app.init(); + app.run(server, port, username, password); + } + + protected JabberClient _client; +} diff --git a/tests/src/java/com/threerings/jme/client/JabberClient.java b/tests/src/java/com/threerings/jme/client/JabberClient.java new file mode 100644 index 000000000..4c43734ad --- /dev/null +++ b/tests/src/java/com/threerings/jme/client/JabberClient.java @@ -0,0 +1,193 @@ +// +// $Id: JabberClient.java 3283 2004-12-22 19:23:00Z ray $ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.jme.client; + +import com.samskivert.util.Config; +import com.threerings.util.MessageManager; + +import com.threerings.presents.client.Client; +import com.threerings.presents.client.SessionObserver; +import com.threerings.presents.dobj.DObjectManager; + +import com.threerings.crowd.chat.client.ChatDirector; +import com.threerings.crowd.client.LocationDirector; +import com.threerings.crowd.client.OccupantDirector; +import com.threerings.crowd.client.PlaceView; +import com.threerings.crowd.util.CrowdContext; + +/** + * The Jabber client takes care of instantiating all of the proper + * managers and loading up all of the necessary configuration and getting + * the client bootstrapped. It can be extended by games that require an + * extended context implementation. + */ +public class JabberClient + implements SessionObserver +{ + /** + * Initializes a new client and provides it with a frame in which to + * display everything. + */ + public void init (JabberApp app) + { + // create our context + _ctx = createContextImpl(); + + // create the directors/managers/etc. provided by the context + createContextServices(app); + + // for test purposes, hardcode the server info + _client.setServer("localhost", 4007); + _client.addClientObserver(this); + } + + /** + * Returns a reference to the context in effect for this client. This + * reference is valid for the lifetime of the application. + */ + public CrowdContext getContext () + { + return _ctx; + } + + // documentation inherited from interface SessionObserver + public void clientDidLogon (Client client) + { + // enter the one and only chat room; giant hack warning: we know + // that the place we're headed to is ID 2 because there's only one + // place on the whole server; a normal client would either issue + // an invocation service request at this point or look at + // something in the BootstrapData to figure out what to do + _ctx.getLocationDirector().moveTo(2); + } + + // documentation inherited from interface SessionObserver + public void clientObjectDidChange (Client client) + { + // nada + } + + // documentation inherited from interface SessionObserver + public void clientDidLogoff (Client client) + { + System.exit(0); + } + + /** + * Creates the {@link JabberContext} implementation that will be + * passed around to all of the client code. Derived classes may wish + * to override this and create some extended context implementation. + */ + protected CrowdContext createContextImpl () + { + return new JabberContextImpl(); + } + + /** + * Creates and initializes the various services that are provided by + * the context. Derived classes that provide an extended context + * should override this method and create their own extended + * services. They should be sure to call + * super.createContextServices. + */ + protected void createContextServices (JabberApp app) + { + // create the handles on our various services + _client = new Client(null, app); + + // create our managers and directors + _locdir = new LocationDirector(_ctx); + _occdir = new OccupantDirector(_ctx); + _msgmgr = new MessageManager(MESSAGE_MANAGER_PREFIX); + _chatdir = new ChatDirector(_ctx, _msgmgr, null); + } + + /** + * The context implementation. This provides access to all of the + * objects and services that are needed by the operating client. + */ + protected class JabberContextImpl implements CrowdContext + { + /** + * Apparently the default constructor has default access, rather + * than protected access, even though this class is declared to be + * protected. Why, I don't know, but we need to be able to extend + * this class elsewhere, so we need this. + */ + protected JabberContextImpl () + { + } + + public Client getClient () + { + return _client; + } + + public DObjectManager getDObjectManager () + { + return _client.getDObjectManager(); + } + + public Config getConfig () + { + return _config; + } + + public LocationDirector getLocationDirector () + { + return _locdir; + } + + public OccupantDirector getOccupantDirector () + { + return _occdir; + } + + public ChatDirector getChatDirector () + { + return _chatdir; + } + + public void setPlaceView (PlaceView view) + { + // TBD + } + + public void clearPlaceView (PlaceView view) + { + // we'll just let the next place view replace our old one + } + } + + protected CrowdContext _ctx; + protected Config _config = new Config("jabber"); + + protected Client _client; + protected LocationDirector _locdir; + protected OccupantDirector _occdir; + protected ChatDirector _chatdir; + protected MessageManager _msgmgr; + + /** The prefix prepended to localization bundle names before looking + * them up in the classpath. */ + protected static final String MESSAGE_MANAGER_PREFIX = "rsrc.i18n"; +} diff --git a/tests/src/java/com/threerings/jme/client/JabberController.java b/tests/src/java/com/threerings/jme/client/JabberController.java new file mode 100644 index 000000000..81d434eb0 --- /dev/null +++ b/tests/src/java/com/threerings/jme/client/JabberController.java @@ -0,0 +1,19 @@ +// +// $Id$ + +package com.threerings.jme.client; + +import com.threerings.crowd.client.PlaceController; +import com.threerings.crowd.client.PlaceView; +import com.threerings.crowd.util.CrowdContext; + +/** + * Handles the basic bits for our simple chat room. + */ +public class JabberController extends PlaceController +{ + protected PlaceView createPlaceView (CrowdContext ctx) + { + return null; + } +}