Contents#

The following page contains information on a variety of Open Wonderland development topics. Often, I'll find a piece of code interesting or important to refer to later. In such a case, I'll put it here and document it where needed.

Client Scripting#

This document is in regards to the EZScript implementation for Open Wonderland. Other implementations such as the ScriptingComponent are outside the scope of this document.

Proposal:#

  • Use local client repository to house startup scripts. A typical callback might be onLoad(). Typical use-cases could include scripting the addition or removal of menus and menu items as well as personalizing a client's key-bindings.

Changing Keybindings#

KeyBindings Description
MOVE_FORWARD Move the avatar forward
MOVE_BACK Move the avatar backward
TURN_LEFT Turn the avatar to the left
TURN_RIGHT Turn the avatar to the right
LEFT Move the avatar to the left
RIGHT Move the avatar to the right

Method Description Usage
GetKeyBindings Retrieve the current map of keybindings. This method is important for using the next two methods. var bindings = GetKeyBindings();
SetBinding Set a particular binding to a particular key for a set of bindings. SetBinding(bindings, "MOVE_FORWARD", "W");
RemoveBinding Remove a particular binding from a set of bindings. RemoveBinding(bindings, "RIGHT");

Changing Camera Perspectives#

Method Description Usage
SetTopDownCamera Set the current camera to look down on the avatar from above. SetTopDownCamera();
SetLeftCamera Set the current camera to look at the avatar from the left. (The camera looks toward the right to the avatar) SetLeftCamera();
SetRightCamera Set the current camera to look at the avatar from the right. (The camera looks toward the left to the avatar) SetRightCamera();

Drag and Drop Events#

Under Construction

Startup Scripts#

Every Wonderland client running the EZScript module has startup scripts that are located in .wonderland/0.5-dev/scripts/startup.ez . This script gets executed when the Wonderland client starts up.
This document is in regards to the EZScript implementation for Open Wonderland. Other implemenations such as the ScriptingComponent are outside the scope of this document.

Cell Scripting#

Global Variables#

Every scripting environment attached to a cell has two global variables: Context, and cell.

Variable Description
Context Main access point for controlling callbacks and triggers in a script.

Most often the Context variable is used to assign new callbacks and triggers.
cell Pointer to the Wonderland cell that effectively encapsulates the scripting environment.

Most often the cell variable is passed as an argument to scripting commands.

  • Context
    • Examples of using the Context variable include:
      • The first letter in the Context variable's name is capitalized due to the fact that JavaScript has a native global variable called: context
Context.enableMouseEvents();
Context.onClick(someFunction, true_of_false);
The following are some common methods owned by the Context variable that are proven useful in scripts.
Method Description Usage
clearCallbacks This will clear any callbacks that have been created as a result of scripting including those inherited from a snapshot.
setTrigger This will identify a certain callback called a "trigger" to be identified with a unique String for a given cell. These are called from other cells. Context.setTrigger("MyTrigger", function_name, false);
triggerCell This will fire (execute) a trigger for a given cell. This often called as part of another cell's script. Context.triggerCell(cellID, "MyTrigger", new Array());
triggerLocalCell This will do the same as above, but only for the local client. Context.triggerLocalCell(cellID, "MyTrigger", new Array());
getCellIDByName This will return a CellID object to be passed to triggerCell. It should be noted that this method is subject to change and a posssible replacement may be $("cellname")

  • Cell
    • Examples of using the cell variable include:
spin(cell, 1, 1);

There exists a global function that is shorthand for Context.getCellIDByName(): $("MyCellName") can be used.

Callbacks#

Callbacks act as event handlers, or in other words, reactions to a user's interactions. For example, clicking on an object.

Callbacks have locality. This means that the scripter can choose whether or not the reactions to their events happen only on their client or on all clients. This is desirable to use when the script uses a command that requires network involvement.

All callbacks are invoked by appending the Context variable to the beginning of the event name:

Context.onClick(function_name, true_or_false);

