blaxxun Client SDK - Shared Information

Experiencing your VRML world with other visitors

You have designed a great VRML world with a lot of animations and interaction for your visitors, but …
… nobody else sees what they are doing. Someone hits a homerun in the virtual baseball stadium but nobody cheers.

Therefore you want to share events with other visitors. Everybody should see what's happening. blaxxun Contact provides an easy way of routing VRML events to all visitors of a multi-user place.

Designing shared events in VRML 2.0

First of all, you have to declare the EXTERNPROTOs BlaxxunZone and SharedEvent. For every type of eventOut you want to share you have to use the eventIn set_type and the eventOut typeToServer. If you want to get an event from the server, you must use the eventOut type_changed and the eventIn typeFromServer. type is one of the following strings: bool, color, float, int32, rotation, string, time, vec2f, vec3f.
Then you have to instantiate a BlaxxunZone named SharedZone into your VRML world. For every event that you want to share, you must add an instance of a SharedEvent as a field to the SharedZone.
At last you have to change the routes in your VRML file:
Instead of routing directly to the target node in your VRML world, you route to the eventIn set_type of the SharedEvent and from the eventOut type_changed of the SharedEvent to your target node. That's it!

Events routed to the SharedEvent nodes are automatically routed to the server by the typeToServer eventOuts and from there to all visitors of the place, including yourself. The SharedEvent PROTO has input and output fields for the following VRML event types:
SFBool, SFColor, SFFloat, SFInt32, SFRotation, SFString, SFTime, SFVec2f, SFVec3f.
Please note that SFTime events are NOT converted to the local time on other clients ! If you are not interested in the actual local time the event was sent, but want to use it to start animations you should use a VRMLScript function to receive the time_changed EventIn and then use the time stamp of the call instead of the original value.

You don't have to define all types of events in your EXTERNPROTO declaration, just the ones that you need for your shared events.

Shared.wrl ( display it ) contains the definition of these 2 prototypes.

Attention! The names of the typeToServer and typeFromServer events must be the same as in the definition of the Shared.wrl !!

Example

Let's look at a small example ( display it ) that illustrates the use. The world just contains three objects, a box, a sphere and a cone. If you click on the sphere, the box changes its color, if you click on the cone, it changes the rotation. Please check shared.wrl ( display it ) for other event types. shareddebug ( display it ) contains a debug version of the PROTOs: Every time a shared event is sent or received, a trace is written to the VRML console.

First of all, we have to declare the EXTERNPROTOs:

EXTERNPROTO BlaxxunZone [
eventIn         MFNode   addEvents
eventIn         MFNode   removeEvents
exposedField    MFNode   events
] "http://www.blaxxun.com/vrml/protos/shared.wrl#BlaxxunZone"

EXTERNPROTO SharedEvent [
exposedField SFString  name
eventIn    SFColor    set_color
eventIn    SFRotation set_rotation
eventOut   SFColor    color_changed
eventOut   SFRotation rotation_changed
eventIn    SFColor    colorFromServer
eventIn    SFRotation rotationFromServer
eventOut   SFColor    colorToServer
eventOut   SFRotation rotationToServer
] "http://www.blaxxun.com/vrml/protos/shared.wrl#SharedEvent"

We want to share the new color and the new rotation with all other members. So for the color we need to quote the following events
eventIn    SFColor    set_color
eventOut   SFColor    colorToServer
eventOut   SFColor    color_changed
eventIn    SFColor    colorFromServer
Remember to name the typeToServer and typeFromServer events exactly the same as in the definition of the SharedEvent Proto!
The "name" field in the SharedEvent can be used to identify the shared event, e.g. to send an event to the VRML world from a CSbot. The use of the name field is optional. The typeToServer and typeFromServer events are used internally by blaxxun Contact.

Then we have to add the SharedZone with one instance of the SharedEvent for the color and one for the translation.

DEF SharedZone BlaxxunZone {
 events [
  DEF SharedColor SharedEvent {name "newColor" }
  DEF SharedRotation SharedEvent { }
 ]
}

These are the three objects:

