ProjectWonderlandArchitecture < Javadesktop < TWiki

TWiki . Javadesktop . ProjectWonderlandArchitecture

Home | Changes | Index | Search | Go

Article: Project Wonderland Software Architecture (v0.3, v0.4)

by Jordan Slott (jslott@dev.java.net)

1. Introduction

Project Wonderland is a software platform for the creation of 3D virtual worlds, primarily enabling geographically distributed participants to collaborate with one another. This document describes the software architecture of Project Wonderland. The primary audience of this document are software developers wishing to extend or modify Project Wonderland. Project Wonderland itself is in an early stage of release, and one can expect that the software architecture, as well as this architecture document will change significantly over the course of time.

This architecture document applies to versions 0.3 and 0.4 of Project Wonderland.

2. Main Components: Client-Server Architecture

Project Wonderland is a Java-based, client-server software platform. The server software is based upon Project Darkstar, a multi-player "gaming" technology for the Java SE platform. (The word gaming is placed in quotes because although Project Darkstar is aimed towards the gaming world, it has been employed in other contexts, namely, herein which is not strictly a game).

Project Darkstar manages a collection of objects (called ManagedObjects) and provides APIs for the synchronized update of the state of these objects in response to events from multiple clients. Updates to ManagedObjects are themselves transactional -- either a coherent set of state updates happen across a set of objects or they do not happen at all. All items within a game or virtual world are represented by ManagedObjects on the server, for example, rooms, players, tools, weapons, or any other virtualized real- world object that exists in the world. Details on Project Darkstar can be found at http://www.projectdarkstar.com.

The client is a desktop Java application and is based upon two technologies to render the 3D world: Java 3D and Looking Glass 3D (LG3D). Java 3D, a standard extension to Java SE, renders sets of 3D objects to the screen, making use of hardware acceleration if possible. Details on Java 3D can be found at https://java3d.dev.java.net/. Project Looking Glass provides a 3D desktop environment. It provides a 3D Windowing environment and a set of API to build 3D applications. Details on Project Looking Glass can be found at https://lg3d-core.dev.java.net/.

3. Virtual 3D World

A virtual world is composed of a collection of "cells", each of which represents a 3D volume in the world. A world has a single, right-handed, 3D cartesian coordinate system (hereafter referred to as "world coordinates"). From the viewer's perspective, the +X axis is towards the right, the +Y axis is gravitationally up, and the +Z axis is towards the user. This coordinate system is the same as defined by Java 3D. Cells may be scenery or objects in the virtual world. Persons, called Avatars, are also represented by cells.

Each cell has a position and bounds inside the virtual world. A cell's origin is given in world coordinates, corresponding to the center of the cell. A cell also has "cell coordinates", where the cell's center is at (0, 0, 0).

A cell may contain zero of more other cells, and hence there exists the notion of a "parent" and "children" for each cell -- a single "master" cell represents the entire world and contains all other cells. A cell may have multiple parents, if it spans the physical bounds of more than one parent cell. Cells, therefore, may overlap with one cell and do not need to be entirely contained within a single cell. (This sounds like it means that the bounds of a cell may overlap the bounds of another cell? Bernard.)

4. Server-side architecture

4.1 Darkstar Boot Class and Data Management

Project Darkstar requires a boot-strapping class to initialize the "game", (which replaces the main() method). The org.jdesktop.lg3d.wonderland.darkstar.server.WonderlandBoot class serves this purpose by implementing the Darkstar AppListener interface. The implementation of its initialize() method performs some very basic tasks which kick-starts the creation of the Wonderland world. They are:

  1. Create an instance of the org.jdesktop.lg3d.wonderland.darkstar.server.UserManager class which maintains the list of users (i.e. clients) which connect to the server.
  2. Create an instance of the org.jdesktop.lg3d.wonderland.darkstar.server.cell.MasterCellCacheGLO class which maintains the list of classes which maintains the cache of cells visible to a user. (Not really sure what this means Bernard.)
  3. Create an instance of the org.jdesktop.lg3d.wonderland.darkstar.server.ChecksumManagerGLO class which manages a series of checksums for classes representing assets in the world.
  4. Open a communication channel named ChannelInfo.USER_CHANGE which communicates changes in the client's status.