Event Description Usage
onClick When a user clicks the mouse. Context.onClick(function_name, true_or_false);
Context.onClick('shift', function_name, true_or_false);
Context.onClick('alt', function_name, true_or_false);
Context.onClick('ctrl', function_name, true_or_false);
onMouseEnter When a user moves the mouse over an object. Context.onMouseEnter(function_name, true_or_false);
onMouseExit When a user moves the moss off an object. Context.onMouseExit(function_name, true_or_false);
onKeyPress When a user has moused over an object and pressed a specific key on the keyboard. Context.onKeyPress("k", function_name, true_or_false);
onApproach When a user walks sufficiently close to an object. Context.onApproach(function_name, true_or_false);
onLeave When a user walks away from an object. Context.onLeave(function_name, true_or_false);

Triggers#

Triggers are a mechanism for one cell to affect other cells. For example: Click on a poster of a new movie and the movie starts playing in a video player nearby.

The following is a sample pair of scripts illustrating the use of triggers. It is ESSENTIAL that you use the workflow described in the next section when crafting triggers such as these below. Two shape cells were created, one a sphere, and the other a cube. Each cell was named appropriately (i.e. Sphere, Cube) before any scripts were written.

The Sphere's script:

   function spinTrigger() {
      spin(cell, 1, 1);
   }

   Context.setTrigger("spin", spinTrigger, false);

At the time of writing, the false parameter in the setTrigger() method, is mandatory.

The Cube's script:

   Context.enableMouseEvents();

   function click() {
      var s = Context.getCellIDByName("Sphere");
      Context.triggerCell(s, "spin", new Array());
   }

   Context.onClick(click, false);

Workflow#

The following workflow should be considered when creating a world with scripting from start-to-finish.
  1. Create all objects in your world
  2. Go into each relevant object's properties through the object editor and give each a unique name
  3. Attach the scripting component to each relevant object via the object editor
  4. Write each script for each object using each object's script editor

Notes#

It should be noted that EZScript is a work in progress and under active development. Please report any problems, comments, and suggestions to the Open Wonderland forums.

Example scripts

Sample Scripts#

These scripts were used during the iED 2011 EZScript workshop
//spin molecule
spin(cell, 1, 5);

//spin + click
Context.enableMouseEvents();

function click() {

spin(cell, 1, 5);
}
Context.onClick(click, false);

//spin + click + highlight
Context.clearCallbacks();
Context.enableMouseEvents();

function click() {
 spin(cell, 1, 5);
}

function highlight() {
HighlightCell(cell, true, 'white');
}

function unhighlight() {
HighlightCell(cell, false, 'white');
}

Context.onClick(click, false);
Context.onMouseEnter(highlight, false);
Context.onMouseExit(unhighlight, false);

//highlight
Context.clearCallbacks();
Context.enableMouseEvents();

function highlight() {
HighlightCell(cell, true, 'white');
}

function unhighlight() {
HighlightCell(cell, false, 'white');
}

Context.onMouseEnter(highlight, false);
Context.onMouseExit(unhighlight, false);

//spin and move plane
animateMove(cell, 0, 0, 1, 3);
spin(cell, .25, 1);
animateMove(cell, 1, 0, 0, 3);
spin(cell, .25, 1);
animateMove(cell, 0, 0, -1, 3);
spin(cell, -.25, 1);
animateMove(cell, -1, 0, 0, 3);
spin(cell, -.25, 1);

//highlight
Context.clearCallbacks();
Context.enableMouseEvents();

function highlight() {
HighlightCell(cell, true, 'white');
}

function unhighlight() {
HighlightCell(cell, false, 'white');
}

Context.onMouseEnter(highlight, false);
Context.onMouseExit(unhighlight, false);

//open door
Context.clearCallbacks();
Context.enableMouseEvents();
Context.enableProximityEvents();

function open() {
 spin(cell, 0.25, 2);
}


function close() {
  spin(cell, 0, 1);
}

Context.onLeave(close, false);
Context.onClick(open, false);

//NPC talking
Context.enableProximityEvents();