DEF BoxRotation Transform {
 children [
  Shape { # the red box
   appearance Appearance { material DEF BoxColor Material { diffuseColor 1 0 0 } }
   geometry   Box { }
  }
 ]
}
# the sphere is used to change the color
Transform {
 position -4 0 0
 children [
  Shape { geometry Sphere {} },
  DEF ColorSensor TouchSensor {},
  DEF ColorScript Script {
   eventIn  SFTime     clicked
   eventOut SFColor color_changed
   url "vrmlscript:
   function clicked (value, time) {
    color_changed = new SFColor(Math.random(),Math.random(),Math.random());
   }
   "
  }
 ]
}

# the cone is used to change the rotation
Transform {
 position 4 0 0
 children [
  Shape { geometry Cone {} },
  DEF RotationSensor TouchSensor {},
  DEF RotationScript Script {
   eventIn  SFTime     clicked
   eventOut SFRotation rotation_changed
   url "vrmlscript:
   function clicked (value, time) {
    angle = Math.random()*6.283;
    rotation_changed =new SFRotation( 0,1,0,angle);
   }
   "
  }
 ]
}

At last we have to add the ROUTEs between the sensors, the SharedEvent nodes and the geometry:

ROUTE RotationSensor.touchTime TO RotationScript.clicked
ROUTE RotationScript.rotation_changed TO SharedRotation.set_rotation
ROUTE SharedRotation.rotation_changed TO BoxRotation.rotation

ROUTE ColorSensor.touchTime TO ColorScript.clicked
ROUTE ColorScript.color_changed TO SharedColor.set_color
ROUTE SharedColor.color_changed TO BoxColor.diffuseColor
 
sample1.wrl ( display it ) contains the source for that example.

Hint:
To make sure that the prototypes are loaded at the same as the other scripts of your world, use PROTOs instead of EXTERNPROTOs and copy the definition of the PROTO from shared.wrl to your VRML world!

Advanced Usage

Though the usage of the BlaxxunZone and SharedEvent is highly recommended, you may chose to use your own implementation. However you may not change the naming of the SharedZone node, the type and naming of its fields events and avatars and the naming of the typeFromServer EventIns and typeToServer EventOuts of your shared event.

As mentioned before it is not necessary to use the complete definition of a SharedEvent or SharedZone, you just instantiate the things you need.

It is also not required to use one SharedEvent per field you want to share. You can use all field types in one SharedEvent. But if you need a field type twice, you have to instantiate another SharedEvent.

The possibility to use different VRML worlds for the same blaxxun Contact scene enables you to use SharedEvents to guide or administrate visitors to your VRML world:

The VRML world your guide is accessing contains the possibility to send SharedEvents ( events are routed to a set_type EventIn of a SharedEvent) whereas the VRML world of your visitors just contains the routing of the EventOuts. Thus they just receive the events but are not able to send them themselves.
For instance you could share the Viewpoints in your guide world, and thus if your guide goes to another viewpoint, all visitors would join him there. But no visitor could do the same thing ! This is especially convenient for guided tours with CDBots. Another usage is to open doors, remove walls, show images or even to take your visitors to another VRML world. You are limited only by your imagination.

Note: to use this feature you must give every SharedEvent a name !

Persistent Storage

The blaxxun Object Manager provides a simple mechanism to store shared information. There are 3 different lifetime modes for shared events:

You just have to name the shared events differently to use a different lifetime. Event names starting with F_ will be stored forever (Forever), event names starting with P_ are stored while someone is visiting the place (Populated).

All stored events of a place are sent to a client after he enters the place.

Additionally you can request all stored events explicitly by sending a shared event named get_events to the server.

Access

The shared events can have different access types that affect the distribution to other clients. These are:

Again you just have to name the events differently to set an access type.

Lock
Write lock means that as soon as someone sends this event, it can't be modified by others unless the locking client releases the lock again or leaves the place. If he leaves the place, the shared event is unlocked automatically. This can be used e.g. in a ball game to lock the ball as soon as someone plays the ball to guarantee that only one person plays the ball at the same time. The event must have a _LOCK in its name to set this access type. An event can be locked by sending any content and released again by sending an empty string.
A shared event with a name like P_S_LOCK_... is treated as a lock event. Setting it to the empty string '' releases the lock. Setting it to any! other string requests the lock from the server. The server answers with the name of the avatar that has the lock.