When a new client opens a connection to the Wonderland server, the WonderlandBoot.loggedIn() method is invoked, which simply creates a new instance of the org.jdesktop.lg3d.wonderland.darkstar.server.WonderlandSessionListener class. It is this class which handles future changes in the state of the client, and in particular creates the avatar when a user logs in (see WonderlandSessionListener.processAvatarSetupMessage()).

4.2 Cell architecture

Project Wonderland employs the Project Darkstar gaming platform on the server-side, where each cell is represented by a managed object. The base abstract class for all cell managed objects is the org.jdesktop.lg3d.wonderland.darkstar.server.cell.CellGLO class. (The suffix "GLO" is a hold-over from an earlier version of Project Darkstar where managed objects were called "Game Logic Objects" (or GLOs)).

There are two types of cells in Wonderland: stationary cells and moveable cells. Stationary cells represent regions which do not move, while moveable cells represent graphics which do move. Avatars are the best (and perhaps only) example of a moveable cell. All stationary cell classes extend org.jdesktop.lg3d.wonderland.darkstar.server.cell.StationaryCellGLO and all moveable cell classes extend org.jdesktop.lg3d.wonderland.darkstar.server.cell.MoveableCellGLO.

Various classes are used to define stationary cells within the Wonderland architecture. The most basic is the "world root" cell (see org.jdesktop.lg3d.wonderland.darkstar.server.cell.WorldRootCellGLO class) which is the root of all cells in the world and is also responsible for creating the world. At present time, the WorldRootCellGLO creates its structure of cells using hard-coded lines of code. (See for example, WorldRootCellGLO.buildFullWorld().) In the future, a more flexible architecture to build worlds is planned.

Currently, the following stationary classes exist to represent the following (in package org.jdesktop.lg3d.wonderland.darkstar.server.cell): simple terrain (SimpleTerrainCellGLO), slide show (SlideShowCellGLO), model viewer (ModelViewerCellGLO), animated (AnimatedCellGLO), audio (AudioCellGLO), and shared application (SharedApp2DCellGLO). The only moveable cell that is exists is the avatar cell (AvatarCellGLO).

4.3 Features of a Cell

All cell classes extend the CellGLO class which provides most of the services necessary for cells. Each cell has a unique ID, generated by a central facility (see org.jdesktop.lg3d.wonderland.darkstar.server.CellIDGenerator) and also a unique name formed as "CELL_" plus ID. (see CellGLO.getCellID() and CellGLO.getGLOName() methods). A cell's ID is simply a number encapsulated by an instance of the org.jdesktop.lg3d.wonderland.darkstar.common.CellID class.

4.3.1 Cell origin and bounds

Each cell's position within the world is defined by its origin, as specified by a 4x4 matrix (see Java 3D's Matrix4d class; the Matrix4d class is used in Java 3D to define general transformations, such as rotations, scalings, translations, and shearings. There seems to be no fundamental limitation why a cell's origin cannot be any combination of these transformations, however, translations and rotations seem to be the only types used in practice). A cell's origin is stored by the 'cellOrigin' member variable and is set directly by all of the cell subclasses. The CellGLO.getOrigin() method returns the origin as the cell in the form of an instance of class Matrix4d.

A cell also has a bounds, represented by the Java 3D Bounds class which describes its physical extent. The subclasses of CellGLO manage the cell's bounds by overriding the CellGLO.getBounds() method.

4.3.2 Cell parents and children

A cell's set of zero or more children and parents are stored in hashed sets. Adding and removing a parent cell is done via the CellGLO.addParentCell() and CellGLO.removeParentCell() methods, respectively. The CellGLO.getParentCellIDs() method returns an array of instances of class CellID, each of which identifies a parent cell. The methods CellGLO.addChildCell() and CellGLO.removeChildCell() add and remove children to and from the cell, respectively. The CellGLO.getChildren() returns a collection of children of the cell.

At any time, some of a cell's children may be invisible, which is conditional upon some visible bounds. The CellGLO.getVisibleCells() method returns a collection of children cells that are visible given a certain bounds. Typically the visible bounds depends upon the viewing frustum of the avatar.

4.3.3 Inter-client communication via a cell

