 |
Home | Changes | Index | Search | Go
DRAFT v0.3: The Wonderland File System (WFS) Architecture
1. Introduction
The following document is a design proposal for the architecture of the Wonderland File
System (WFS). The WFS allows worlds in Project Wonderland to be defined as a series of
hierarchically arranged XML files. A world in Wonderland consists of a hierarchical set of 3D
volumes (called 'cells'). Currently, the creation of these cells, their properties, and the
parent/child relationships among them are hard-coded. It is the purpose of WFS to allow
developers to flexibly define worlds using a well-defined hierarchy of files (typically
organized in directories on disk).
The architecture of WFS should be:
- Extensible, so that new types of cells may be added with no changes required by the underlying software mechanism.
- Developer friendly, so that the structure of the world may be edited and re-loaded easily.
- Network aware, so that new world components may be obtained over the network.
2. Features of the "Wonderland File System"
The Wonderland File System will have the following features:
- It will allow developers to create worlds easily, by creating a hiearchy of directories and disk files representing individual cells. The structure of the world can easily be re-arranged by re-arranging the hierarchy of files on disk.
- A WFS represents a self-contained, relocatable set of cells and resources which may be incorporated into worlds.
- A WFS will have a well-defined set of conventions which will help identify where components will reside in the file system and also help identify the version of the file system specification used.
- A WFS may be archived into a single file and exported over the network.
- A WFS defines a unique, location-independent namespace for some or all of the components contained within the file system.
2.1 Definitions
For the purposes of this architecture proposal, the following definitions apply:
A cell represents a 3D volume in Wonderland. It may consist of a collection of fixed, solid
objects or represent moveable objects such as avatars.
A resource represents raw content such as a collection of polygons or shapes. They are
typically created by a 3D visual authoring tool and stored in some file format specific to
the authoring tool or as a Java 3D scene graph. Raw audio files are also considered resources.
3. High-Level Architecture
A Wonderland File System is a set of directories and files on disk arranged in a certain
way and following certain naming conventions. A single WFS contains all of the cell
definitions (as defined in XML files), (optionally) resources (e.g. artwork) used by these
cells, and optionally a mapping of disk directories to uniquely-named URIs so that portions
of the world may be available over the network. In general, the directory structure of a WFS
will mimic the hierarchical relationship among cells in the world. A WFS, however, may
also contain an archive of resources made available over the network and/or a collection
of unrelated re-usable cells.
Figure 1 illustrates the high-level architecture of the Wonderland File System. Each
machine runs a single instance of the Wonderland server, which defines a single, contiguous
world with bounds from negative infinity to positive infinity along all three cartesian axes.
Associated with each running instance of the Wonderland server is a 'root' WFS, whose
path on the local filesystem is given by the 'worldRoot' property, defined within the
WonderlandServerConfig? class and stored in the WonderlandServerConfig?.xml file. (Strictly
speaking, more than one instance of the Wonderland server may run on a single machine, so
long as they have unique network identies.)
Typically, an 'administrator' executes the Wonderland server and has read/write permission
to the root WFS. 'Users', on the other hand, may run the Wonderland client, but also may
wish to add content to the world.
In the most simple case, the root WFS defines the entire world -- it contains all of the
cell definitions and all of the resources necessary to display those cells. In more
advanced configurations, the root WFS (or any WFS for that matter) may allow portions of
the world to be defined by other WFS located on the same server file system, or located
on different machines entirely. Figure 1 illustrates an example usage of this advanced
configuration, where a certain subset of the world is defined by another WFS, perhaps
contained within a user's directory. In this way, the Wonderland administator can
provision the world and assign parts of it to users. (For example, the administrator may
define an office building, but provision offices to individual users. Individual users
can then design their offices the way they wish.) A special type of cell (WFS Cell)
links in other WFS's.
To facilitate the identification of WFS's and cells contained within them, the
WFS architecture defines a URI type independent of the structure of the files on disk. The
root WFS for each machine is always given as 'wfs://'. As described later
in this document, WFS URI's may refer to entire WFS's or individual cells within a WFS. At
this point, WFS URI's only refer to cells, not individual resources.
4. The Structure of a Wonderland File System
4.1 The Base-Level Directory
The top-level of each Wonderland File System is always a directory which follows the naming
convention: '-wfs'. The location of the base level directory is defined by the 'worldRoot'
property in the Wonderland server configuration file.
4.2 WFS Version
Each instance of a WFS will conform to some version of the WFS architecture specification.
This version number consists of a major and minor version number and is stored in a file
named 'version.xml' in the base-level WFS directory. The version.xml file may be absent --
if so, the system assumes the most recent version implemented by the server software.
Wonderland guarantees both forward and backward compatibility for versions with the same
major number. Specifications for the directory structure with different major version numbers
give no compatibility guarantees. Compatibility guarantees also do not apply to specification
versions < 1.0. It is not necessary for all WFS's referenced by a single running instance of
the server to be of the same version -- a root WFS may contain references to other WFSs with
different versions. The version.xml file is a Java Bean serlialization of the WFSVersion class
as defined below.
public class WFSVersion {
private int major;
private int minor;
public WFSVersion() {}
public int getMajor() { return this.major };
public void setMajor(int major) { this.major = major; }
public int getMinor() { return this.minor };
public void setMinor(int minor) { this.minor = minor; }
}
Note that in WFS two different types of version numbers exist: the entire WFS has a version
number, while each cell definition has a version number as well. The later kind of version
is described later.
4.3 Cell Files, Resources and Directories
Each cell within a WFS is represented by a single XML file and takes the format specified
by JSR 57: Long-Term Presistence for Java Beans at http://jcp.org/en/jsr/detail?id=57. Each
cell file name follows the convention: '-wlc.xml'. A cell may be removed from the
world (perhaps temporarily) by simply renaming the file to not include the '-wlc' suffix.
The attributes of a cell are defined by the cell's XML file itself, including its position
in the world, expressed as coordinates with respect to its parent cell ('cell-local
coordinates'). (Also, see "Issues" below)
The directory structure of the WFS follows the desired structure of the wonderland world
-- the directory structure hierarchy defines the parent/child relationship among the cells
in the world. A cell may have one or more child cells, each spatially contained within
their parent. For a parent cell named '-wlc.xml', its child cells are placed with
a directory named '-wld'. By simply removing the '-wld' suffix from the directory
name, child cells may be (temporarily) unloaded from the world.
The resources (e.g. artwork) used by the cells are specified using URIs. These URIs may
refer to a location on the server's local disk or may be located over the network (e.g.
HTTP URI's). The administrator may control whether external artwork may be used in the
WFS with the 'allowExternalResources' property in the Wonderland server configuration
file. By default, this property is set to 'false'.
Figure 2a illustrates an example of the structure of a WFS. It contains a single cell,
defined by the 'room-wlc.xml' file. The 'hall.xml' is a properly formatted XML file,
however, since it does not follow the cell file naming convention it is ignored. The
room cell has three children found in the 'room-wld' directory. They are: 'desk-wlc.xml',
'door-wlc.xml', and 'chair-wlc.xml'. The version.xml gives the version of the WFS
specification in use; the aliases.xml file is described below.
4.4 WFS URI's
The Wonderland File System defines a new URI protocol type, 'wfs'. The 'wfs' URI type
uniquely identifies parts of a WFS externally in a way that is independent of the exact
structure of the WFS. A WFS itself maps URIs to files and directories contained within
it, in a file named aliases.xml.
Each running instance of a Wonderland server always has one URI referring to the base
of its root file system: 'wfs://:/'. All URIs referring to parts of the
root WFS derive from this base URI. The ':' part of the URI is a DNS domain
name. It is the Wonderland server itself which handles access requests to WFS URIs;
they typically listen to a well-known port defined by the Project Darkstar infrastructure.
If a Wonderland client has a cell which imports portions of worlds defined by a WFS URI
located on another host, it contacts the Wonderland server on that host and requests the
cells.
Each WFS may have one aliases.xml file which defines all of the URI mappings for it. The
aliases.xml file is an XML serialization of the WFSAliases class, as defined below.
An example aliases.xml file is also shown below, which refers to the WFS defined in
Figure 2a. In this example, the WFS exports the 'room' cell' and the 'hall' cell. This
allows other WFS's (in perhaps other Wonderland servers) to refer to elements of the WFS
pictured in Figure 2a. Note that only cells may be exported -- at this time, exporting raw
resources files from within a WFS is not supported. Also note that to export a cell, its
disk file name does not need to follow the naming conventions outlined above, nor does any
directory within it resides. This permits developers to construct entirely 'archival'
Wonderland file systems and export some or all of its contents. This also permits 'hybrid'
Wonderland file systems, with parts which are loaded into a world (i.e. follow the naming
conventions) and parts that are simply exported for use in other Wonderland file systems.
public class WFSAliases {
private Hashmap<URI, URL> aliases;
public WFSAliases() {}
public Hashmap<URI, URL> getAliases() { return this.aliases; }
public void setAliases(Hashmap<URI, URL> aliases) { this.aliases = aliases; }
}
File: aliases.xml
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0" class="java.beans.XMLDecoder">
<object class="java.util.HashMap">
<void method="put">
<string>building/components/room</string>
<string>room-wlc.xml</string>
</void>
<void method="put">
<string>building/components/hall</string>
<string>hall.xml</string>
</void>
</object>
</java>
4.5 Resource Specification
Most often, cells require a certain set of external resources to render them -- the most
salient example of a resource is a 3D scene graph (e.g. a Java 3D scene file, .j3s) stored
on disk. Other examples of resources include audio files and external applications to display
in the Wonderland world. Currently, the locations of these resources are hard-coded paths
to local disk.
In the Wonderland File System, cells refer to the resources it needs using a URI, supporting
the following protocols: file, ftp, ftps, http, and https.
If a resource URI contains a relative path, then the 'file' protocol type is assumed. Resources
may be stored either within the WFS or anywhere on the server's local disk.
In the current version of the specification, for security reasons, the ftp, ftps, http,
and https protocol types are only supported if they refer to the same machine upon which
the WFS resides or if the 'allowExternalResources' flag is set to 'false'.
(In this version of the specification, resources may or may not be included in a WFS. In
the future, resources may more formally become part of the WFS, and perhaps also exported
via a WFS URI.)
4.6 WFS Archive Files
Any WFS may be packaged as a JAR, TAR, or ZIP file. The archive file must have the WFS
root directory (i.e. '-wfs/') as its only top-level entry, all other top-level
entries are ignored.
Wonderland File System archive files may be used in several ways:
- They may be 'dropped in' directly into an exiting WFS (without needed to unpack the archive file). In this instance the archive file must follow the naming convention: '-wla.', where may be 'tar', 'jar', or 'zip'. These archive files may also be additionally compressed using either gzip (in which case they have an additional '.gz' extension), or the UNIX compress format (in which case they have an additional '.Z' extension). There is no need to uncompress the archive file. The contents of the archive file are treated as if the archive is extracted into the current directory, without the root '-wfs/' directory.
- They may be made available as a bundle of resources and cells over the internet to be included in other Wonderland File Systems.
4.7 Requirements of WFS on Native 'Filesystems'
WFS maps the concepts of traditional file systems onto the organization of 3D worlds. In
reality, WFS will most likely be stored on disk on some host, however WFS must not require
features not found in all filesystems. Specifically, WFS only requires:
- A hiearchical set of files and directories can be defined.
- Files and directories can have names which include the '-wfs', '-wlc', and '-wld' suffixes and also the '.xml' extension.
- Files must have a 'last modification date' associated with it. (used for the live update of worlds)
4.8 'Live' Update of Wonderland Worlds
A developer may change the directory structure at any time; it is only when she/he 'pings'
the Wonderland server does it attempt re-read the directory structure. Wonderland will
provide a way to 'ping' the server through an administrative communication channel. The
ability to 'ping' the server will be provided via the Wonderland graphical client and
also as a simple command-line tool.
Wonderland fails gracefully when loading the world structure from disk. It ignores
malformed cell XML files and malformed directories (and all files and directories below
the malformed directory). Wonderland will provide a separate pre-verifier tool which
will perform simple checks on the file system to report whether it contains any
errors. It is the responsibility of the developer to maintain backup copies of the
directory structure.
5. Including WFS's in a World
As mentioned throughout this document, WFS's represent self-contained bundles of cells
which may be included in any Wonderland world. There are generally three different ways
in which administrators/developers can include WFS's located elsewhere. In each of the
three cases, the cell (and any of its children) is the basic unit imported into a world.
- If the WFS is part of the world existing on some other Wonderland server host.
- If the WFS is packaged in an archive available over the net.
- If the WFS is located locally in a user's home directory.
Case 1: In this instance a remote Wonderland server hosts a world, and also exports all
or part of its world via WFS URIs. The remote Wonderland server may contain items which
are included and positioned within its world and are also exported. For example, a chair
may exist at a certain location within a remote Wonderland world. When importing the chair,
the local Wonderland server may wish to override some of its attributes, for example, its
origin.
Case 2: In this instance a WFS is packaged as an archive file located on the network
and available, for example, via an HTTP URI. In this instance, the home Wonderland server
must know the HTTP URI of the archive file and the WFS URI of the cell within the archive
file to be imported. As in Case 1, the home Wonderland server may wish to override certain
attributes of the imported cell.
Case 3: In this instance, an admistrator of a Wonderland world may wish to provision a
space for various users: for example, an office building may be provisioned into separate
offices, each controlled by users. In this case, a user may load a WFS into his/her
provisioned spaced during runtime. This is illustrated in Figure 1.
6. Wonderland Cell Types
At the heart of Wonderland's ability to display virtual worlds is the different types
of cells it supports. The following tables lists all of the cell types, with an
asterisks (*) indicating new cell types defined by this specification.
| Cell Type | Description |
| Anchor* | A cell which allows the teleportation to other Wonderland worlds |
| Animated | A cell containing an animation of individual frames of a 3D volume |
| Audio | A cell which plays audio and has an optional visual representation |
| Avatar | A cell which represents a person in the world |
| Context Menu | A cell which represents a menu for user selection |
| Java 3D | A cell which is rendered by Java 3D code |
| Model Viewer | A cell whose 3D object can be manipulated in the world |
| Shared App 2D | A cell which displays a 2D X Windows application |
| Simple Terrain | A cell which displays a 3D scene from file |
| Slide Show | A cell which displays a sequence of images |
| Tile* | A cell which displays a single 3D volume repeated to fill the space |
| WFS* | A cell which represents the inclusion of a Wonderland File System |
| WFSUser* | A cell which represents the inclusion of a user-defined Wonderland File System |
| WFSArchive* | A cell which represents the inclusion of an archived Wonderland File System |
This specification introduces three new cell types: Anchor, Tile, and WFS. The Anchor cell
lets an avatar jump to other parts of the world, or to different Wonderland worlds
entirely. The anchor cell type takes a URI (of type 'wfs') which defines the position
to jump to. (We very well may need a cell on the receiving end of the transportation
as well.)
The Tile cell allows a single 3D volume to be repeated at a regular interval over
the bounds of the cell. (Similar to a desktop background image which may be tiled
over the screen).
There are several different ways other WFS may be included in an existing world as
defined in Section 5. The WFS, WFSUser, and WFSArchive cell types handle each of
these three cases.
The WFS cell type takes a URI and attaches the cells referred by that URI into
the world. The WFS cell may wish to override a certain set of the attributes defined
by the included set of cells; currently, only the origin may be overridden (to be
expanded for sure in the future). The URI may be a WFS URI, in which case it is
located remotely, or a FILE URI in which case it is located locally. The root of
all Wonderland worlds is defined by this cell type.
The WFSUser cell type takes a user id in the Wonderland server who is responsible
for defining that part of the world. To associate a WFS with that WFSUser cell, the
user sends a special administration message to the server, with the URI of the WFS
that is to be loaded, and a flag that indicates whether that URI should permanently
be associated with that WFS cell, or whether that assocation vanishes upon server
reboot (or perhaps upon a certain timeout).
The WFSArchive cell type includes cells stores in an archive of a WFS. This cell
takes the URI of the archive file and the WFS URI (perhaps empty) of the subset
of the world defined in the archive to include. (Ideally, there should be no reason
this should be a separate cell type, to be visited later for sure).
6.1 Adding New Cell Types to Wonderland
New cell types should be able to be added to Wonderland. It is beyond the scope of this
specification to define this mechanism, except to say that Java class files may be
included in a WFS in the future.
7. Wonderland File System Cell Implememtation
All cells are represented by a specially formatted XML file within a Wonderland File
System. The Java SE XMLDecoder mechanism reads properly formatted XML files and instantiates
Java Beans objects; the XMLEncoder writes properly formatted XML files from existing Java Beans
objects. The XML files represent only that information necessary to create the world -- it is
not meant as a mechanism to save the existing state of a world to disk. Instead, the Project
Darkstar infrastructure provides the facility to save 'game' state to persistent storage
automatically for all of its managed objects (of which cells are but one example in Wonderland).
In the initial implementation, the hierarchy of the cells in memory will mimic the hierarchy
of cells on disk; in future versions of Wonderland this may not be the case if it attempts
to optimize this tree structure for spatially-optimized queries.
7.1 Software Architecture of Cell Classes and their Properties
A cell's configuration properties will be represented by a 'Properties' class named after
the type of cell and conforming to the Java Beans pattern (fields with getter/setter methods
and the default constructor). For example, the simple terrain cell type will have a class
named SimpleTerrainCellProperties? class and contain all of the fields necessary to initialize
the class in memory. The Properties classes will also mirror the class hierarchy of the
cell classes themselves. The existing Cell GLO (Game Logic Object) classes will be augmented
to refer to the Properties class and contain a constructor which takes the Properties class
as an argument. Property fields will be removed from the existing Cell GLO's classes
and instead the Properties class will be queried for configuration information. It is these
Properties classes that will be read from disk using the XMLDecoder mechanism.
The Properties classes will contain the name of the corresponding Cell GLO class to instantiate
when the XML file is read from disk. If no such information exists, Wonderland assumes
the corresponding Cell GLO class is named after the Properties file, minus the 'Properties'
suffix and with a 'GLO' suffix added instead. The name of the corresponding Cell GLO does not
need to be given in the XML file: it may be hardcoded in the Properties class.
Although not currently a feature, the architecture should allow the potential for the
configuration state to be written to disk by Wonderland in addition to reading in the
world configuration. One example of a good use of this feature is for tools which allows
the easy creation of Wonderland worlds (e.g. a Netbeans plugin which generates the WFS
automatically).
(As an alternative, rather than have separate Cell GLO and Properties classes, the Cell GLO
class itself may be redesigned to follow the Java Bean pattern for its configuration fields
and be written/read from disk. This approach has several drawbacks. First, it requires that
each Cell GLO class follows the Java Bean pattern (unless it otherwise defines a BeanInfo? class
or a PersistenceDelegate?). This may expose fields publicly that are not intended to be exposed.
Similarly, fields with public setting/getters may be written to XML files that are not part of
the configuration state of the cell. Separating the 'live' state (stored in the Cell GLO class)
from the 'configuration' state seems like good policy with few drawbacks.)
The position of a cell within the world is defined with respect to its parent, where the
center of the parent's cell is (0, 0, 0). Currently, the Wonderland cells are created using
world coordinates. Aside from converting the existing Wonderland demos into cell-local
coordinates for initialization, little change should be required internally if Wonderland
continues to represent the 3D object graph in world coordinates. When a cell is read from
disk using a coordinate system with respect to its parent, the code may simply walk up the
chain of its parents to translate the cell local coordinates into world coordinates.
7.2 Properties Class Hierarchy
The following code defines the Properties class architecture most of the cell types in
Wonderland, excluding the Avatar and Moveable cell type. The comments within this code
further describe each attribute.
To note: the CellProperties? class defines a method, validate() which gets invoked after
the XML file is read from disk and before the Cell GLO class is created. This lets the
Properties class make sure all of the information is correct, or fills in any missing
information. For example, the SimpleTerrainProperties? class will make sure the 'cellBounds'
property is correct, using the 'cellOrigin' and 'cellSize' attributes present in the
XML file.
/**
* The base property class for all cell types, including the following attributes:
*
* cellOrigin - a 4x4 matrix transformation representing the origin of the cell.
* major - the major version of the cell property specification
* minor - the minor version of the cell property specification
*/
public abstract class CellProperties {
private Matrix4d cellOrigin;
private int major;
private int minor;
public CellProperties() {}
private abstract String getGLOClass(); /* Returns the name of the GLO class */
private void validate() {} /* Called before the GLO is created */
public Matrix4d getCellOrigin() { return this.cellOrigin; }
public void setCellOrigin(Matrix4d cellOrigin) { this.cellOrigin = cellOrigin; }
public int getMajor() { return this.major; }
public void setMajor(int major) { this.major = major; }
public int getMinor() { return this.minor; }
public void setMinor(int minor) { this.minor = minor; }
}
/**
* The base property class for all stationary cells, including the following attributes:
*
* cellBounds - the physical bounds of a cell
* safePoint - a position within the cell where avatars can be safely moved
*/
public abstract class StationaryCellProperties extends CellProperties {
private Bounds cellBounds;
private Matrix4d safePoint;
public StationaryCellProperties() {}
public Bounds getCellBounds() { return this.cellBounds; }
public void setCellBounds(Bounds bounds) { this.cellBounds = bounds; }
public Matrix4d getSafePoint() { return this.safePoint; }
public void setSafePoint(Matrix4d safePoint) { this.safePoint = safePoint; }
}
/**
* The base property class for all 'application' like cells. This is currently left
* empty for future expansion.
*/
public abstract class ApplicationCellProperties extends StationaryCellProperties {
public ApplicationCellProperties() {}
}
/**
* A cell representing an X Windows application in the world, with attributes:
*
* application - a URI describing the application to display
*/
public class SharedApp2DCellProperties extends ApplicationCellProperties {
private URI application;
public SharedApp2DCellProperties() {}
public String getGLOClass() { return "SharedApp2DCellGLO"; }
public URI getApplication() { return this.application; }
public void setApplication(URI name) { this.application = name; }
}
/**
* A rectangular cell representing a simple 3D scene, with attributes:
*
* size - The size of each edge of the rectangular cell.
* model - The URI of the scene graph stored on disk (somewhere).
*/
public class SimpleTerrainCellProperties extends StationaryCellProperties {
private float size;
private URI model;
public SimpleTerrainCellProperties() {}
public String getGLOClass() { return "SimpleTerrainCellGLO"; }
public void validate() { super.setBounds(... code here...); }
public float getSize() { return this.size; }
public void setSize(float size) { this.size = size; }
public URI getModel() { return this.model; }
public void setModel(URI model) { this.model = model; }
@Override
public void setBounds(Bounds bounds) { /* Do nothing */ }
}
/**
* A cell representing an animiation of a simple 3D scene, with properties:
*
* model - An array of URIs of the scene graph stored on disk (somewhere).
*/
public class AnimatedCellProperties extends ApplicationCellProperties {
private URI[] models;
public AnimatedCellProperties() {}
public String getGLOClass() { return "AnimatedCellGLO"; }
public URI[] getModels() { return this.models; }
public void setModels(URI[] models) { this.models = models; }
}
/**
* A cell representing an audio source in the scene, with properties:
*
* treatments - An array of URIs of the 3D scene representing the audio source.
*/
public class AudioCellProperties extends AnimatedCellProperties {
private URI[] treatments;
public AudioCellProperties() {}
public String getGLOClass() { return "AudioCellGLO"; }
public URI[] getTreatments() { return this.models; }
public void setTreatments(URI[] treatments) { this.treatments = treatments; }
}
/**
* A cell drawn by code which renders to a Java 3D scene graph, with properties:
*
* size - The size of each edge of the rectangular cell.
* renderer - A class which renders the scene.
*/
public class Java3DCellProperties extends StationaryCellProperties {
private float size;
private Class renderer;
public Java3DCellProperties() {}
public String getGLOClass() { return "Java3DCellGLO"; }
public void validate() { super.setBounds(... code here...); }
public float getSize() { return this.size; }
public void setSize(float size) { this.size = size; }
public Class getRenderer() { return this.renderer; }
public void setRenderer(Class renderer) { this.renderer = renderer; }
@Override
public void setBounds(Bounds bounds) { /* Do nothing */ }
}
/**
* A cell representing a simple 3D scene which can be manipulated by the
* client, with properties.
*
* model - The URI of the scene graph stored on disk (somewhere).
*/
public class ModelViewerCellProperties extends ApplicationCellProperties {
private URI model;
public ModelViewerCellProperties() {}
public String getGLOClass() { return "ModelViewerCellGLO"; }
public URI getModel() { return this.model; }
public void setModel(URI model) { this.model = model; }
}
/**
* A cell representing an X Windows application displayed in the world,
* with properties.
*
* application - A URI describing the location of the application
* viewingRectangle - The area in which the avatar views the application
* xPixelScale - The scaling of pixels along the x-axis
* yPixelScale - The scaling of pixels along the y-axis
*/
public class SharedApp2DCellProperties extends ApplicationCellProperties {
private URI application;
private Matrix4d viewingRectangle;
private float xPixelScale;
private float yPixelScale;
public SharedApp2DCellProperties() {}
public String getGLOClass() { return "SharedApp2DCellGLO"; }
public URI getApplication() { return this.application; }
public void setApplication(URI application) { this.model = application; }
public Matrix4d getViewingRectangle() { return this.viewingRectangle; }
public void setViewingRectangle(Matrix4d viewingRectangle) { this.viewingRectangle = viewingRectangle; }
public float getXPixelScale() { return this.xPixelScale; }
public void setXPixelScale() { this.xPixelScale = xPixelScale; }
public float getYPixelScale() { return this.yPixelScale; }
public void setYPixelScale() { this.yPixelScale = yPixelScale; }
}
/**
* A cell representing a series of slides, with properties.
*
* models - An array of URIs of the slides stored on disk.
*/
public class SlideShowCellProperties extends ApplicationCellProperties {
private URI[] models;
public SlideShowCellProperties() {}
public String getGLOClass() { return "SlideShowCellGLO"; }
public URI[] getModels() { return this.models; }
public void setModels(URI[] model) { this.models = models; }
}
/**
* A cell representing a tiling of a 3D scene graph, with properties:
*
* model - The URI of the model to tile across the cell
*/
public class TileCellProperties extends StationaryCellProperties {
private URI model;
public TileCellProperties() {}
public String getGLOClass() { return "TileCellGLO"; }
public URI getModel() { return this.model; }
public void setModel(URI model) { this.model = model; }
}
/**
* A cell representing an 'anchor' which lets an avatar jump to
* another part of the world or different world entirely, with
* attributes:
*
* href - The URI of the point to jump to.
*/
public class AnchorCellProperties extends StationaryCellProperties {
private URI href;
public AnchorCellProperties() {}
public String getGLOClass() { return "AnchorCellGLO"; }
public URI getHref() { return this.href; }
public void setHref(URI href) { this.href = href; }
}
/**
* A cell representing a world (or portion thereof) defined by a
* Wonderland File System. The location of the WFS is given by the
* 'uri' property and can be a disk file or located on a remote
* Wonderland server.
*/
public class WFSCellProperties extends StationaryCellProperties {
private URI uri;
private Matrix4d overrideOrigin;
public WFSCellProperties() {}
public String getGLOClass() { return "WFSCellGLO"; }
public URI getUri() { return this.uri; }
public void setUri(URI uri) { this.uri = uri; }
public Matrix4d getOverrideOrigin() { return this.overrideOrigin; }
public void setOverrideOrigin(Matrix4d origin) { this.overrideOrigin = origin; }
}
/**
* A cell representing a world (or portion thereof) defined by an
* archived Wonderland File System. The location of the WFS is given
* by the 'uri' property and can be a disk file or located on a remote
* Wonderland server. The 'uri' takes the form:
*
* <protocol>://<machine>:<port>//<archivefile>?<name>
*
* for example, "http://java.net/useful_stuff.tar.gz?rooms/great_office"
*
* where http://java.net/useful_stuff.tar.gz locates the WFS archive and
* rooms/greatoffice locates a cell defined by the aliases.xml file within
* the archive.
*/
public class WFSArchiveCellProperties extends StationaryCellProperties {
private URI uri;
private Matrix4d overrideOrigin;
public WFSCellArchiveProperties() {}
public String getGLOClass() { return "WFSArchiveCellGLO"; }
public URI getUri() { return this.uri; }
public void setUri(URI uri) { this.uri = uri; }
public Matrix4d getOverrideOrigin() { return this.overrideOrigin; }
public void setOverrideOrigin(Matrix4d origin) { this.overrideOrigin = origin; }
}
/**
* A cell representing a world (or portion thereof) defined by a
* user.
*/
public class WFSUserCellProperties extends StationaryCellProperties {
private String userId;
public WFSUserCellProperties() {}
public String getGLOClass() { return "WFSUserCellGLO"; }
public String getUser() { return this.user; }
public void setUser(String user) { this.user = user; }
}
7.3 Example XML File
The following is the correspond XML file representation of an instance of
the SimpleTerrainCellProperties? class:
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0" class="java.beans.XMLDecoder">
<object class="SimpleTerrainCellProperties">
<void property="cellBounds">
<object class="javax.media.j3d.BoundingSphere">
<void property="radius">
<double>4.0</double>
</void>
</object>
</void>
<void property="cellOrigin">
<object class="javax.vecmath.Matrix4d">
<void property="m00">
<double>1.0</double>
</void>
<void property="m03">
<double>63.55871105194092</double>
</void>
<void property="m11">
<double>1.0</double>
</void>
<void property="m13">
<double>-1.0</double>
</void>
<void property="m22">
<double>1.0</double>
</void>
<void property="m23">
<double>50.0</double>
</void>
<void property="m33">
<double>1.0</double>
</void>
</object>
</void>
<void property="size">
<float>40.0</float>
</void>
</object>
</java>
This example illustrates a few issues:
- The BoundingSphere? class is not properly serialized to XML. It's radius property is present, but not its center (because the Point3d class does not follow the Java Bean pattern). In this case, a special PersistenceDelegate? must be defined to properly serialize the BoundingSphere? class.
- There is an overlap in the attributes between StationaryCellProperties? and SimpleTerrainCellProperties?. Typically, simple terrain cells are defined in terms of a center and a size, from which the bounds are created (versus, say, 2D shared app cells which specify a bounds upon creation). If the developer has the ability to specify the 'bounds' property in the XML file, this could potentially create a cell with conflicting attributes. This is solved by the validate() method on the CellProperties?() class.
- Although the origin of the cell is represented internally as a 4D Matrix (i.e. encoded as a translation), this may not be the best way to represent it on disk. Rather a Point3d object may be best.
8. World Loading Algorithm (Roughly)
The algorithm used by the Wonderland server to load worlds from disk is as follows:
- At the time of initialization, the Wonderland server traverses the entire directory structure under 'worldRoot', according to the directory and file naming conventions outlined above.
- It (potentially) informs all clients of an update to the structure of the world (see discussion below).
- For each file, it instantiates the proper Properties class.
- It searches a list (stored using an appropriate Collection class) for the canonical name of the current file on disk being looked at. This list contains also pairs the canonical name of the file with its last modified date, and a reference to the corresponding Cell GLO class in memory. (This list is initially empty upon boot).
- If the file exists in the list and the last modified date of the disk file is not newer than that found in the list, the file is ignored, and traversal of the file system continues.
- If the file does not exist in the list, a new corresponding Cell GLO class is created, added to the server-side cache and communicated to the client for setup. An entry in the list is created for the new file.
- If the file exists in the list and its last modified date is older than that found on disk, then the old Cell GLO class is removed (and thus communicated to the client) and a new Cell GLO class is created, communicated to the client for setup, and an entry added to the list.
- For all remaining entries in the list which are not found currently on disk, their corresponding Cell GLO classes are removed from the server, removed from the client, and removed from the list.
- If any newly created cell causes a collision with the position of the avatar, then move the avatar to a 'safe' location. (see discussion below)
- It finally (potentially) informs all clients than the update to the world is complete.
8.1 Policy for Updating Clients
When updating the structure of the Wonderland world, the server may implement one of two
policies: it may inform the clients that the world is being updated, wait until it processes
all remaining events from the client, and forbid the client from sending new events until
the world update is complete (effectively 'freezing' the client until the update is complete).
Second, it may simply update the cells in the world at the same time the client continues to
interact with the world.
These two end-member policies have the following traits: a policy which 'freezes' the client
may result in an unacceptable user experience. On the other hand, a policy which updates the
state of the world while allowing the clients to continue to interact with it may cause a
set of possibly unknown error conditions.
For each client, we can break the analysis of this issue into three considerations: if a
changed cell is not visible to the avatar, if the changed cell is visible to the avatar, and
if the avatar is within the changed cell. For the first two cases, there should be no issues
for either of the two update policies -- for a visible cell, it may briefly disappear and
re-appear.
If the avatar is currently standing in a cell which is updated (changed, removed, or added),
there is a potential conflict in either of the two update policies. For example, the avatar
could find itself within the bounds of a new solid object in the world. (e.g. if inside of
a room, a desk is added). Since the server knows the current position of the avatar, it may
simply 'move' the avatar to a 'safe' position when updating the cell. Each 'stationary' cell
has a property 'safePoint' which defines the coordinates (with respect to the center of the
cell) that an avatar may be moved and will not collide with any solid object in the cell.
By default, the vlue of the 'safePoint' property is (0, 0, 0).
9. Issues
The architecture for the WFS has several issues, summarized here:
- The file system architecture does not allow cell's to be defined in terms of 'global coordinates'. One possible solution is to add a flag to CellProperties? indicating that the cell origin is in 'global coordinates'. The remaining issue is where in the WFS directory hierarchy to place global-coordinate cells. They could be placed in a special directory and make Wonderland find the proper parent.
- The file system architecture does not easily allow for cells with multiple parents, mostly due to the fact that a cell's position in the world is defined in relation to its single parent.
- Although the Java Beans persistence mechanism XML format is convenient for for the XMLDecoder mechanism, it may not be human-editable easily for those not familiar with the XML schema. This issue may be mitigated by example XML files for each cell type and perhaps IDE plugins which let you visually create a world and write out the corresponding directory structure.
10. Conclusion
This document outlined the architecture of describing Wonderland worlds as a hierarchy of
files and directories on disk. Minimal changes to the existing Wonderland code is necessary,
with the exception of converting to a cell-local coordinate system. The main challenge of this
architecture is to properly handle circumstances where changes to the world structure conflict
with the existing state of the world (e.g. the current position of the avatar). This
specification hopefully leaves open the possibility to load worlds and world components from
over the network.
|