This example ( display it ) illustrates the use.

If the lock is not set, you can set it by clicking on the red sphere. If you have the lock, you can release it by clicking on the green sphere.
Click ( display it ) here to load the example vrml file.

Distribution
Distribution means that the event is only send to the server and it isn't distributed to other clients. You just have to add _S_ to the name, e.g. P_S_ will be send only to the server and stored there while someone is visiting the place.

Pilot
Pilot is a special lock that will be passed to the next user whenever the "pilot" user leaves the place. It is marked by adding a _PILOT to the name.
In the following example ( display it ), the first user to enter receives the Pilot Lock. If this user leaves, another user receives the Pilot Lock. If the user releases the lock by clicking on the green sphere, another user receives the lock.

If there is no other user, the lock will go back to the user that had it.

Click ( display it ) here to load the example vrml file.

A shared event with a name like P_S_PILOT_... is treated as a pilot event. Setting it to the empty string '' releases the lock.
Setting it to any other string requests the lock from the server.
The server answers with the name of the avatar that has the lock.

Group
Usually SharedEvents are distributed to everyone in the scene, even though they are only of interest to some clients (e.g. the ones being close enough to see the effects of the event or the clients playing the game). Normally this is no problem but in some cases you might want to restrict the distribution to a selected group of users e.g. when

Grouped SharedEvents (identified by S_GRP_ in their name) differ from global SharedEvents in 2 points:
To use grouped SharedEvents you need:

To start you set the S_GRP_SUBSCRIBE) to the name of the group you want to subscribe to (Note this implies you can only subscribe to at most one group!). To unsubscribe you have to send an empty value "". After subscription you will receive all group specific events, which are only distributed to subscribers of the same group. Example: if you are subscribed to 'TeamA' and change the value of any group event this change is only! distributed to clients who are also subscribed to 'TeamA'. Note a current bug: If you set a GRP event you will receive it twice.
Here is a little example, which also uses History shared events ( see next paragraph). You subscribe to 'red' or 'green' by clicking the respective box. Further clicking will send shared Events to the respective group. Have a look at the VRML source.
Of course grouped events can be combined with the other access types for access and storage.

History
Additionally special _HIST_ and _RESET extensions are available in 4.1. The _HIST_ extension tells the Object manager to store the history of this shared event, that is all values set for it during its lifetime. The _HIST_ extension can be combined with the different access types. A user will receive the queue of all values set for that shared event, not only the last one (as normal). For group events he receives the queue after subscribing.
As the shared event queues may become quite big you need a possibility to reset it:
Setting a Reset shared event (with _RESET as suffix) to 'eventname' resets the event queue for the shared event named 'eventname', setting a _GRP_RESET event to 'groupname' resets the shared event queue for the group groupname (see the subscribe event), that is the history of ALL grouped shared events.
Please note that history shared events require a proper application logic and enough system resources for the blaxxun Community Server. Especially persistent shared events need to be used very careful.
There is no inherent right or security mechanism on _RESET events, so your application should ensure that only authorized clients operate on them. You will usually use a PILOT or LOCK event to decide which client resets certain shared event queues.
We recommend to use _HIST_ events only where unavoidable e.g. where you cannot store the current status in a single shared event (see limitations below) or where the time line of the event is absolutely necessary. Note that due to the nature of the net, we cannot absolutely ensure that the user will receive the SharedEvent queue in the same order as it is sent (though for TCP connections it is highly likely).
This example uses groups and history shared events.

Hint:
The blaxxun Server SDK can be used to modify the standard behavior of the Object Manager and to implement your own logic.

Limitations

You may not send strings of a length exceeding 200 bytes.

Network limitations
It's a big difference whether events are routed inside the VRML browser, just requiring some program code to execute on your PC, or whether they are send over a (usually slow) internet connection to all other visitors of a multi-user place. So special care has to be taken in the design of shared events. E.g. you should never route fraction_changed events of a TimeSensor or Interpolator!
The best way is to send either the initial event, e.g. the touchTime event of a TouchSensor or the final result, e.g the end position from a PlaneSensor. And to perform the action on all clients separately, e.g. interpolate to the end position.