Cells also provide a communication mechanism between clients, using the Project Darkstar channel mechanism. Each cell can have a single communication channel, identified by a unique name and created via the CellGLO.openCellChannel() method. The CellGLO.getCellChannel() method returns the cell's channel. Clients are added as listeners to the channel via the CellGLO.addUserToCellChannel() method and removed via the CellGLO.removeUserFromCellChannel() method. Each of these two methods takes the unique id of the client session as argument. See Section 6 below regarding details of the client-server communication architecture in Project Wonderland.

4.3.4 Client-side cell classes and setup

Each CellGLO class on the server has a corresponding Cell class on the client which is responsible for rendering the cell. The name of the corresponding client cell class is defined by each of the individual server-side cell subclasses via the CellGLO.getClientCellClassName() method.

A server-side CellGLO communicates its visual contents and other setup data via an instance of a class that implements the org.jdesktop.lg3d.wonderland.darkstar.common.CellSetup interface. This is returned from the CellGLO.getSetupData() method that is implemented by each of the individual server-side CellGLO subclasses.

The CellSetup interface itself is simply an empty interface which extends the java.io.Serializable interface so that it may be sent across the wire. Each server-side CellGLO class defines its own "setup" class that implements the CellSetup interface. Examples (in package org.jdesktop.lg3d.wonderland.darkstar.common) include AnimatedCellSetup, AvatarCellSetup, ModelViewerCellSetup, SharedApp2DCellSetup, SimpleCellSetup, and SlideShowCellSetup. The SimpleCellSetup class is used, for example, by the simple terrain cell and has methods which return the name of disk files storing the scene.

4.4 Server-side Cell Caching

The set of Cells which should be currently kept in memory by the client is managed by the server via an instance of org.jdesktop.lg3d.wonderland.darkstar.server.cell.UserCellCacheGLO class, an instance of this class exists for each user (which is equivalent to saying "client") and is created when the user logs in. All instances of UserCellCacheGLO are managed by the instance of MasterCellCacheGLO class that was created by WonderlandBoot (see section 4.1). They are managed objects within the Project Darkstar infrastructure.

The server-side cell caches support several state changes to CellGLOs They are: cell created, root cell created, cell moved, cell deleted, and add parent to cell. At the present time, the UserCellCacheGLO.revalidate() method considers those CellGLOs which are currently visible and adds those CellGLOs which are new and deletes from the client's memory those which are no longer visible. Changes in the state of CellGLOs are communicated via a dedicated channel (named CELL_CACHE) associated with the instance of UserCellCacheGLO class. At present, the messages that are communicated on this channel are serialized instances of the org.jdesktop.lg3d.wonderland.darkstar.common.messages.CellHierarchyMessage class.

The visible cells are determined by the position of the avatar. Its visible domain is determined by an instance of class org.jdesktop.lg3d.wonderland.darkstar.common.AvatarBoundsManager via its getProximityBounds() method. This method defines the visible area as a sphere of a specified radius (AvatarBoundsManager.PROXIMITY_SIZE = 200.0) from the center of the avatar.

5. Client-side Architecture

5.1 The Main class

The org.jdesktop.lg3d.wonderland.Main class, as its name implies, implements the static main() method to start-up the client. It initializes its user interface and reads in any mutable configuration options from an external XML-formatted configuration file.

The initialization of the connection with the server happens via it inner class named StartupListener, which implements the Lg3dStartupListener interface, from Project Looking Glass -- this listener's startupComplete() method is invoked when the initialization of the graphics is complete. In turn, the implementation of the startupComplete() method displays a login dialog (see class org.jdesktop.lg3d.wonderland.LoginDialog) which accepts login information from the user. It initiates a connection to the Wonderland server and invokes the method Main.enableMainWindow() to "turn on" the Wonderland client.