function SayHello() {
  ShowHUDMessage("Hello, Welcome to Open Wonderland!");
}

function SayGoodbye() {
  ShowHUDMessage("Talk to you soon! Bye!");
}

Context.onApproach(SayHello, true);
Context.onLeave(SayGoodbye, true);

//NPC walking in a circle
var x;
for(x = 0; x < 20; x++) {
  MoveNpcForward(cell);
  MoveNpcLeft(cell);
}

Often times a developer will want to manipulate the HUD or Head's Up Display. When this occurs, one must remember to call the code on the AWT Event Queue like so:
SwingUtilities.invokeLater(new Runnable() { 
    public void run() {
    
    }
});
Often a developer may want to execute code on the MT-Game thread. In such a circumstance, the developer should wrap the code as such:
SceneWorker.addWorker(new WorkCommit() { 
    public void commit() {
        //put code here
    }
}); 

Processors#

Under Construction

Summary#

The shared-state component allows for dynamic server state information to be easily created, retrieved, updated, and deleted. Through the component, shared maps are created to pass SharedData back and forth. Shared Maps are special map implementations that automatically send messages to and from the server to keep the state of the map synchronized across all clients. Not only does this work well for dynamic state settings, but it also provides a great mechanism for sending and retrieving custom messages. When maps are created through the component, listeners handle the message processing.

Usage
#

Server
#

Include the following field declaration in your CellMO (or ComponentMO) class. You won't explicitly access it, but the annotation will do the heavy lifting for you.

    @UsesCellComponentMO(SharedStateComponentMO.class)
    private ManagedReference<SharedStateComponentMO> sharedStateComponentRef;

Client #

Include the following field declaration in your Cell (or Component) class.
    @UsesCellComponent
    private SharedStateComponent sharedStateComponent;
    private SharedMapCli mySharedMap;

Shared Maps#

As mentioned prior, shared maps utilize SharedData. SharedData is an interface implemented by wrappers of common Java primitives. The following implementations are included by default:

SharedData Java Primitive
SharedString String
SharedBoolean boolean
SharedByte byte
SharedChar char
SharedFloat float
SharedInteger int
SharedLong long
SharedShort short

Each shared datatype implements the SharedData interface and is annotated by two annotations: @CellState , and @XmlRootElement. By mimicking this pattern, one can create their own custom shared data types that will work in SharedMaps through the SharedStateComponent.

Listeners#

Shared Map Listeners are typically inner classes which are used to react to messages received through the SharedStateComponent. You can use these listeners in such a way by including the following class as an inner class of the cell or cell component you are using the SharedStateComponent in:

    class SharedMapListener implements SharedMapListenerCli {    
        public void propertyChanged(SharedMapEventCli event) {
            ...
        }
    }


In order to be used, listeners must be attached to the map that contains the data. You can attach a listener to a map by using the following:

    SharedMapListener listener = new SharedMapListener();
    mySharedMap.addSharedMapListener(listener);

Presence Manager#

The presence manager package can be used to obtain user specific data on the client. To get the current presence manager for a given session, i.e. The current Wonderland instance use the following code:
    PresenceManagerFactory.getPresenceManager(A_Wonderland_Session);

With a presence manager, you can retrieve user specific data in the form of PresenceInfo, set up a PresenceManagerListener to be notified when a user has logged in, out, updated their avatar, moved into and out of speaking distance.

PresenceManagerListener#

Notes#

Common Cells#

  • Common cells in essence are cells with no predefined type. With a common cell, one can attach models directly to it's scenegraph, add a cell with a defined type as a child, and to act as a placeholder for Wonderland's cell graph.
  • You cannot directly insert a common cell from the wonderland client's "Insert object" menu. Instead, they are more properly to be used programmatically through scripting.
  • Because common cells are part of the EZScript framework, creation of a common cell comes with an EZScript capability and SharedStateComponent pre-attached.

Simple Physics#

Under Construction

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-27) was last changed on 23-Dec-2011 16:56 by JagWire