You might have noticed that the BlaxxunZone contains EventIns named addEvents and removeEvents. These are supported only by blaxxun Contact plug in, release 4.0 or higher. Additionally an "addEvent" event is NOT send to other clients. It's only performed locally. So make sure that the event that triggers adding a new event is defined as shared event.

Joining or leaving a chat group in 3D

blaxxun Contact supports 2 specially named SharedEvents groupJoin and groupLeave, providing the possibility to join or leave a chatgroup ( identified via their String field ) via VRML. To use this feature add 2 SharedEvents to your VRML scene, where one name field reads 'groupJoin' the other one 'groupLeave'. Once you send the name of the chat group you want to join to the set_string(stringToServer) EventIn, the client will automatically join respectively create this chat group if it did not exist.
To create a localized chat groups ie. a chat group defined by a space in VRML put a proximity sensor in your world which once activated sends the 'group name' to the groupJoin SharedEvent. Or you might use a TouchSensor which does the same thing.

Note that sending this event is NOT distributed by Contact over the server ( to avoid enforcement of everybody joining a chat group). Please use blaxxun Agents to send enforced chat invitations to selected visitors

You can test it using the small example. If you click on the cone, you join a chatgroup, if you click on the sphere, you leave it again. The chat panel will be automatically activated. So if you activate the Public chat panel again and click on the cone, the Vrmlgroup chat panel will become active.

Chat in 3D

You can get all the information about the chat in 3D. So you can think of a completely different chat interface, showing all chat on a board in 3D or displaying the chat on top of each avatar. You can even send chat from 3D.

The BlaxxunZone and the Avatar PROTO contain special fields to support it.

PROTO BlaxxunZone [ 
exposedField    MFString    sendToChat ""
exposedField    MFString    groupChatName ""
exposedField    MFString    groupChat ""
]
If you set a string in sendToChat, it will be sent to the Public chat group.
Incoming chat will be written to the exposedField groupChat. groupChatName will reflect the name of the chat group that received the chat. Example4 ( display it ) demonstrates the use. The last 5 chat output lines will be displayed in 3D. The example also shows how to use the Script EAI. You can send chat from an HTML form and receive it in an HTML frame.

The Avatar proto contains a field chatGesture. If that field exists, Contact will write all chat from that avatar into that field. http://www.blaxxun.com/vrml/avatars/chat.wrl ( display it ) is an avatar that displays all his chat over its head.

Getting Avatar information

Your own avatar

You want to put a mirror in your world and display the names of the visitors on a blackboard ?

blaxxun Contact 3D and the blaxxunZone ( for compatibility with older blaxxun Contact versions ) both contain exposedFields named myAvatarUrl and myAvatarName. blaxxun Contact sets both once you enter a VRML world. Note that the myAvatarName field is for information only, changing it via the corresponding eventIn will have no consequences in blaxxun Contact. However changing myAvatarUrl will replace the visitors avatar once he reloads or goes to another scene ( see Avatar pages in the Developer guide ). So its best use is in locker rooms where you get dressed before entering the main world. blaxxun Contact 4.1 or higher has another field: myAvatarSize, which contains the avatar size/NavigationInfo as calculated by Contact.
Please note that

Your own avatars nickname:
You can retrieve the users nickname directly from Contact3d via the EventOut Browser.myAvatarName_changed or from the exposedField myAvatarName in the BlaxxunZone. Read that field e.g. to display the name somewhere in 3D.

PROTO BlaxxunZone [ 
exposedField    SFString myAvatarName ""
]

Avatars of other visitors

Whenever blaxxun Contact adds an avatar to the VRML world, it sends an event to the addAvatars eventIn of the BlaxxunZone. And a removeAvatars event if the avatar is deleted.
Let's look at a small example that illustrates the use. The world adds a "shadow" for every avatar in 2 meters distance whenever an avatar is added. It uses the avatar_added eventOut of the BlaxxunZone and routes it to the children field of a Transform node:

EXTERNPROTO BlaxxunZone [
eventIn         MFNode   addAvatars
eventOut      MFNode   avatars_added
eventIn         MFNode   removeAvatars
eventOut      MFNode   avatars_removed
] "http://www.blaxxun.com/vrml/protos/shared.wrl#BlaxxunZone"