All communication with the Darkstar-based Wonderland server is managed by an instance of class org.jdesktop.lg3d.wonderland.darkstar.client.ChannelController. (This seems to be somewhat misleadingly named as it doesn't control channels, instead it provides a direct client-server communication mechanism.) A new connection to the server is initiated via the ChannelController.initCommunications() method. See Section 6 below for details of class ChannelController.

5.2 Wonderland Universe

The "universe", as created by an instance of class org.jdesktop.lg3d.wonderland.scenemanager.WonderlandUniverseFactory, creates the main drawing canvas and initializes some basic viewing parameters. This instance is created by an instance of class org.jdesktop.lg3d.wonderland.scenemanager.WonderlandPlatformConfig, which in turn, is specified by the lg.platformConfigClass property.

5.3 Scene Manager

Project Wonderland defines its own scene manager, the equivalent of an X Windows window manager in Project Looking Glass. Class org.jdesktop.lg3d.wonderland.scenemanager.WonderlandSceneManager extends the LG3D SceneManagerBase class, an abstract class which implements the LG3D SceneManager interface. The LG3D SceneManagerBase class handles communication with the LG3D display server (the moral equivalent of the X Windows Server) via its implementation of the LG3D interface DisplayServerManagerInterface.

The WonderlandSceneManager.initialize() method contains the bulk of the functionality of this class. It creates an instance of class org.jdesktop.lg3d.wonderland.scenemanager.WorldController with an instance of the Java 3D BranchGroup class to which the WorldController will attach all of the visual content. It also adds the instance of the Java 3D BranchGroup class as a child of the LG3D display server's root.

The instance of WonderlandSceneManager also creates an instance of an LG3D StandardAppContainer class, using a null-style layout manager. The implementation of the SceneManager.addFrame3D() and SceneManager.removeFrame3D() methods add and remove frames to and from the instance of class StandardAppContainer. The usage of this is currently unclear.

The instance of class WonderlandSceneManger is installed according to the LG3D specification as follows: the createSceneManager() method of org.jdesktop.lg3d.wonderland.scenemanager.WonderlandConfigControl returns an instance of class WonderlandSceneManager. The Main class sets the "lg.configclass" property to "org.jdesktop.lg3d.wonderland.scenemanager.WonderlandConfigControl". (Additional configuration information for the scene manager is also handled by the WonderlandConfigControl class, which reads an XML-formatted file of configuration options, by default: "/org/jdesktop/lg3d/wonderland/scenemanager/resources/wonderland.lgcfg".)

5.4 World Controller

The instance of class WorldController handles all of the visible content in the Wonderland world. As class members, it maintains instances of two important client-side classes: org.jdesktop.lg3d.wonderland.scenemanager.UserCellCache and ChannelController. The WorldController takes as an argument a Java 3D BranchGroup to which it adds lighting: an ambient light of color RGB = {0.7, 0.7, 0.7}, and two directional lights. One directional light is white and is down-to-the-left. The second directional light is RGB = {0.2, 0.2, 0.3} and is up-to-the-left. (TODO: What's the effect of this lighting descriptively?)

Details of classes UserCellCache (section 5.4) and ChannelController (section 5.x) are found below.

5.5 Client-Side Cell Caching

Visible cells are cached and maintained by an instance of UserCellCache. The loading/unloading of cells and changing their state is controlled entirely by the server through messages send from the server to the client, formatted as instances of class CellHierarchyMessage. The UserCellCache.handleMessage() method handles these server events, sent over a communication channel maintained by the Project Darkstar infrastructure and handled by an instance of class org.jdesktop.lg3d.wonderland.darkstar.client.UserCellCacheChannelListener.

A common operation, particular at client boot-time, is the request to create new cells on the client side via a message of type CellHierarchyMessage.LOAD_CELL. Using the configuration information embedded in the CellHiearchyMessage, an instance of the client-side cell class is create and initialized. The new cell is added to the HashMap cache of cells, and the thread (an instance of inner class CellUpdateThread within class UserCellCache) is signalled to update the set of visible cells to render (the UserCellCache.visibleCells member variable).

The instance of class UserCellCache also manages the list of cells in which the avatar is currently positioned via the UserCellCache.avatarInCells member variable (a HashSet). This set is updated when the CellUpdateThread is signalled that an update has occurred. Cell enter and exit events are generated--as represented by classes CellEnterEvent and CellExitEvent (in package org.jdesktop.lg3d.wonderland.scenemanager.events), respectively--and posted.

Class UserCellCache currently only implements a subset of the cell states: VISIBLE and INACTIVE. The following cell states are currently not handled: ACTIVE, DISK, and BOUNDS.

Class UserCellCache also implements the org.jdesktop.lg3d.wonderland.scenemanager.UserMotionListener interface which receives notification when the avatar moves (via the userMoved() method). The implementation of the UserCellCache.userMoved() method is currently basic: it simply updates the status of the visible cells and generates cell enter/exit messages using the updated position of the avatar.

6. Client-Server Communication

This section outlines all of the communication channels and messages sent between the Wonderland client and server and between clients.

Each client is represented on the server by a number of objects. The objects are:

There is one of each of these objects per user/client. As the user moves around the world, the server tracks which cells that user "knows about". When the user moves, it notifies the server and the server examines the UserCellCacheGLO to see if that client has already loaded all the cells in its immediate area. If the server finds a cell the client hasn't seen yet, it sends it a message, telling the client to load the new cell.

6.1 Client-Server Direct Communication

When a client connects to the server, a direct client-server communication link is automatically set up by Project Darkstar.

The server transmits the following messages to a client over this mechanism

  1. An initial message giving the version of the communication protocol (in WonderlandBoot.loggedIn()).
  2. Potential error messages as instances of class org.jdesktop.lg3d.wonderland.darkstar.common.messages.ErrorMessage (ditto, and also in WonderlandSessionListener.processFileTransferMessage().
  3. Instances of class org.jdesktop.lg3d.wonderland.darkstar.common.messages.NativeApplicationMessage as messages in reply to a "create application cell" message (in WonderlandSessionListener.processNativeApplicationMessage()).
  4. Instances of class org.jdesktop.lg3d.wonderland.darkstar.common.messages.SoftphoneMessage (in the callStatusChanged() and processSoftphoneMessage() methods of WonderlandSessionListener.

These are handled by a client as follows:

  1. The protocol version and error messages are handled by ChannelController.handleMessage().
  2. NativeApplicationMessage messages are handled by the receivedMessage() method of the inner class MessageListener of class org.jdesktop.lg3d.wonderland.appshare.ServerApp2DCell.
  3. SoftphoneMessage messages are also handled by ChannelController.handleMessage().

A client transmits the following messages to the server over this mechanism:

  1. Instances of classes NativeApplicationMessage. These are sent by the constructor of class ServerApp2DCell.and the sendMessage() method of ChannelController.
  2. Instances of org.jdesktop.lg3d.wonderland.darkstar.common.messages.SoftphoneMessage. These are sent by the connectSoftphone() and disconnectSoftphone() methods of ChannelController.
  3. Instances of org.jdesktop.lg3d.wonderland.darkstar.common.messages.AvatarSetupMessage initiated by the method loggedIn() in class ChannelController.
  4. instances of some sublcass of org.jdesktop.lg3d.wonderland.darkstar.common.messages.CellMessage. Currently there appear to be none.

The server receives the following messages from the client over this mechanism:

  1. Instances of classes NativeApplicationMessage. These are handled by the receivedMessage() method of org.jdesktop.lg3d.wonderland.darkstar.server.WonderlandBaseSessionListener, and subsequently by its processNativeApplicationMessage() method.
  2. Instances of SoftphoneMessage. These are handled by the receivedMessage() method of WonderlandSessionListener.
  3. Instances of org.jdesktop.lg3d.wonderland.darkstar.common.messages.AvatarSetupMessage messages . These are also handled by the receivedMessage() method of WonderlandSessionListener.
  4. Other instances of some sublcass of org.jdesktop.lg3d.wonderland.darkstar.common.messages.CellMessage messages, dispatched to instances of class org.jdesktop.lg3d.wonderland.darkstar.server.CellMessageListener.

6.2 Publish/Subscribe Communication Channels

The Wonderland server also creates publish/subscribe communication channels, which include: USER_CHANGE, CELL_CACHE, AVATAR_P2P, AVATAR_CELL, and SERVER_MANAGER_CHANNEL. A channel provides a communications mechanism between clients and also between a client and its server.

6.2.1 The USER_CHANGE channel

The USER_CHANGE communication channel is created by WonderlandBoot in its initialize() method, and all new clients are automatically added to it. It is used exclusively for server-->client communication.

The server transmits the following messages to the client over this channel:

The server does not receive any messages from the client on this channel.

The client does not transmit any messages on this channel.

The client handles these messages via the receivedMessage() method of class org.jdesktop.lg3d.wonderland.darkstar.client.UserChannelListener.

6.2.2 CELL_CACHE channels

The server creates a CELL_CACHE channel for each client connected. The name of the channel takes the form: user + CELL_CACHE, where 'user' is the name of the user. The CELL_CACHE channel for a client is created by the instance of class UserCellCacheGLO that corresponds to that client (in its contructor). Each new client is automatically added to one of these channels.

Each instance of class UserCellCacheGLO has a CELL_CACHE channel. Only one client/user (the user who's cache it is) is subscribed to that CELL_CACHE channel. The subscription is managed in the login() method of class UserCellCacheGLO. This channel is used exclusively for server-->client communication.

The server transmits the following messages to the client over this channel. The messages are sent by the instance of UserCellCacheGLO.

The server does not receive any messages from the client on this channel.

The client does not transmit any messages on this channel.

The client handles these messages via the receivedMessage() method an instance of class org.jdesktop.lg3d.wonderland.darkstar.client.UserCellCacheChannelListener.

6.2.3 AVATAR_P2P channels

The server creates an AVATAR_P2P channel for each client connected. The name of the channel takes the form: user + AVATAR_P2P, where 'user' is the name of the user. This channel is created by an instance of class AvatarCellGLO during its constructor, and then maintained by that instance of AvatarCellGLO. Another client may request to join an client's P2P? channel via the AvatarCellMessage(JOIN_P2P) message sent on the AVATAR_CELL channel (see below).

Each avatar sends its motion updates over its client's AVATAR_P2P channel, so any client that cares about those updates (generally any other client in visual range of the avatar) will subscribe to it.

The server transmits the following messages to a client over this channel:

A client handles messages via the method receivedMessage() of an instance of class org.jdesktop.lg3d.wonderland.darkstar.client.AvatarP2PChannelListener.

A client transmits instances of class AvatarP2PMessage over this channel, though only of kind MOVE and CHAT:

The server currently receives messages on this channel via the handleMessage() method of an instance of class org.jdesktop.lg3d.wonderland.darkstar.serverAvatarP2PChannelListenerGLO . (The method is only used for logging purposes.)

Thus, this channel is used for inter-client communication (for AvatarP2PMessages of kind MOVE and CHAT), and for server-->client communication (for AvatarP2PMessages of kind SETUP and SPEAKING).

6.2.4 AVATAR_CELL channels

An AVATAR_CELL channel is created by an instance of class AvatarCellGLO during its constructor. The name of the channel takes the form: user + AVATAR_CELL, where 'user' is the name of the user.

The server transmits the following messages to the client over this channel:

When a cell becomes visible, the server steps through a list of all CellGLOs and adds the client to the =CellGLO='s channel if it (the channel) exists. Currently, only the avatar CellGLO? creates a channel for itself. At that point, a SETUP message is sent to the client, which keeps a reference to the channel for future communication.

The server receives the following messages from the client over this channel:

The client transmits instances of class AvatarCellMessage over this channel (see class org.jdesktop.lg3d.wonderland.darkstar.client.cell.AvatarCell.)

The client receives messages over this channel. It handles them via the receivedMessage() method of an instance of class org.jdesktop.lg3d.wonderland.darkstar.client.cell.AvatarCellChannelListener.

6.2.5 The SERVER_MANAGER_CHANNEL channel

The SERVER_MANAGER_CHANNEL communication channel, created by an instance of class org.jdesktop.lg3d.wonderland.darkstar.server.ServerManagerGLO, is used to communication server management information to the client. Currently, the server itself and a special client (hardcoded to name "ServerManager") are added to this channel.

The server transmits and receives instances of class org.jdesktop.lg3d.wonderland.darkstar.common.messages.ServerManagerMessage to the client over this channel, of which there are four kinds: STATUS, FULL_STATUS, CHANGE_UPDATE_INTERVAL, and SET_USER_LIMIT.

The only client to the SERVER_MANAGER_CHANNEL communication channel is provided by an instance of class org.jdesktop.lg3d.wonderland.management.ManagerUI which can be opened using the ANT run-manager target.

6.3 Guidelines for Managing Change at Client and Server

There is a distinction between two kinds of user interaction:
  1. User interaction that only changes the state of the client, perhaps in terms of the appearance of a Cell. An example would be when a user's cursor hovers over a widget (see, for example, the sample module)
  2. User interaction that causes a change of state of a CellGLO on the server. An example would be when a user clicks on a widget (see the sample module for an example)

The two cases are described below. In each case it is assumed that four clients (C1, C2, C3 and C4) are connected to a server.

6.3.1 Change of state of the client
  1. User interaction with Cell on client C2 causes local state change in Cell (no change in server state)
  2. Cell updates appearance
  3. Cell broadcasts message to other clients on Cell's channel; message identifies "kind of change" and new state of Cell
  4. Other clients receive message and their corresponding Cell updates its appearance

client change

6.3.2 Change of state of the server
  1. User interaction with Cell on client C2 causes state change in CellGLO on server
  2. Cell updates local state (if necessary) and appearance
  3. Client C2 send message direct to server. Message describes "kind of change" and new state of Cell
  4. Server identifies appropriate CellGLO
  5. CellGLO updates its state
  6. Server broadcasts message on Cell's channel to all clients except originating client. Message describes "kind of change" and new state.
  7. Each client receives message and updates state of Cell (if necessary) and appearance.

server change

The above flow of control differs from conventional Model-View-Controller (MVC) in the following features:

  1. There is no clear separation between the model and its view. A CellGLO determines its Cell (which is equivalent to saying that the model determines its view). This means that it is not possible to use the same CellGLO class to be rendered by multiple Cell classes. For example, a CellGLO class representing a die could not have two Cell classes that provided different renderings of a die.
  2. There is no clear separation between a view and its controller. The controller for a view (following the Swing etiquette) is provided by an inner class in the view class. So, for example, a controller for a Cell is often provided by an inner class of the Cell class.
  3. Because multiple clients render the same Cell, it's necessary to synchronise between the clients. This requirement is outside MVC, and is handled in Wonderland by the use of messages to the channel owned by a Cell.

Finally, the flow of control in MVC differs sublty from that of Wonderland. For example, if Wonderland used MVC, the flow of control would be

  1. User interaction with Cell on client C2 causes state change in CellGLO on server
  2. Client C2 send message direct to server. Message describes "kind of change" and new state of CellGLO
  3. Server identifies appropriate CellGLO
  4. CellGLO updates its state
  5. Server broadcasts message on Cell's channel to all clients. Message describes "kind of change".
  6. Each client receives message and requests the state of the CellGLO
  7. Each client updates state of Cell (if necessary) and appearance.

classic MVC

The reason for this difference is performance. It is important that the user is notified of a change of appearance as soon as possible (i.e. before notifying the server).

7. Summary of Important Code Flow Sequences

This section summarizes the flow of control in the code for two aspects of Project Wonderland: when a client first connects and when an avatar moves or changes its look direction.

7.1. Sequence of Code when a Client First Connects

  1. The Main class creates the main window and adds an instance of the LG3D Lg3dConnector class to the main window. This, in turn, starts the LG3D display server. Upon initialization, the L3GD display server initializes the universe, windowing system, view, creates the root scene graph, and initializes the scene manager.
  2. The Wonderland Scene Manager creates a new instance of class WorldController, which creates a new instances of the ChannelController and UserCellCache classes.
  3. Upon completion of the LG3D initialization, the StartupListener.startupComplete() method is called which raises the Wonderland Login dialog.
  4. Upon user login confirmation, a connection to the Darkstar server is opened. The client waits for login confirmation, which is sent asynchronously via a call to WonderlandClientListener.loggedIn().
  5. Upon login, the client sends an AvatarSetupMessage message to the Darkstar server via its client-server communication mechanism with information about the avatar, such as its visual model.
  6. Upon the conclusion of login, the main window of the Wonderland client is enabled.

7.2 Sequence of Code upon Initialization of the Server

  1. The WonderlandBoot.initialize() method creates new instances of classes ServerManagerGLO, UserManager, MasterCellCacheGLO, and ChecksumManagerGLO. A publish/subscribe channel is also created named USER_CHANGE.
  2. The MasterCellCacheGLO instance creates a new instance of class WorldRootCellGLO. In turn this calls the WorldRootCellGLO.buildWorld() method which creates all of the cells in the world.
  3. An instance of class WonderlandSessionListener receives an AvatarSetupMessage message from the client. It creates a new instance of class UserGLO.
  4. The UserGLO instance creates a new AvatarCellGLO instance, which in turn creates a new UserCellCacheGLO instance.
  5. The UserCellCacheGLO instance creates a publish/subscribe channel named user+CELL_CACHE, where 'user' is the name of the user.
  6. The AvatarCelLGLO instance then opens a publish/subscribe channel named AVATAR_P2P and a channel named user+AVATAR_TILE, where 'user' is the name of the user.
  7. The WonderlandSessionListener instance then joins the client to the USER_CHANGE channel and sends a UserChangedMessage(USER_ADDED) message to the client. It then calls the login() method on the UserGLO instance.
  8. The UserGLO.login() method adds a reference of the user to the hash map relating user ID's to user object references. It calls AvatarCellGLO.login().
  9. The AvatarCellGLO.login() adds the receiving instance of AvatarCellGLO to the MasterCellCacheGLO instance. It then calls UserCellCacheGLO.login() which joins the client to the user+CELL_CACHE channel, adds itself (the UserCellCacheGLO) to the MasterCellCacheGLO instance, and sends a CellHierarchyMessage(LOAD_CELL) message to the channel named "user+CELL_CACHE", and then sends a CellHiearchyMessage(SET_WORLD_ROOT) message to the channel named "user+CELL_CACHE".
  10. The UserGLO.login() method then calls the UserCellCacheGLO.avatarCellMoved() method, which computes the list of visible cells and sends CellHierarchyMessage(LOAD_CELL) messages for all visible cells on the channel named "user+CELL_CACHE". It also sends CellHierarchyMessage(DELETE_CELL or CELL_INACTIVE) messages for all newly non- visible cells on the channel named "user+CELL_CACHE".
  11. The WonderlandSessionListener finally sends UserChangedMessage messages to each of the clients via the USER_CHANGE channel to notify them of the new client.

7.2 Sequence of Code when an Avatar Moves

In this code sequence we consider when the user presses one of the cursor-control keys to move the position of the avatar.

  1. The key event is handled by the keyPressed() method of class org.jdesktop.lg3d.wonderland.scenemanager.WalkBehavior. The state of the instance of the inner class Stimulus is updated to reflect the key state change.
  2. The method scheduleUpdate() of the instance of class org.jdesktop.lg3d.wonderland.scenemanager.AvatarControlBehavior is called which tells it that pending updates to the avatar state exists.
  3. The AvatarControlBehavior.processStimulus() method wakes up and calls the WalkBehavior.updateState() method which updates the position state of the avatar.
  4. Collision detection is performed based upon the new position of the Avatar. The position of the camera is then updated.
  5. All implementations of interface UserMotionListener are notified of the new position of the avatar via the method userMoved(). One example of an implementation of UserMotionListener is class UserCellCache, whose userMoved() method calls the UserCellCache.updateCells() method. (Another example implementation of the interface is class AvatarCell).
  6. The updateCells() method computes the visible cells based upon the user's viewing frustum. It updates the state of each cell and the list of visible cells. For all visible cells, it updates the list of cells the avatar is currently standing in. It causes events of type CellEnterEvent and CellExitEvent to be sent to the appropriate cells (within the LG3D event framework). (At this time the AvatarCellMessage types CELL_ENTER and CELL_EXIT are not sent to the server, nor does the server take any action upon receiving these events).
  7. The AvatarCell.userMoved() method sends an AvatarCellMessage(AVATAR_MOVE & CELLMOVE) to the server via the AVATAR_TILE channel. The position of the avatar is updated on the server and the UserCellCacheGLO is asked to revalidate itself (which computes the list of visible and invisible cells, updates its state, and informs the client of such).

8. Future Documentation Work

This software architecture document details just the basics of the Wonderland client-server software. Noticeably absent is documentation on avatar's and their configuration and control behavior, application sharing, and audio.

----- Revision r14 - 07 May 2008 - 03:14:12 - Main.jslott