DEF SharedZone BlaxxunZone{}
DEF AvatarShadow Transform
{
translation 0 0 -2
children []
}
ROUTE SharedZone.avatars_added TO AvatarShadow.addChildren
ROUTE SharedZone.avatars_removed TO AvatarShadow.removeChildren

sample2.wrl ( display it ) contains the source for that example.

If the avatars use the standard blaxxun Avatar PROTO, the VRML world can check the fields of the avatar node, e.g. to get the current position of an avatar.
Note: this requires node parsing via the EAI or VRMLScript. sample2.wrl contains an example for finding the touch sensor that is part of the avatar url.

Beam to Avatars

If you beam to another avatar, Contact adds a Viewpoint into the world and positions it 3 meters in front of the other avatar. But you can define your own Viewpoint and specify a different distance.

The BlaxxunZone contains the following fields:

PROTO BlaxxunZone [ 
exposedField	SFNode   beamToViewpoint []
exposedField    SFFloat  beamToDistance 3
]

You can use beamToDistanceto change the distance and beamToViewpoint to use your own viewpoint, e.g.

DEF VIEW1 Viewpoint {}
DEF SharedZone BlaxxunZone { 
beamToViewpoint USE VIEW1 
beamToDistance 2
}

Avatar LODs

Contact uses an efficient method of displaying only the nearest avatars and culling avatars that aren't visible. Additionally you can use LODs to display the avatars with a different level of detail. Of course the avatars can have an LOD built in. But you can also define an LOD for your world that will affect all avatars.

The BlaxxunZone contains the following fields:

PROTO BlaxxunZone [ 
exposedField    MFNode   avatarLOD []
exposedField    MFFloat  avatarRange []
]
The following example displays a grey box whenever an avatar is more than 20 meters away:
DEF SharedZone BlaxxunZone
{
  avatarRange [ 20 ]
  avatarLOD [   
   Transform { translation 0 -1 0
    children [
     Shape {
      appearance Appearance { material Material { diffuseColor 0.5 0.5 0.5 } }
      geometry Box { size 0.3 1.85 0.3 }
     }
    ]
   }
  ]
}

Avatar gestures

You can send avatar gestures using the set_myAvatarGesture eventIn of the SharedZone. Contact sets the myAvatarGesture_changed eventOut whenever a gesture is performed whether by the method above or any user action triggering a gesture ( e.g. body language menu ). These gestures are distributed to other clients. If you simply want the users avatar to perform a gesture e.g. in a locker room use the set_myAvatarGesture eventIn of Contact3d (Browser.set_myAvatarGesture). Note this makes sense only in 3rd person mode.

The BlaxxunZone contains the following fields:

PROTO BlaxxunZone [ 
eventIn         SFInt32  set_myAvatarGesture
eventIn         SFInt32  myAvatarGestureFromServer 
eventOut        SFInt32  myAvatarGesture_changed
eventOut        SFInt32  myAvatarGestureToServer 
]



The chat example ( display it ) contains also a "send gesture 1" button in HTML that sends out the gesture1. You can visit the example with 2 clients or activate the third person mode (type A in the 3D window) to see at the gesture.

Limitations
Only avatars are added that are displayed in 3D. For performance and bandwidth reasons, blaxxun Contact adds only avatars that are in your neighborhood. The other avatars are only visible in the people list and chat.
If you want to get events from all avatars in the scene, you could use a bot that sends a shared event whenever an avatar enters the scene.
Right now, you get 3 events for each avatar ( 3 adds and 2 removes), as first the default avatar is added, then replaced with the users avatar and in step 3 (unless the users avatar implements our avatar interface) replaced with a wrapped version of the users avatar.
We recommend highly to include the BlaxxunZone as a PROTO into the world (no EXTERNPROTO) to guarantee that it is loaded when blaxxun Contact starts adding avatars. This way you can additionally improve performance by removing all events and fields you do not need in your VRML world. E.g. the add/remove avatars/objects are rarely used, but due to their structure ( complete VRML files/scene graphs added) cost performance.

Shared Objects
Please note that SharedObjects and SharedObjectEvents are only available/useful in a community context. To fully understand their possibilities you should have a good understanding of our community concepts.
We will describe only those events and fields, that are useful for your world design. Overriding the implementation of other events is not recommended (but possible).
For the full implementation see shared.wrl

EXTERNPROTO SharedObject [
exposedField SFVec3f  translation
exposedField SFRotation  rotation
exposedField SFString  name
exposedField SFString  id
exposedField MFNode  children
eventIn SFBool  startMove
eventIn MFString  attributesFromServer
exposedField MFString attributes
eventOut MFString  attributes_changed
eventOut SFTime  touchTime
eventOut SFBool  isOver
eventOut SFVec3f  newPosition
eventOut SFRotation  newRotation
] "http://www.blaxxun.com/vrml/protos/shared.wrl#SharedObject"
Override this implementation if you want to implement a world specific SharedObject handling. E.g. you could use the attributes field to read a 2D image of the shared object, initially just load this image and load the VRML representation on an user action. This will decrease download size for worlds with a lot of SharedObjects.
In the blaxxun Contact configuration file (bxx file) you can specify the attributes that should be read automatically for all objects. Per default, these are the prize and the count of objects.

[World Params]objectpucolumnvalue TPR,CNT,IMG,CLA
will read the class and image attribute additionally.
Of course you could design your own object movement handling too.
Usually you will not use world specific SharedObject handling, but rather want to create special SharedObjects. This is done if you implement the SharedObject as a:

EXTERNPROTO SharedObjectEvent [
#shared object fields
eventIn SFString  set_name
eventOut SFString  name_changed
eventIn SFString  set_action
eventOut SFString  action_changed
eventIn MFString  set_attributes
eventOut MFString  attributes_changed
eventIn MFString  attributesFromServer
eventOut MFString  attributesToServer
eventIn SFTime  set_touchTime
eventOut SFTime  touchTime
eventIn SFBool  set_isOver
eventOut SFBool  isOver
] "http://www.blaxxun.com/vrml/protos/shared.wrl#SharedObjectEvent"

Note that the SharedObjectEvent additionally contains all fields of a sharedevent. Usage of those will make the object behave like a sharedevent. However there are some restrictions:


You use the SharedObjectEvent proto inside a sharedobject like the avatar proto in avatars. All fields defined in here replace the standard "sharedobject proto" one, e.g. you could define a special HUD for moving a certain object. Or use a touchsensor inside (e.g. to water a plant, highlight the object in the object panel and to display the object pop up menu on the object in 3d). The most interesting fields are set_attributes and attributes_changed which allow to read all the object attributes, e.g. price, request additional attributes, or update attributes of the object in he database.

To read additional attribute values set set_attributes to
[ "GET",<attribute to read name>(,<attribute to read name>)...]
respectively
[ "SET",<attribute to set name><attribute value> (,<attribute to set name><attribute value>)...]
to change attribute values.

With the set_action eventIn you define special 3d actions that are displayed in the object menu and send directly to 3D, e.g. an action "Water" directly waters the plant.
Here's a standalone example. ( display it ) For more information on SharedObjects please refer to Community documentation.

Object LODs

Similar to Avatar LODS Contact provides an LOD mechanism for objects (blaxxun Contact 4.3 and higher). Note that Contact 4.3 introduces a default LOD for objects, that is an empty shape displayed for distances greater than 30 units. Only if you want to overwrite or remove this handling you need to use the following fieldsin the BlaxxunZone :

PROTO BlaxxunZone [ 
exposedField    MFNode   objectLOD []
exposedField    MFFloat  objectRange []
]
The following example displays a grey box whenever an object is more than 20 meters away:
DEF SharedZone BlaxxunZone
{
  objectRange [ 20 ]
  objectLOD [   
   Transform { translation 0 -1 0
    children [
     Shape {
      appearance Appearance { material Material { diffuseColor 0.5 0.5 0.5 } }
      geometry Box { size 0.3 1.85 0.3 }
     }
    ]
   }
  ]
}

Related links

Download all examples

VRML 97 Specification
VRML 97 Node Reference
The Annotated VRML97 Reference Manual
General blaxxun Developer Information


© 1998 blaxxun interactive AG All rights reserved.